From ac04a7110df84e42ad64809a4d444ebf8982a4b7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 18 May 2018 15:42:18 -0400 Subject: [PATCH 0001/4847] Return canned GraphQL query responses in spec mode --- lib/relay-network-layer-manager.js | 59 +++++++++++++++++++++++++++--- test/helpers.js | 5 ++- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index 1ae291dcaa..0952c3eb35 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -13,11 +13,46 @@ function logRatelimitApi(headers) { console.debug(`GitHub API Rate Limit: ${remaining}/${total} — resets ${resetsIn}`); } -const tokenPerEnvironmentUrl = new Map(); +const responsesByQuery = new Map(); + +export function expectRelayQuery(operationPattern, response) { + let resolve, reject; + const promise = new Promise((resolve0, reject0) => { + resolve = () => resolve0({data: response}); + reject = reject0; + }); + + responsesByQuery.set(operationPattern.name, {promise, response, variables: operationPattern.variables || {}}); + + return {promise, resolve, reject}; +} + +export function clearRelayExpectations() { + responsesByQuery.clear(); +} + +const tokenPerURL = new Map(); +const fetchPerURL = new Map(); function createFetchQuery(url) { + if (atom.inSpecMode()) { + return function specFetchQuery(operation, variables, cacheConfig, uploadables) { + const expectation = responsesByQuery.get(operation.name); + if (!expectation) { + // eslint-disable-next-line no-console + console.log(`GraphQL query ${operation.name} was:\n ${operation.text.replace(/\n/g, '\n ')}`); + + const e = new Error(`Unexpected GraphQL query: ${operation.name}`); + e.rawStack = e.stack; + throw e; + } + return expectation.promise; + }; + } + return function fetchQuery(operation, variables, cacheConfig, uploadables) { - const currentToken = tokenPerEnvironmentUrl.get(url); + const currentToken = tokenPerURL.get(url); + return fetch(url, { method: 'POST', headers: { @@ -43,17 +78,29 @@ export default class RelayNetworkLayerManager { static getEnvironmentForHost(host, token) { host = host === 'github.com' ? 'https://api.github.com' : host; const url = host === 'https://api.github.com' ? `${host}/graphql` : `${host}/api/v3/graphql`; - const config = relayEnvironmentPerGithubHost.get(host) || {}; - let {environment, network} = config; - tokenPerEnvironmentUrl.set(url, token); + let {environment, network} = relayEnvironmentPerGithubHost.get(host) || {}; + tokenPerURL.set(url, token); if (!environment) { const source = new RecordSource(); const store = new Store(source); - network = Network.create(createFetchQuery(url)); + network = Network.create(this.getExistingFetchQuery(url)); environment = new Environment({network, store}); relayEnvironmentPerGithubHost.set(host, {environment, network}); } return environment; } + + static getExistingFetchQuery(url) { + if (!tokenPerURL.has(url)) { + return null; + } + + let fetch = fetchPerURL.get(url); + if (!fetch) { + fetch = createFetchQuery(url); + fetchPerURL.set(fetch); + } + return fetch; + } } diff --git a/test/helpers.js b/test/helpers.js index 9ae40fa868..eedbeae74c 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -7,13 +7,14 @@ import transpiler from 'atom-babel6-transpiler'; import React from 'react'; import ReactDom from 'react-dom'; import sinon from 'sinon'; +import {Directory} from 'atom'; import Repository from '../lib/models/repository'; import GitShellOutStrategy from '../lib/git-shell-out-strategy'; import WorkerManager from '../lib/worker-manager'; import ContextMenuInterceptor from '../lib/context-menu-interceptor'; import getRepoPipelineManager from '../lib/get-repo-pipeline-manager'; -import {Directory} from 'atom'; +import {clearRelayExpectations} from '../lib/relay-network-layer-manager'; assert.autocrlfEqual = (actual, expected, ...args) => { const newActual = actual.replace(/\r\n/g, '\n'); @@ -248,6 +249,8 @@ afterEach(function() { ContextMenuInterceptor.dispose(); global.sinon.restore(); + + clearRelayExpectations(); }); // eslint-disable-next-line jasmine/no-global-setup From 88c48ffde4d98fc05be71966a0bab98320e1511e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 18 May 2018 15:43:02 -0400 Subject: [PATCH 0002/4847] Spec for the simple case of loading mentionable users --- test/models/user-store.test.js | 44 ++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index b6653999db..c9605bffb3 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -1,11 +1,11 @@ import dedent from 'dedent-js'; import UserStore, {NO_REPLY_GITHUB_EMAIL} from '../../lib/models/user-store'; - +import RelayNetworkLayerManager, {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import {cloneRepository, buildRepository, FAKE_USER} from '../helpers'; describe('UserStore', function() { - it('loads store with users and committer in repo upon construction', async function() { + it('loads store with local git users and committer in a repo with no GitHub remote', async function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); const store = new UserStore({repository}); @@ -23,6 +23,46 @@ describe('UserStore', function() { await assert.async.deepEqual(store.committer, FAKE_USER); }); + it('loads store with mentionable users from the GitHub API in a repo with a GitHub remote', async function() { + const workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + + await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); + await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); + await repository.setConfig('remote.old.url', 'git@sourceforge.com:me/stuff.git'); + await repository.setConfig('remote.old.fetch', '+refs/heads/*:refs/remotes/old/*'); + + const {resolve, promise} = expectRelayQuery({name: 'MentionableUserQuery'}, { + repository: { + mentionableUsers: { + nodes: [ + {login: 'kuychaco', email: 'kuychaco@github.com', name: 'Katrina Uychaco'}, + {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, + {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, + ], + pageInfo: { + hasNextPage: false, + endCursor: null, + }, + }, + }, + }); + + const store = new UserStore({repository}); + assert.deepEqual(store.getUsers(), []); + + resolve(); + await promise; + + assert.deepEqual(store.getUsers(), [ + {login: 'kuychaco', email: 'kuychaco@github.com', name: 'Katrina Uychaco'}, + {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, + {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, + ]); + }); + + it('infers no-reply emails for users without a public email address'); + it('excludes committer and no reply user from `getUsers`', async function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); From 92b063f4f2a7723089e12690aaa42b1a707ce427 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 21 May 2018 10:45:19 -0400 Subject: [PATCH 0003/4847] Load users from GraphQL if a GitHub remote and token are present --- lib/models/user-store.js | 68 +++++++++++++++++++++++++++++----- test/models/user-store.test.js | 13 ++++--- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index dd1b5d9374..f2ac51a6b1 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -1,3 +1,5 @@ +import RelayNetworkLayerManager from '../relay-network-layer-manager'; + // This is a guess about what a reasonable value is. Can adjust if performance is poor. const MAX_COMMITS = 5000; @@ -28,22 +30,29 @@ export default class UserStore { } } - loadUsers() { - this.loadUsersFromLocalRepo(); - } - - async loadUsersFromLocalRepo() { - const users = await this.repository.getAuthors({max: MAX_COMMITS}); + async loadUsers() { const committer = await this.repository.getCommitter(); this.setCommitter(committer); + + const githubRemotes = (await this.repository.getRemotes()).filter(remote => remote.isGithubRepo()); + const users = githubRemotes.length === 0 + ? await this.loadUsersFromLocalRepo() + : await this.loadUsersFromGraphQL(githubRemotes); + this.addUsers(users); this.didUpdate(); } - addUsersFromGraphQL(response) { - // TODO: [ku 3/2018] also get users from GraphQL API if available. Will need to reshape the data accordingly - // This will get called in relay query renderer callback - // this.addUsers(users); + loadUsersFromLocalRepo() { + return this.repository.getAuthors({max: MAX_COMMITS}); + } + + async loadUsersFromGraphQL(remotes) { + const mentionableUsers = await Promise.all(remotes.map(remote => getMentionableUsers(remote))); + return mentionableUsers.reduce((acc, list) => { + acc = {...acc, ...list}; + return acc; + }, {}); } addUsers(users) { @@ -77,3 +86,42 @@ export default class UserStore { }); } } + +async function getMentionableUsers(remote) { + const fetchQuery = RelayNetworkLayerManager.getExistingFetchQuery('https://api.github.com/graphql'); + if (!fetchQuery) { + // No authentication token + return []; + } + + const response = await fetchQuery({ + name: 'GetMentionableUsers', + text: ` + query GetMentionableUsers { + repository(owner: $owner, name: $name) { + mentionableUsers(first: $first, after: $after) { + nodes { + login + email + name + } + pageInfo { + hasNextPage + endCursor + } + } + } + } + `, + }, { + owner: remote.getOwner(), + name: remote.getRepo(), + first: 100, + after: null, + }); + + return response.data.repository.mentionableUsers.nodes.reduce((acc, node) => { + acc[node.email] = node.name; + return acc; + }, {}); +} diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index c9605bffb3..b54cf33f23 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -24,6 +24,8 @@ describe('UserStore', function() { }); it('loads store with mentionable users from the GitHub API in a repo with a GitHub remote', async function() { + RelayNetworkLayerManager.getEnvironmentForHost('https://api.github.com', '1234'); + const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); @@ -32,7 +34,7 @@ describe('UserStore', function() { await repository.setConfig('remote.old.url', 'git@sourceforge.com:me/stuff.git'); await repository.setConfig('remote.old.fetch', '+refs/heads/*:refs/remotes/old/*'); - const {resolve, promise} = expectRelayQuery({name: 'MentionableUserQuery'}, { + const {resolve} = expectRelayQuery({name: 'GetMentionableUsers'}, { repository: { mentionableUsers: { nodes: [ @@ -52,12 +54,11 @@ describe('UserStore', function() { assert.deepEqual(store.getUsers(), []); resolve(); - await promise; - assert.deepEqual(store.getUsers(), [ - {login: 'kuychaco', email: 'kuychaco@github.com', name: 'Katrina Uychaco'}, - {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, - {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, + await assert.async.deepEqual(store.getUsers(), [ + {email: 'smashwilson@github.com', name: 'Ash Wilson'}, + {email: 'kuychaco@github.com', name: 'Katrina Uychaco'}, + {email: 'mona@lisa.com', name: 'Mona Lisa'}, ]); }); From 5bea3addb8712f1f184b04dc341312fa9fc3469b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 21 May 2018 10:51:34 -0400 Subject: [PATCH 0004/4847] Assert against mentionable users that aren't also in git history --- test/models/user-store.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index b54cf33f23..dfe9c59f10 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -38,9 +38,9 @@ describe('UserStore', function() { repository: { mentionableUsers: { nodes: [ - {login: 'kuychaco', email: 'kuychaco@github.com', name: 'Katrina Uychaco'}, - {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, + {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, + {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, ], pageInfo: { hasNextPage: false, @@ -57,8 +57,8 @@ describe('UserStore', function() { await assert.async.deepEqual(store.getUsers(), [ {email: 'smashwilson@github.com', name: 'Ash Wilson'}, - {email: 'kuychaco@github.com', name: 'Katrina Uychaco'}, {email: 'mona@lisa.com', name: 'Mona Lisa'}, + {email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, ]); }); From 5f850b4266da367a60c1f993c537037447753c25 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 21 May 2018 14:11:30 -0400 Subject: [PATCH 0005/4847] Match expected GraphQL queries by variables --- lib/relay-network-layer-manager.js | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index 0952c3eb35..f63f74b92c 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -22,7 +22,9 @@ export function expectRelayQuery(operationPattern, response) { reject = reject0; }); - responsesByQuery.set(operationPattern.name, {promise, response, variables: operationPattern.variables || {}}); + const existing = responsesByQuery.get(operationPattern.name) || []; + existing.push({promise, response, variables: operationPattern.variables || {}}); + responsesByQuery.set(operationPattern.name, existing); return {promise, resolve, reject}; } @@ -37,8 +39,22 @@ const fetchPerURL = new Map(); function createFetchQuery(url) { if (atom.inSpecMode()) { return function specFetchQuery(operation, variables, cacheConfig, uploadables) { - const expectation = responsesByQuery.get(operation.name); - if (!expectation) { + const expectations = responsesByQuery.get(operation.name) || []; + const match = expectations.find(expectation => { + if (Object.keys(expectation.variables).length !== Object.keys(variables).length) { + return false; + } + + for (const key in expectation.variables) { + if (expectation.variables[key] !== variables[key]) { + return false; + } + } + + return true; + }); + + if (!match) { // eslint-disable-next-line no-console console.log(`GraphQL query ${operation.name} was:\n ${operation.text.replace(/\n/g, '\n ')}`); @@ -46,7 +62,8 @@ function createFetchQuery(url) { e.rawStack = e.stack; throw e; } - return expectation.promise; + + return match.promise; }; } From 350ff6e4b51ff188c0f9127fff79090d3538e9f3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 21 May 2018 14:14:10 -0400 Subject: [PATCH 0006/4847] Fetch multiple pages of mentionable users --- lib/models/user-store.js | 81 +++++++++++++++++++--------------- test/models/user-store.test.js | 73 +++++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 36 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index f2ac51a6b1..7ef35c4768 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -47,12 +47,13 @@ export default class UserStore { return this.repository.getAuthors({max: MAX_COMMITS}); } - async loadUsersFromGraphQL(remotes) { - const mentionableUsers = await Promise.all(remotes.map(remote => getMentionableUsers(remote))); - return mentionableUsers.reduce((acc, list) => { - acc = {...acc, ...list}; - return acc; - }, {}); + loadUsersFromGraphQL(remotes) { + for (const remote of remotes) { + getMentionableUsers(remote, users => { + this.addUsers(users); + this.didUpdate(); + }); + } } addUsers(users) { @@ -87,41 +88,51 @@ export default class UserStore { } } -async function getMentionableUsers(remote) { +async function getMentionableUsers(remote, callback) { const fetchQuery = RelayNetworkLayerManager.getExistingFetchQuery('https://api.github.com/graphql'); if (!fetchQuery) { // No authentication token - return []; + return; } - const response = await fetchQuery({ - name: 'GetMentionableUsers', - text: ` - query GetMentionableUsers { - repository(owner: $owner, name: $name) { - mentionableUsers(first: $first, after: $after) { - nodes { - login - email - name - } - pageInfo { - hasNextPage - endCursor + let hasMore = true; + let cursor = null; + + while (hasMore) { + const response = await fetchQuery({ + name: 'GetMentionableUsers', + text: ` + query GetMentionableUsers { + repository(owner: $owner, name: $name) { + mentionableUsers(first: $first, after: $after) { + nodes { + login + email + name + } + pageInfo { + hasNextPage + endCursor + } } } } - } - `, - }, { - owner: remote.getOwner(), - name: remote.getRepo(), - first: 100, - after: null, - }); - - return response.data.repository.mentionableUsers.nodes.reduce((acc, node) => { - acc[node.email] = node.name; - return acc; - }, {}); + `, + }, { + owner: remote.getOwner(), + name: remote.getRepo(), + first: 100, + after: cursor, + }); + + const connection = response.data.repository.mentionableUsers; + + callback(connection.nodes.reduce((acc, node) => { + acc[node.email] = node.name; + return acc; + }, {})); + + cursor = connection.pageInfo.endCursor; + hasMore = connection.pageInfo.hasNextPage; + } } diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index dfe9c59f10..a588cf351b 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -34,7 +34,10 @@ describe('UserStore', function() { await repository.setConfig('remote.old.url', 'git@sourceforge.com:me/stuff.git'); await repository.setConfig('remote.old.fetch', '+refs/heads/*:refs/remotes/old/*'); - const {resolve} = expectRelayQuery({name: 'GetMentionableUsers'}, { + const {resolve} = expectRelayQuery({ + name: 'GetMentionableUsers', + variables: {owner: 'me', name: 'stuff', first: 100, after: null}, + }, { repository: { mentionableUsers: { nodes: [ @@ -62,6 +65,74 @@ describe('UserStore', function() { ]); }); + it('loads users from multiple pages from the GitHub API', async function() { + RelayNetworkLayerManager.getEnvironmentForHost('https://api.github.com', '1234'); + + const workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + + await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); + await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); + await repository.setConfig('remote.old.url', 'git@sourceforge.com:me/stuff.git'); + await repository.setConfig('remote.old.fetch', '+refs/heads/*:refs/remotes/old/*'); + + const {resolve: resolve0} = expectRelayQuery({ + name: 'GetMentionableUsers', + variables: {owner: 'me', name: 'stuff', first: 100, after: null}, + }, { + repository: { + mentionableUsers: { + nodes: [ + {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, + {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, + {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, + ], + pageInfo: { + hasNextPage: true, + endCursor: 'foo', + }, + }, + }, + }); + + const {resolve: resolve1} = expectRelayQuery({ + name: 'GetMentionableUsers', + variables: {owner: 'me', name: 'stuff', first: 100, after: 'foo'}, + }, { + repository: { + mentionableUsers: { + nodes: [ + {login: 'zzz', email: 'zzz@github.com', name: 'Zzzzz'}, + {login: 'aaa', email: 'aaa@github.com', name: 'Aahhhhh'}, + ], + pageInfo: { + hasNextPage: false, + endCursor: 'bar', + }, + }, + }, + }); + + const store = new UserStore({repository}); + assert.deepEqual(store.getUsers(), []); + + resolve0(); + await assert.async.deepEqual(store.getUsers(), [ + {email: 'smashwilson@github.com', name: 'Ash Wilson'}, + {email: 'mona@lisa.com', name: 'Mona Lisa'}, + {email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, + ]); + + resolve1(); + await assert.async.deepEqual(store.getUsers(), [ + {email: 'aaa@github.com', name: 'Aahhhhh'}, + {email: 'smashwilson@github.com', name: 'Ash Wilson'}, + {email: 'mona@lisa.com', name: 'Mona Lisa'}, + {email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, + {email: 'zzz@github.com', name: 'Zzzzz'}, + ]); + }); + it('infers no-reply emails for users without a public email address'); it('excludes committer and no reply user from `getUsers`', async function() { From 3e9bc31eaa4bf44418258d7ca6ea35a54a706ce0 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 21 May 2018 14:45:03 -0400 Subject: [PATCH 0007/4847] Infer no-reply emails --- lib/models/user-store.js | 4 ++++ test/models/user-store.test.js | 36 +++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index 7ef35c4768..ae6d85df56 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -128,6 +128,10 @@ async function getMentionableUsers(remote, callback) { const connection = response.data.repository.mentionableUsers; callback(connection.nodes.reduce((acc, node) => { + if (node.email === '') { + node.email = `${node.login}@users.noreply.github.com`; + } + acc[node.email] = node.name; return acc; }, {})); diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index a588cf351b..b71d5a541d 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -73,8 +73,6 @@ describe('UserStore', function() { await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); - await repository.setConfig('remote.old.url', 'git@sourceforge.com:me/stuff.git'); - await repository.setConfig('remote.old.fetch', '+refs/heads/*:refs/remotes/old/*'); const {resolve: resolve0} = expectRelayQuery({ name: 'GetMentionableUsers', @@ -133,7 +131,39 @@ describe('UserStore', function() { ]); }); - it('infers no-reply emails for users without a public email address'); + it('infers no-reply emails for users without a public email address', async function() { + RelayNetworkLayerManager.getEnvironmentForHost('https://api.github.com', '1234'); + + const workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + + await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); + await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); + + const {resolve} = expectRelayQuery({ + name: 'GetMentionableUsers', + variables: {owner: 'me', name: 'stuff', first: 100, after: null}, + }, { + repository: { + mentionableUsers: { + nodes: [ + {login: 'simurai', email: '', name: 'simurai'}, + ], + pageInfo: { + hasNextPage: false, + endCursor: null, + }, + }, + }, + }); + + const store = new UserStore({repository}); + + resolve(); + await assert.async.deepEqual(store.getUsers(), [ + {email: 'simurai@users.noreply.github.com', name: 'simurai'}, + ]); + }); it('excludes committer and no reply user from `getUsers`', async function() { const workdirPath = await cloneRepository('multiple-commits'); From d8e512e3e06f4b5522363c8a40adef2819e8cf2a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 21 May 2018 14:56:58 -0400 Subject: [PATCH 0008/4847] Call addUsers once --- lib/models/user-store.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index ae6d85df56..6c0e784d00 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -35,18 +35,17 @@ export default class UserStore { this.setCommitter(committer); const githubRemotes = (await this.repository.getRemotes()).filter(remote => remote.isGithubRepo()); - const users = githubRemotes.length === 0 + githubRemotes.length === 0 ? await this.loadUsersFromLocalRepo() : await this.loadUsersFromGraphQL(githubRemotes); + } + async loadUsersFromLocalRepo() { + const users = await this.repository.getAuthors({max: MAX_COMMITS}); this.addUsers(users); this.didUpdate(); } - loadUsersFromLocalRepo() { - return this.repository.getAuthors({max: MAX_COMMITS}); - } - loadUsersFromGraphQL(remotes) { for (const remote of remotes) { getMentionableUsers(remote, users => { From 7f7d07ff65208ccb45885cdbfaa552aeec6c1b69 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 21 May 2018 15:42:53 -0400 Subject: [PATCH 0009/4847] Author model --- lib/models/author.js | 29 +++++++++++++++++++++++++++++ test/models/author.test.js | 19 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 lib/models/author.js create mode 100644 test/models/author.test.js diff --git a/lib/models/author.js b/lib/models/author.js new file mode 100644 index 0000000000..21da35c9a8 --- /dev/null +++ b/lib/models/author.js @@ -0,0 +1,29 @@ +export const NO_REPLY_GITHUB_EMAIL = 'noreply@github.com'; + +export default class Author { + constructor(email, fullName, login = null) { + this.email = email; + this.fullName = fullName; + this.login = login; + } + + getEmail() { + return this.email; + } + + getFullName() { + return this.fullName; + } + + getLogin() { + return this.login; + } + + isNoReply() { + return this.email === NO_REPLY_GITHUB_EMAIL; + } + + hasLogin() { + return this.login !== null; + } +} diff --git a/test/models/author.test.js b/test/models/author.test.js new file mode 100644 index 0000000000..ed2f444d8d --- /dev/null +++ b/test/models/author.test.js @@ -0,0 +1,19 @@ +import Author, {NO_REPLY_GITHUB_EMAIL} from '../../lib/models/author'; + +describe('Author', function() { + it('recognizes the no-reply GitHub email address', function() { + const a0 = new Author('foo@bar.com', 'Eh'); + assert.isFalse(a0.isNoReply()); + + const a1 = new Author(NO_REPLY_GITHUB_EMAIL, 'Whatever'); + assert.isTrue(a1.isNoReply()); + }); + + it('distinguishes authors with a GitHub handle', function() { + const a0 = new Author('foo@bar.com', 'Eh', 'handle'); + assert.isTrue(a0.hasLogin()); + + const a1 = new Author('other@bar.com', 'Nah'); + assert.isFalse(a1.hasLogin()); + }); +}); From 45f24accccee61b2f883550d3842752c35ece098 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 09:06:10 -0400 Subject: [PATCH 0010/4847] Construct Authors from Present.getAuthors() --- lib/models/repository-states/present.js | 6 +++-- test/models/repository.test.js | 35 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index 6075a609fa..cf3780eae1 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -11,6 +11,7 @@ import Hunk from '../hunk'; import HunkLine from '../hunk-line'; import DiscardHistory from '../discard-history'; import Branch, {nullBranch} from '../branch'; +import Author from '../author'; import BranchSet from '../branch-set'; import Remote from '../remote'; import Commit from '../commit'; @@ -616,8 +617,9 @@ export default class Present extends State { // For now we'll do the naive thing and invalidate anytime HEAD moves. This ensures that we get new authors // introduced by newly created commits or pulled commits. // This means that we are constantly re-fetching data. If performance becomes a concern we can optimize - return this.cache.getOrSet(Keys.authors, () => { - return this.git().getAuthors(options); + return this.cache.getOrSet(Keys.authors, async () => { + const authorMap = await this.git().getAuthors(options); + return Object.keys(authorMap).map(email => new Author(email, authorMap[email])); }); } diff --git a/test/models/repository.test.js b/test/models/repository.test.js index acab459700..69e3b8d6bd 100644 --- a/test/models/repository.test.js +++ b/test/models/repository.test.js @@ -536,6 +536,41 @@ describe('Repository', function() { }); }); + describe('getAuthors', function() { + it('returns user names and emails', async function() { + const workingDirPath = await cloneRepository('multiple-commits'); + const repository = new Repository(workingDirPath); + await repository.getLoadPromise(); + + await repository.git.exec(['config', 'user.name', 'Mona Lisa']); + await repository.git.exec(['config', 'user.email', 'mona@lisa.com']); + await repository.git.commit('Commit from Mona', {allowEmpty: true}); + + await repository.git.exec(['config', 'user.name', 'Hubot']); + await repository.git.exec(['config', 'user.email', 'hubot@github.com']); + await repository.git.commit('Commit from Hubot', {allowEmpty: true}); + + await repository.git.exec(['config', 'user.name', 'Me']); + await repository.git.exec(['config', 'user.email', 'me@github.com']); + await repository.git.commit('Commit from me', {allowEmpty: true}); + + const authors = await repository.getAuthors({max: 3}); + assert.lengthOf(authors, 3); + + const expected = [ + ['mona@lisa.com', 'Mona Lisa'], + ['hubot@github.com', 'Hubot'], + ['me@github.com', 'Me'], + ]; + for (const [email, fullName] of expected) { + assert.isTrue( + authors.some(author => author.getEmail() === email && author.getFullName() === fullName), + `getAuthors() output includes ${fullName} <${email}>`, + ); + } + }); + }); + describe('pull()', function() { it('updates the remote branch and merges into local branch', async function() { const {localRepoPath} = await setUpLocalAndRemoteRepositories({remoteAhead: true}); From f845cdfaaae8e82d4723d7548a022b016f373734 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 09:06:48 -0400 Subject: [PATCH 0011/4847] Return an Author or nullAuthor from getCommitter() --- lib/models/author.js | 42 ++++++++++++++++++++++++++++++++++ lib/models/repository.js | 6 ++++- test/models/repository.test.js | 17 +++++++------- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/lib/models/author.js b/lib/models/author.js index 21da35c9a8..b6f29eb6ce 100644 --- a/lib/models/author.js +++ b/lib/models/author.js @@ -26,4 +26,46 @@ export default class Author { hasLogin() { return this.login !== null; } + + isPresent() { + return true; + } + + toString() { + let s = `${this.fullName} <${this.email}>`; + if (this.hasLogin()) { + s += ` @${this.login}`; + } + return s; + } } + +export const nullAuthor = { + getEmail() { + return ''; + }, + + getFullName() { + return ''; + }, + + getLogin() { + return null; + }, + + isNoReply() { + return false; + }, + + hasLogin() { + return false; + }, + + isPresent() { + return false; + }, + + toString() { + return 'null author'; + }, +}; diff --git a/lib/models/repository.js b/lib/models/repository.js index 7a3d58ca5a..b785b55f01 100644 --- a/lib/models/repository.js +++ b/lib/models/repository.js @@ -6,6 +6,7 @@ import fs from 'fs-extra'; import {getNullActionPipelineManager} from '../action-pipeline'; import CompositeGitStrategy from '../composite-git-strategy'; import Remote, {nullRemote} from './remote'; +import Author, {nullAuthor} from './author'; import Branch from './branch'; import {Loading, Absent, LoadingGuess, AbsentGuess} from './repository-states'; @@ -241,7 +242,10 @@ export default class Repository { } }); } - return committer; + + return committer.name !== null && committer.email !== null + ? new Author(committer.email, committer.name) + : nullAuthor; } } diff --git a/test/models/repository.test.js b/test/models/repository.test.js index 69e3b8d6bd..ca28ee4131 100644 --- a/test/models/repository.test.js +++ b/test/models/repository.test.js @@ -514,13 +514,14 @@ describe('Repository', function() { const workingDirPath = await cloneRepository('three-files'); const repository = new Repository(workingDirPath); await repository.getLoadPromise(); - assert.deepEqual(await repository.getCommitter(), { - name: FAKE_USER.name, - email: FAKE_USER.email, - }); + + const committer = await repository.getCommitter(); + assert.isTrue(committer.isPresent()); + assert.strictEqual(committer.getFullName(), FAKE_USER.name); + assert.strictEqual(committer.getEmail(), FAKE_USER.email); }); - it('returns empty object if user name or email do not exist', async function() { + it('returns a null object if user name or email do not exist', async function() { const workingDirPath = await cloneRepository('three-files'); const repository = new Repository(workingDirPath); await repository.getLoadPromise(); @@ -529,10 +530,8 @@ describe('Repository', function() { // getting the local config for testing purposes only because we don't // want to blow away global config when running tests. - assert.deepEqual(await repository.getCommitter({local: true}), { - name: null, - email: null, - }); + const committer = await repository.getCommitter({local: true}); + assert.isFalse(committer.isPresent()); }); }); From 19f9d9f24b864c51533cfd8023006224150d7a42 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 10:02:33 -0400 Subject: [PATCH 0012/4847] Sort and match Authors --- lib/models/author.js | 14 ++++++++++++++ test/models/author.test.js | 14 +++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/models/author.js b/lib/models/author.js index b6f29eb6ce..f2f6f32660 100644 --- a/lib/models/author.js +++ b/lib/models/author.js @@ -31,6 +31,10 @@ export default class Author { return true; } + matches(other) { + return this.getEmail() === other.getEmail(); + } + toString() { let s = `${this.fullName} <${this.email}>`; if (this.hasLogin()) { @@ -38,6 +42,12 @@ export default class Author { } return s; } + + static compare(a, b) { + if (a.getFullName() < b.getFullName()) { return -1; } + if (a.getFullName() > b.getFullName()) { return 1; } + return 0; + } } export const nullAuthor = { @@ -65,6 +75,10 @@ export const nullAuthor = { return false; }, + matches(other) { + return other === this; + }, + toString() { return 'null author'; }, diff --git a/test/models/author.test.js b/test/models/author.test.js index ed2f444d8d..6f5952ec2c 100644 --- a/test/models/author.test.js +++ b/test/models/author.test.js @@ -1,4 +1,4 @@ -import Author, {NO_REPLY_GITHUB_EMAIL} from '../../lib/models/author'; +import Author, {nullAuthor, NO_REPLY_GITHUB_EMAIL} from '../../lib/models/author'; describe('Author', function() { it('recognizes the no-reply GitHub email address', function() { @@ -16,4 +16,16 @@ describe('Author', function() { const a1 = new Author('other@bar.com', 'Nah'); assert.isFalse(a1.hasLogin()); }); + + it('implements matching by email address', function() { + const a0 = new Author('same@same.com', 'Zero'); + const a1 = new Author('same@same.com', 'One'); + const a2 = new Author('same@same.com', 'Two', 'two'); + const a3 = new Author('different@same.com', 'Three'); + + assert.isTrue(a0.matches(a1)); + assert.isTrue(a0.matches(a2)); + assert.isFalse(a0.matches(a3)); + assert.isFalse(a0.matches(nullAuthor)); + }); }); From 00ae45c45ac76543b58c51e6e22211790fcff7eb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 10:02:53 -0400 Subject: [PATCH 0013/4847] Store Authors sorted within the UserStore --- lib/models/user-store.js | 175 ++++++++++++++++++--------------- test/models/user-store.test.js | 82 +++++++-------- 2 files changed, 126 insertions(+), 131 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index 6c0e784d00..2c3211d476 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -1,10 +1,9 @@ import RelayNetworkLayerManager from '../relay-network-layer-manager'; +import Author, {nullAuthor} from './author'; // This is a guess about what a reasonable value is. Can adjust if performance is poor. const MAX_COMMITS = 5000; -export const NO_REPLY_GITHUB_EMAIL = 'noreply@github.com'; - export default class UserStore { constructor({repository, onDidUpdate}) { this.repository = repository; @@ -13,8 +12,10 @@ export default class UserStore { }); this.onDidUpdate = onDidUpdate || (() => {}); // TODO: [ku 3/2018] Consider using Dexie (indexDB wrapper) like Desktop and persist users across sessions - this.users = {}; - this.committer = {}; + + this.allUsers = new Map(); + this.users = []; + this.committer = nullAuthor; this.populate(); } @@ -35,32 +36,110 @@ export default class UserStore { this.setCommitter(committer); const githubRemotes = (await this.repository.getRemotes()).filter(remote => remote.isGithubRepo()); - githubRemotes.length === 0 - ? await this.loadUsersFromLocalRepo() - : await this.loadUsersFromGraphQL(githubRemotes); + if (githubRemotes.length === 0) { + await this.loadUsersFromLocalRepo(); + } else { + await this.loadUsersFromGraphQL(githubRemotes); + } } async loadUsersFromLocalRepo() { const users = await this.repository.getAuthors({max: MAX_COMMITS}); this.addUsers(users); - this.didUpdate(); } loadUsersFromGraphQL(remotes) { - for (const remote of remotes) { - getMentionableUsers(remote, users => { - this.addUsers(users); - this.didUpdate(); + return Promise.all( + remotes.map(remote => this.loadMentionableUsers(remote)), + ); + } + + async loadMentionableUsers(remote) { + const fetchQuery = RelayNetworkLayerManager.getExistingFetchQuery('https://api.github.com/graphql'); + if (!fetchQuery) { + // No authentication token + return; + } + + let hasMore = true; + let cursor = null; + + while (hasMore) { + const response = await fetchQuery({ + name: 'GetMentionableUsers', + text: ` + query GetMentionableUsers { + repository(owner: $owner, name: $name) { + mentionableUsers(first: $first, after: $after) { + nodes { + login + email + name + } + pageInfo { + hasNextPage + endCursor + } + } + } + } + `, + }, { + owner: remote.getOwner(), + name: remote.getRepo(), + first: 100, + after: cursor, }); + + const connection = response.data.repository.mentionableUsers; + + this.addUsers(connection.nodes.map(node => { + if (node.email === '') { + node.email = `${node.login}@users.noreply.github.com`; + } + + return new Author(node.email, node.name, node.login); + })); + + cursor = connection.pageInfo.endCursor; + hasMore = connection.pageInfo.hasNextPage; } } addUsers(users) { - this.users = {...this.users, ...users}; + let changed = false; + for (const author of users) { + if (!this.allUsers.has(author.getEmail())) { + changed = true; + } + this.allUsers.set(author.getEmail(), author); + } + + if (changed) { + this.finalize(); + } + } + + finalize() { + // TODO: [ku 3/2018] consider sorting based on most recent authors or commit frequency + const users = []; + for (const author of this.allUsers.values()) { + if (author.matches(this.committer)) { continue; } + if (author.isNoReply()) { continue; } + + users.push(author); + } + users.sort(Author.compare); + this.users = users; + this.didUpdate(); } setCommitter(committer) { + const changed = !this.committer.matches(committer); this.committer = committer; + if (changed) { + this.finalize(); + } } didUpdate() { @@ -68,74 +147,6 @@ export default class UserStore { } getUsers() { - // TODO: [ku 3/2018] consider sorting based on most recent authors or commit frequency - // Also, this is obviously not the most performant. Optimize once we incorporate github username info, - // as this will likely impact the shape of the data we store - const users = this.users; - - // you wouldn't download a car. you wouldn't add yourself as a co author. - delete users[this.committer.email]; - delete users[NO_REPLY_GITHUB_EMAIL]; - - return Object.keys(users) - .map(email => ({email, name: this.users[email]})) - .sort((a, b) => { - if (a.name < b.name) { return -1; } - if (a.name > b.name) { return 1; } - return 0; - }); - } -} - -async function getMentionableUsers(remote, callback) { - const fetchQuery = RelayNetworkLayerManager.getExistingFetchQuery('https://api.github.com/graphql'); - if (!fetchQuery) { - // No authentication token - return; - } - - let hasMore = true; - let cursor = null; - - while (hasMore) { - const response = await fetchQuery({ - name: 'GetMentionableUsers', - text: ` - query GetMentionableUsers { - repository(owner: $owner, name: $name) { - mentionableUsers(first: $first, after: $after) { - nodes { - login - email - name - } - pageInfo { - hasNextPage - endCursor - } - } - } - } - `, - }, { - owner: remote.getOwner(), - name: remote.getRepo(), - first: 100, - after: cursor, - }); - - const connection = response.data.repository.mentionableUsers; - - callback(connection.nodes.reduce((acc, node) => { - if (node.email === '') { - node.email = `${node.login}@users.noreply.github.com`; - } - - acc[node.email] = node.name; - return acc; - }, {})); - - cursor = connection.pageInfo.endCursor; - hasMore = connection.pageInfo.hasNextPage; + return this.users; } } diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index b71d5a541d..1a519b9695 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -1,6 +1,7 @@ import dedent from 'dedent-js'; -import UserStore, {NO_REPLY_GITHUB_EMAIL} from '../../lib/models/user-store'; +import UserStore from '../../lib/models/user-store'; +import Author, {nullAuthor} from '../../lib/models/author'; import RelayNetworkLayerManager, {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import {cloneRepository, buildRepository, FAKE_USER} from '../helpers'; @@ -11,16 +12,13 @@ describe('UserStore', function() { const store = new UserStore({repository}); assert.deepEqual(store.getUsers(), []); - assert.deepEqual(store.committer, {}); + assert.strictEqual(store.committer, nullAuthor); // Store is populated asynchronously await assert.async.deepEqual(store.getUsers(), [ - { - email: 'kuychaco@github.com', - name: 'Katrina Uychaco', - }, + new Author('kuychaco@github.com', 'Katrina Uychaco'), ]); - await assert.async.deepEqual(store.committer, FAKE_USER); + await assert.async.deepEqual(store.committer, new Author(FAKE_USER.email, FAKE_USER.name)); }); it('loads store with mentionable users from the GitHub API in a repo with a GitHub remote', async function() { @@ -59,9 +57,9 @@ describe('UserStore', function() { resolve(); await assert.async.deepEqual(store.getUsers(), [ - {email: 'smashwilson@github.com', name: 'Ash Wilson'}, - {email: 'mona@lisa.com', name: 'Mona Lisa'}, - {email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, + new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), + new Author('mona@lisa.com', 'Mona Lisa', 'octocat'), + new Author('annthurium@github.com', 'Tilde Ann Thurium', 'annthurium'), ]); }); @@ -116,18 +114,18 @@ describe('UserStore', function() { resolve0(); await assert.async.deepEqual(store.getUsers(), [ - {email: 'smashwilson@github.com', name: 'Ash Wilson'}, - {email: 'mona@lisa.com', name: 'Mona Lisa'}, - {email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, + new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), + new Author('mona@lisa.com', 'Mona Lisa', 'octocat'), + new Author('annthurium@github.com', 'Tilde Ann Thurium', 'annthurium'), ]); resolve1(); await assert.async.deepEqual(store.getUsers(), [ - {email: 'aaa@github.com', name: 'Aahhhhh'}, - {email: 'smashwilson@github.com', name: 'Ash Wilson'}, - {email: 'mona@lisa.com', name: 'Mona Lisa'}, - {email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, - {email: 'zzz@github.com', name: 'Zzzzz'}, + new Author('aaa@github.com', 'Aahhhhh', 'aaa'), + new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), + new Author('mona@lisa.com', 'Mona Lisa', 'octocat'), + new Author('annthurium@github.com', 'Tilde Ann Thurium', 'annthurium'), + new Author('zzz@github.com', 'Zzzzz', 'zzz'), ]); }); @@ -161,7 +159,7 @@ describe('UserStore', function() { resolve(); await assert.async.deepEqual(store.getUsers(), [ - {email: 'simurai@users.noreply.github.com', name: 'simurai'}, + new Author('simurai@users.noreply.github.com', 'simurai', 'simurai'), ]); }); @@ -182,12 +180,10 @@ describe('UserStore', function() { // verify that FAKE_USER is not in users returned from `getUsers` const users = store.getUsers(); - const committerFromStore = users.find(user => user.email === FAKE_USER.email); - assert.isUndefined(committerFromStore); + assert.isFalse(users.some(user => user.getEmail() === FAKE_USER.email)); // verify that no-reply email address is not in users array - const noReplyUser = users.find(user => user.email === NO_REPLY_GITHUB_EMAIL); - assert.isUndefined(noReplyUser); + assert.isFalse(users.some(user => user.isNoReply())); }); describe('addUsers', function() { @@ -198,24 +194,15 @@ describe('UserStore', function() { await assert.async.lengthOf(store.getUsers(), 1); - store.addUsers({ - 'mona@lisa.com': 'Mona Lisa', - 'hubot@github.com': 'Hubot Robot', - }); + store.addUsers([ + new Author('mona@lisa.com', 'Mona Lisa'), + new Author('hubot@github.com', 'Hubot Robot'), + ]); - await assert.async.deepEqual(store.getUsers(), [ - { - name: 'Hubot Robot', - email: 'hubot@github.com', - }, - { - name: 'Katrina Uychaco', - email: 'kuychaco@github.com', - }, - { - name: 'Mona Lisa', - email: 'mona@lisa.com', - }, + assert.deepEqual(store.getUsers(), [ + new Author('hubot@github.com', 'Hubot Robot'), + new Author('kuychaco@github.com', 'Katrina Uychaco'), + new Author('mona@lisa.com', 'Mona Lisa'), ]); }); }); @@ -225,18 +212,18 @@ describe('UserStore', function() { const repository = await buildRepository(workdirPath); const store = new UserStore({repository}); - await assert.async.deepEqual(store.committer, FAKE_USER); + await assert.async.deepEqual(store.committer, new Author(FAKE_USER.email, FAKE_USER.name)); const newEmail = 'foo@bar.com'; await repository.setConfig('user.email', newEmail); repository.refresh(); - await assert.async.deepEqual(store.committer, {name: FAKE_USER.name, email: newEmail}); + await assert.async.deepEqual(store.committer, new Author(FAKE_USER.email, FAKE_USER.name)); const newName = 'Foo Bar'; await repository.setConfig('user.name', newName); repository.refresh(); - await assert.async.deepEqual(store.committer, {name: newName, email: newEmail}); + await assert.async.deepEqual(store.committer, new Author(newEmail, newName)); }); it('refetches users when HEAD changes', async function() { @@ -249,10 +236,7 @@ describe('UserStore', function() { const store = new UserStore({repository}); await assert.async.deepEqual(store.getUsers(), [ - { - email: 'kuychaco@github.com', - name: 'Katrina Uychaco', - }, + new Author('kuychaco@github.com', 'Katrina Uychaco'), ]); sinon.spy(store, 'addUsers'); @@ -265,8 +249,8 @@ describe('UserStore', function() { `, {allowEmpty: true}); await assert.async.equal(store.addUsers.callCount, 1); - assert.isOk(store.getUsers().find(user => { - return user.name === 'New Author' && user.email === 'new-author@email.com'; + assert.isTrue(store.getUsers().some(user => { + return user.getFullName() === 'New Author' && user.getEmail() === 'new-author@email.com'; })); // Change head due to branch checkout From 9576c1fd0329033332184f287380671598b76882 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 10:40:41 -0400 Subject: [PATCH 0014/4847] Use a ModelObserver to track the Repository --- lib/models/user-store.js | 48 ++++++++++++++++------------------ test/models/user-store.test.js | 2 +- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index 2c3211d476..bfb558d13a 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -1,53 +1,47 @@ +import yubikiri from 'yubikiri'; + import RelayNetworkLayerManager from '../relay-network-layer-manager'; import Author, {nullAuthor} from './author'; +import ModelObserver from './model-observer'; // This is a guess about what a reasonable value is. Can adjust if performance is poor. const MAX_COMMITS = 5000; export default class UserStore { constructor({repository, onDidUpdate}) { - this.repository = repository; - this.repository.onDidUpdate(() => { - this.loadUsers(); - }); this.onDidUpdate = onDidUpdate || (() => {}); // TODO: [ku 3/2018] Consider using Dexie (indexDB wrapper) like Desktop and persist users across sessions this.allUsers = new Map(); this.users = []; this.committer = nullAuthor; - this.populate(); + + this.repositoryObserver = new ModelObserver({ + fetchData: r => yubikiri({ + committer: r.getCommitter(), + authors: r.getAuthors({max: MAX_COMMITS}), + remotes: r.getRemotes(), + }), + didUpdate: () => this.loadUsers(this.repositoryObserver.getActiveModelData()), + }); + this.repositoryObserver.setActiveModel(repository); } - populate() { - if (this.repository.isPresent()) { - this.loadUsers(); - } else { - this.repository.onDidChangeState(({from, to}) => { - if (!from.isPresent() && to.isPresent()) { - this.loadUsers(); - } - }); + async loadUsers(data) { + if (!data) { + return; } - } - async loadUsers() { - const committer = await this.repository.getCommitter(); - this.setCommitter(committer); + this.setCommitter(data.committer); - const githubRemotes = (await this.repository.getRemotes()).filter(remote => remote.isGithubRepo()); + const githubRemotes = data.remotes.filter(remote => remote.isGithubRepo()); if (githubRemotes.length === 0) { - await this.loadUsersFromLocalRepo(); + this.addUsers(data.authors); } else { await this.loadUsersFromGraphQL(githubRemotes); } } - async loadUsersFromLocalRepo() { - const users = await this.repository.getAuthors({max: MAX_COMMITS}); - this.addUsers(users); - } - loadUsersFromGraphQL(remotes) { return Promise.all( remotes.map(remote => this.loadMentionableUsers(remote)), @@ -134,6 +128,10 @@ export default class UserStore { this.didUpdate(); } + setRepository(repository) { + this.repositoryObserver.setActiveModel(repository); + } + setCommitter(committer) { const changed = !this.committer.matches(committer); this.committer = committer; diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 1a519b9695..66bd3ca47c 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -167,7 +167,7 @@ describe('UserStore', function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); const store = new UserStore({repository}); - await store.loadUsersFromLocalRepo(); + await assert.async.lengthOf(store.getUsers(), 1); sinon.spy(store, 'addUsers'); // make a commit with FAKE_USER as committer From 0a6a903c90b722c910dd594c47fc3a15b3db0b95 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 10:48:09 -0400 Subject: [PATCH 0015/4847] Turn UserStore into an event Emitter --- lib/models/user-store.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index bfb558d13a..cf4d7b3d92 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -1,4 +1,5 @@ import yubikiri from 'yubikiri'; +import {Emitter} from 'event-kit'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; import Author, {nullAuthor} from './author'; @@ -8,10 +9,10 @@ import ModelObserver from './model-observer'; const MAX_COMMITS = 5000; export default class UserStore { - constructor({repository, onDidUpdate}) { - this.onDidUpdate = onDidUpdate || (() => {}); - // TODO: [ku 3/2018] Consider using Dexie (indexDB wrapper) like Desktop and persist users across sessions + constructor({repository}) { + this.emitter = new Emitter(); + // TODO: [ku 3/2018] Consider using Dexie (indexDB wrapper) like Desktop and persist users across sessions this.allUsers = new Map(); this.users = []; this.committer = nullAuthor; @@ -141,7 +142,11 @@ export default class UserStore { } didUpdate() { - this.onDidUpdate(this.getUsers()); + this.emitter.emit('did-update', this.getUsers()); + } + + onDidUpdate(callback) { + return this.emitter.on('did-update', callback); } getUsers() { From e4f92a8f29cb57473075d61255a52f910528472a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:07:23 -0400 Subject: [PATCH 0016/4847] PropType shapes for new models --- lib/prop-types.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/prop-types.js b/lib/prop-types.js index b099508491..2d17a1994a 100644 --- a/lib/prop-types.js +++ b/lib/prop-types.js @@ -38,8 +38,8 @@ export const CommitPropType = PropTypes.shape({ }); export const AuthorPropType = PropTypes.shape({ - email: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, + getEmail: PropTypes.func.isRequired, + getFullName: PropTypes.func.isRequired, }); export const RelayConnectionPropType = nodePropType => PropTypes.shape({ @@ -86,3 +86,8 @@ export const MergeConflictItemPropType = PropTypes.shape({ theirs: PropTypes.oneOf(statusNames).isRequired, }).isRequired, }); + +export const UserStorePropType = PropTypes.shape({ + getUsers: PropTypes.func.isRequired, + onDidUpdate: PropTypes.func.isRequired, +}); From edf3bb1a04092636b70209421d17a9be6409b333 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:07:37 -0400 Subject: [PATCH 0017/4847] getAuthors() stub should return [] --- lib/models/repository-states/state.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/repository-states/state.js b/lib/models/repository-states/state.js index aa1756107e..c24f9080a1 100644 --- a/lib/models/repository-states/state.js +++ b/lib/models/repository-states/state.js @@ -293,7 +293,7 @@ export default class State { // Author information getAuthors() { - return Promise.resolve({}); + return Promise.resolve([]); } // Branches From 7ee56cbcac7db2688d40d392f83ba1cad36bc5b8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:09:14 -0400 Subject: [PATCH 0018/4847] The UserStore observes its Repository --- lib/controllers/git-tab-controller.js | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index 7b98772179..7d5a49b5dc 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -66,12 +66,7 @@ export default class GitTabController extends React.Component { selectedCoAuthors: [], }; - this.userStore = new UserStore({ - repository: this.props.repository, - onDidUpdate: users => { - this.setState({mentionableUsers: users}); - }, - }); + this.userStore = new UserStore({repository: this.props.repository}); } render() { @@ -135,16 +130,8 @@ export default class GitTabController extends React.Component { this.refView.refRoot.addEventListener('focusin', this.rememberLastFocus); } - componentDidUpdate(prevProps) { - if (prevProps.repository !== this.props.repository) { - this.userStore = new UserStore({ - repository: this.props.repository, - onDidUpdate: users => { - this.setState({mentionableUsers: users}); - }, - }); - } - + componentDidUpdate() { + this.userStore.setRepository(this.props.repository); this.refreshResolutionProgress(false, false); } From c4292dea6dafd96cb1eaf76b3aa8bf4361de59aa Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:09:53 -0400 Subject: [PATCH 0019/4847] Update the UserStore in the updateSelectedCoAuthors callback --- lib/controllers/git-tab-controller.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index 7d5a49b5dc..43c9649864 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -5,6 +5,7 @@ import PropTypes from 'prop-types'; import GitTabView from '../views/git-tab-view'; import UserStore from '../models/user-store'; +import Author from '../models/author'; import {CommitPropType, BranchPropType, FilePatchItemPropType, MergeConflictItemPropType} from '../prop-types'; import {autobind} from '../helpers'; @@ -245,7 +246,7 @@ export default class GitTabController extends React.Component { updateSelectedCoAuthors(selectedCoAuthors, newAuthor) { if (newAuthor) { - this.userStore.addUsers({[newAuthor.email]: newAuthor.name}); + this.userStore.addUsers([newAuthor]); selectedCoAuthors = selectedCoAuthors.concat([newAuthor]); } this.setState({selectedCoAuthors}); From e7772b54225d3fb8a1fb91ee40970f1fba7cd2ec Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:10:22 -0400 Subject: [PATCH 0020/4847] Pass the UserStore through the component tree --- lib/controllers/commit-controller.js | 6 +++--- lib/controllers/git-tab-controller.js | 3 +-- lib/views/git-tab-view.js | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/controllers/commit-controller.js b/lib/controllers/commit-controller.js index 3aa490d25b..240d4a618d 100644 --- a/lib/controllers/commit-controller.js +++ b/lib/controllers/commit-controller.js @@ -7,7 +7,7 @@ import {CompositeDisposable} from 'event-kit'; import fs from 'fs-extra'; import CommitView from '../views/commit-view'; -import {AuthorPropType} from '../prop-types'; +import {AuthorPropType, UserStorePropType} from '../prop-types'; import {autobind} from '../helpers'; export const COMMIT_GRAMMAR_SCOPE = 'text.git-commit'; @@ -31,7 +31,7 @@ export default class CommitController extends React.Component { stagedChangesExist: PropTypes.bool.isRequired, lastCommit: PropTypes.object.isRequired, currentBranch: PropTypes.object.isRequired, - mentionableUsers: PropTypes.arrayOf(AuthorPropType), + userStore: UserStorePropType.isRequired, selectedCoAuthors: PropTypes.arrayOf(AuthorPropType), updateSelectedCoAuthors: PropTypes.func, prepareToCommit: PropTypes.func.isRequired, @@ -105,7 +105,7 @@ export default class CommitController extends React.Component { onChangeMessage={this.handleMessageChange} toggleExpandedCommitMessageEditor={this.toggleExpandedCommitMessageEditor} deactivateCommitBox={this.isCommitMessageEditorExpanded()} - mentionableUsers={this.props.mentionableUsers} + userStore={this.props.userStore} selectedCoAuthors={this.props.selectedCoAuthors} updateSelectedCoAuthors={this.props.updateSelectedCoAuthors} /> diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index 43c9649864..2c9d432304 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -63,7 +63,6 @@ export default class GitTabController extends React.Component { this.refView = null; this.state = { - mentionableUsers: [], selectedCoAuthors: [], }; @@ -89,7 +88,7 @@ export default class GitTabController extends React.Component { mergeConflicts={this.props.mergeConflicts} workingDirectoryPath={this.props.workingDirectoryPath} mergeMessage={this.props.mergeMessage} - mentionableUsers={this.state.mentionableUsers} + userStore={this.userStore} selectedCoAuthors={this.state.selectedCoAuthors} updateSelectedCoAuthors={this.updateSelectedCoAuthors} diff --git a/lib/views/git-tab-view.js b/lib/views/git-tab-view.js index ac75712030..44c6bd9d9e 100644 --- a/lib/views/git-tab-view.js +++ b/lib/views/git-tab-view.js @@ -8,7 +8,7 @@ import GitLogo from './git-logo'; import CommitController from '../controllers/commit-controller'; import RecentCommitsController from '../controllers/recent-commits-controller'; import {isValidWorkdir, autobind} from '../helpers'; -import {AuthorPropType} from '../prop-types'; +import {AuthorPropType, UserStorePropType} from '../prop-types'; export default class GitTabView extends React.Component { static focus = { @@ -32,7 +32,7 @@ export default class GitTabView extends React.Component { mergeConflicts: PropTypes.arrayOf(PropTypes.object), workingDirectoryPath: PropTypes.string, mergeMessage: PropTypes.string, - mentionableUsers: PropTypes.arrayOf(AuthorPropType), + userStore: UserStorePropType.isRequired, selectedCoAuthors: PropTypes.arrayOf(AuthorPropType), updateSelectedCoAuthors: PropTypes.func.isRequired, @@ -184,7 +184,7 @@ export default class GitTabView extends React.Component { isLoading={this.props.isLoading} lastCommit={this.props.lastCommit} repository={this.props.repository} - mentionableUsers={this.props.mentionableUsers} + userStore={this.props.userStore} selectedCoAuthors={this.props.selectedCoAuthors} updateSelectedCoAuthors={this.props.updateSelectedCoAuthors} /> From 65066a3909ec7095e68b50340c74d42d23332495 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:10:45 -0400 Subject: [PATCH 0021/4847] Observe the passed UserStore and update the Select component --- lib/views/commit-view.js | 46 ++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/lib/views/commit-view.js b/lib/views/commit-view.js index b721ab97b7..9c79af933f 100644 --- a/lib/views/commit-view.js +++ b/lib/views/commit-view.js @@ -8,8 +8,9 @@ import Tooltip from '../atom/tooltip'; import AtomTextEditor from '../atom/atom-text-editor'; import CoAuthorForm from './co-author-form'; import RefHolder from '../models/ref-holder'; +import ObserveModel from './observe-model'; import {LINE_ENDING_REGEX, autobind} from '../helpers'; -import {AuthorPropType} from '../prop-types'; +import {AuthorPropType, UserStorePropType} from '../prop-types'; const TOOLTIP_DELAY = 200; @@ -39,7 +40,7 @@ export default class CommitView extends React.Component { deactivateCommitBox: PropTypes.bool.isRequired, maximumCharacterLimit: PropTypes.number.isRequired, message: PropTypes.string.isRequired, - mentionableUsers: PropTypes.arrayOf(AuthorPropType), + userStore: UserStorePropType.isRequired, selectedCoAuthors: PropTypes.arrayOf(AuthorPropType), updateSelectedCoAuthors: PropTypes.func, commit: PropTypes.func.isRequired, @@ -246,30 +247,33 @@ export default class CommitView extends React.Component { } renderCoAuthorInput() { - if (!this.state.showCoAuthorInput) { return null; } return ( - + )} + ); } From ea65ac0ad1e3a8251350c34720f463a74210c62e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:11:29 -0400 Subject: [PATCH 0022/4847] Pass an empty UserStore in tests --- test/controllers/commit-controller.test.js | 3 +++ test/views/commit-view.test.js | 3 +++ 2 files changed, 6 insertions(+) diff --git a/test/controllers/commit-controller.test.js b/test/controllers/commit-controller.test.js index 396b69c2dc..fa0b7d867a 100644 --- a/test/controllers/commit-controller.test.js +++ b/test/controllers/commit-controller.test.js @@ -5,6 +5,7 @@ import {shallow} from 'enzyme'; import Commit from '../../lib/models/commit'; import {nullBranch} from '../../lib/models/branch'; +import UserStore from '../../lib/models/user-store'; import CommitController, {COMMIT_GRAMMAR_SCOPE} from '../../lib/controllers/commit-controller'; import {cloneRepository, buildRepository, buildRepositoryWithPipeline} from '../helpers'; @@ -24,6 +25,7 @@ describe('CommitController', function() { lastCommit = new Commit({sha: 'a1e23fd45', message: 'last commit message'}); const noop = () => {}; + const store = new UserStore({}); app = ( {}; const returnTruthyPromise = () => Promise.resolve(true); + const store = new UserStore({}); app = ( Date: Tue, 22 May 2018 14:11:40 -0400 Subject: [PATCH 0023/4847] Import shuffle --- test/controllers/git-tab-controller.test.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/controllers/git-tab-controller.test.js b/test/controllers/git-tab-controller.test.js index b6eba8e027..1221d77492 100644 --- a/test/controllers/git-tab-controller.test.js +++ b/test/controllers/git-tab-controller.test.js @@ -1,20 +1,17 @@ import fs from 'fs'; import path from 'path'; - import React from 'react'; import {mount} from 'enzyme'; - import dedent from 'dedent-js'; import until from 'test-until'; import GitTabController from '../../lib/controllers/git-tab-controller'; import {gitTabControllerProps} from '../fixtures/props/git-tab-props'; - import {cloneRepository, buildRepository, buildRepositoryWithPipeline, initRepository} from '../helpers'; import Repository from '../../lib/models/repository'; -import {GitError} from '../../lib/git-shell-out-strategy'; - +import Author from '../../lib/models/author'; import ResolutionProgress from '../../lib/models/conflicts/resolution-progress'; +import {GitError} from '../../lib/git-shell-out-strategy'; describe('GitTabController', function() { let atomEnvironment, workspace, workspaceElement, commandRegistry, notificationManager; From b9b97053a3de934729046106b5ac4818e70827a8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:11:53 -0400 Subject: [PATCH 0024/4847] I... have no idea how this was passing before? --- test/controllers/git-tab-controller.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/controllers/git-tab-controller.test.js b/test/controllers/git-tab-controller.test.js index 1221d77492..af5a4f17ca 100644 --- a/test/controllers/git-tab-controller.test.js +++ b/test/controllers/git-tab-controller.test.js @@ -65,6 +65,9 @@ describe('GitTabController', function() { assert.lengthOf(wrapper.find('StagingView'), 1); assert.lengthOf(wrapper.find('CommitController'), 1); + await repository.getLoadPromise(); + await updateWrapper(repository, wrapper); + await assert.async.isFalse(wrapper.update().find('.github-Panel').hasClass('is-loading')); assert.lengthOf(wrapper.find('StagingView'), 1); assert.lengthOf(wrapper.find('CommitController'), 1); From 3985f558d990fe854e727b08be67bb3665bb10d8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:12:05 -0400 Subject: [PATCH 0025/4847] Use the Author model in the test fixture --- test/controllers/git-tab-controller.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/controllers/git-tab-controller.test.js b/test/controllers/git-tab-controller.test.js index af5a4f17ca..e864c58cba 100644 --- a/test/controllers/git-tab-controller.test.js +++ b/test/controllers/git-tab-controller.test.js @@ -169,8 +169,8 @@ describe('GitTabController', function() { const repository = await buildRepository(workdirPath); const wrapper = mount(await buildApp(repository)); - const coAuthors = [{name: 'Mona Lisa', email: 'mona@lisa.com'}]; - const newAuthor = {name: 'Mr. Hubot', email: 'hubot@github.com'}; + const coAuthors = [new Author('mona@lisa.com', 'Mona Lisa')]; + const newAuthor = new Author('hubot@github.com', 'Mr. Hubot'); wrapper.instance().updateSelectedCoAuthors(coAuthors, newAuthor); From 0c64139478ea921166f33793677d9194aa33026b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:32:44 -0400 Subject: [PATCH 0026/4847] :fire: unused import --- lib/controllers/git-tab-controller.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index 2c9d432304..e57e06ff70 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -5,7 +5,6 @@ import PropTypes from 'prop-types'; import GitTabView from '../views/git-tab-view'; import UserStore from '../models/user-store'; -import Author from '../models/author'; import {CommitPropType, BranchPropType, FilePatchItemPropType, MergeConflictItemPropType} from '../prop-types'; import {autobind} from '../helpers'; From 1d84a611a4c2ffa16164df984594f08e36d36b23 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:33:02 -0400 Subject: [PATCH 0027/4847] Present talks model objects, GSOS talks raw objects --- lib/models/repository-states/present.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index cf3780eae1..bd8c2fb7c9 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -233,7 +233,16 @@ export default class Present extends State { ], // eslint-disable-next-line no-shadow () => this.executePipelineAction('COMMIT', (message, options) => { - return this.git().commit(message, options); + const opts = (!options || !options.coAuthors) + ? options + : { + ...options, + coAuthors: options.coAuthors.map(author => { + return {email: author.getEmail(), name: author.getFullName()}; + }), + }; + + return this.git().commit(message, opts); }, message, options), ); } From 68ea76c2016aedeb17030460c10c99bed9d77469 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:33:10 -0400 Subject: [PATCH 0028/4847] More Author model usage --- test/controllers/git-tab-controller.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/controllers/git-tab-controller.test.js b/test/controllers/git-tab-controller.test.js index e864c58cba..5a1e7a7f32 100644 --- a/test/controllers/git-tab-controller.test.js +++ b/test/controllers/git-tab-controller.test.js @@ -609,7 +609,7 @@ describe('GitTabController', function() { assert.deepEqual(commitBeforeAmend.coAuthors, []); // add co author - const author = {email: 'foo@bar.com', name: 'foo bar'}; + const author = new Author('foo@bar.com', 'foo bar'); const commitView = wrapper.find('CommitView').instance(); commitView.setState({showCoAuthorInput: true}); commitView.onSelectedCoAuthorsChanged([author]); @@ -621,7 +621,7 @@ describe('GitTabController', function() { await repository.commit.returnValues[0]; await updateWrapper(repository, wrapper); - assert.deepEqual(getLastCommit().coAuthors, [author]); + assert.deepEqual(getLastCommit().coAuthors, [{email: author.getEmail(), name: author.getFullName()}]); assert.strictEqual(getLastCommit().getMessageSubject(), commitBeforeAmend.getMessageSubject()); }); From f9e71462c5eb6cad923684dc4c26b938e37ca832 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 May 2018 14:43:30 -0400 Subject: [PATCH 0029/4847] Another Author model --- test/controllers/git-tab-controller.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/controllers/git-tab-controller.test.js b/test/controllers/git-tab-controller.test.js index 5a1e7a7f32..2a6abbb17a 100644 --- a/test/controllers/git-tab-controller.test.js +++ b/test/controllers/git-tab-controller.test.js @@ -631,7 +631,7 @@ describe('GitTabController', function() { assert.deepEqual(commitBeforeAmend.coAuthors, []); // add co author - const author = {email: 'foo@bar.com', name: 'foo bar'}; + const author = new Author('foo@bar.com', 'foo bar'); const commitView = wrapper.find('CommitView').instance(); commitView.setState({showCoAuthorInput: true}); commitView.onSelectedCoAuthorsChanged([author]); @@ -645,7 +645,7 @@ describe('GitTabController', function() { await updateWrapper(repository, wrapper); // verify that commit message has coauthor - assert.deepEqual(getLastCommit().coAuthors, [author]); + assert.deepEqual(getLastCommit().coAuthors, [{email: author.getEmail(), name: author.getFullName()}]); assert.strictEqual(getLastCommit().getMessageSubject(), newMessage); }); From c8c60510466cd12e561947cdcd8f23e1096a3e2e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 May 2018 11:41:26 -0400 Subject: [PATCH 0030/4847] Acquire the token from the GithubLoginModel --- lib/models/user-store.js | 26 ++++-- lib/relay-network-layer-manager.js | 9 +- test/models/user-store.test.js | 140 ++++++++++++++++++++++++----- 3 files changed, 139 insertions(+), 36 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index cf4d7b3d92..f0898b8d4a 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -3,13 +3,14 @@ import {Emitter} from 'event-kit'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; import Author, {nullAuthor} from './author'; +import {UNAUTHENTICATED} from '../shared/keytar-strategy'; import ModelObserver from './model-observer'; // This is a guess about what a reasonable value is. Can adjust if performance is poor. const MAX_COMMITS = 5000; export default class UserStore { - constructor({repository}) { + constructor({repository, login}) { this.emitter = new Emitter(); // TODO: [ku 3/2018] Consider using Dexie (indexDB wrapper) like Desktop and persist users across sessions @@ -23,12 +24,19 @@ export default class UserStore { authors: r.getAuthors({max: MAX_COMMITS}), remotes: r.getRemotes(), }), - didUpdate: () => this.loadUsers(this.repositoryObserver.getActiveModelData()), + didUpdate: () => this.loadUsers(), }); this.repositoryObserver.setActiveModel(repository); + + this.loginObserver = new ModelObserver({ + didUpdate: () => this.loadUsers(), + }); + this.loginObserver.setActiveModel(login); } - async loadUsers(data) { + async loadUsers() { + const data = this.repositoryObserver.getActiveModelData(); + if (!data) { return; } @@ -50,12 +58,18 @@ export default class UserStore { } async loadMentionableUsers(remote) { - const fetchQuery = RelayNetworkLayerManager.getExistingFetchQuery('https://api.github.com/graphql'); - if (!fetchQuery) { - // No authentication token + const loginModel = this.loginObserver.getActiveModel(); + if (!loginModel) { return; } + const token = await loginModel.getToken('https://api.github.com'); + if (token === UNAUTHENTICATED) { + return; + } + + const fetchQuery = RelayNetworkLayerManager.getFetchQuery('https://api.github.com/graphql', token); + let hasMore = true; let cursor = null; diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index f63f74b92c..cf1a821b79 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -100,7 +100,7 @@ export default class RelayNetworkLayerManager { if (!environment) { const source = new RecordSource(); const store = new Store(source); - network = Network.create(this.getExistingFetchQuery(url)); + network = Network.create(this.getFetchQuery(url)); environment = new Environment({network, store}); relayEnvironmentPerGithubHost.set(host, {environment, network}); @@ -108,11 +108,8 @@ export default class RelayNetworkLayerManager { return environment; } - static getExistingFetchQuery(url) { - if (!tokenPerURL.has(url)) { - return null; - } - + static getFetchQuery(url, token) { + tokenPerURL.set(url, token); let fetch = fetchPerURL.get(url); if (!fetch) { fetch = createFetchQuery(url); diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 66bd3ca47c..7aac4b49ac 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -2,10 +2,27 @@ import dedent from 'dedent-js'; import UserStore from '../../lib/models/user-store'; import Author, {nullAuthor} from '../../lib/models/author'; -import RelayNetworkLayerManager, {expectRelayQuery} from '../../lib/relay-network-layer-manager'; +import GithubLoginModel from '../../lib/models/github-login-model'; +import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; +import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import {cloneRepository, buildRepository, FAKE_USER} from '../helpers'; describe('UserStore', function() { + let login; + + function nextUpdatePromise(store) { + return new Promise(resolve => { + const sub = store.onDidUpdate(() => { + sub.dispose(); + resolve(); + }); + }); + } + + beforeEach(function() { + login = new GithubLoginModel(InMemoryStrategy); + }); + it('loads store with local git users and committer in a repo with no GitHub remote', async function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); @@ -15,14 +32,15 @@ describe('UserStore', function() { assert.strictEqual(store.committer, nullAuthor); // Store is populated asynchronously - await assert.async.deepEqual(store.getUsers(), [ + await nextUpdatePromise(store); + assert.deepEqual(store.getUsers(), [ new Author('kuychaco@github.com', 'Katrina Uychaco'), ]); - await assert.async.deepEqual(store.committer, new Author(FAKE_USER.email, FAKE_USER.name)); + assert.deepEqual(store.committer, new Author(FAKE_USER.email, FAKE_USER.name)); }); it('loads store with mentionable users from the GitHub API in a repo with a GitHub remote', async function() { - RelayNetworkLayerManager.getEnvironmentForHost('https://api.github.com', '1234'); + await login.setToken('https://api.github.com', '1234'); const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); @@ -51,12 +69,13 @@ describe('UserStore', function() { }, }); - const store = new UserStore({repository}); - assert.deepEqual(store.getUsers(), []); + const store = new UserStore({repository, login}); + await nextUpdatePromise(store); resolve(); + await nextUpdatePromise(store); - await assert.async.deepEqual(store.getUsers(), [ + assert.deepEqual(store.getUsers(), [ new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), new Author('mona@lisa.com', 'Mona Lisa', 'octocat'), new Author('annthurium@github.com', 'Tilde Ann Thurium', 'annthurium'), @@ -64,7 +83,7 @@ describe('UserStore', function() { }); it('loads users from multiple pages from the GitHub API', async function() { - RelayNetworkLayerManager.getEnvironmentForHost('https://api.github.com', '1234'); + await login.setToken('https://api.github.com', '1234'); const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); @@ -109,18 +128,24 @@ describe('UserStore', function() { }, }); - const store = new UserStore({repository}); + const store = new UserStore({repository, login}); + + await nextUpdatePromise(store); assert.deepEqual(store.getUsers(), []); resolve0(); - await assert.async.deepEqual(store.getUsers(), [ + await nextUpdatePromise(store); + + assert.deepEqual(store.getUsers(), [ new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), new Author('mona@lisa.com', 'Mona Lisa', 'octocat'), new Author('annthurium@github.com', 'Tilde Ann Thurium', 'annthurium'), ]); resolve1(); - await assert.async.deepEqual(store.getUsers(), [ + await nextUpdatePromise(store); + + assert.deepEqual(store.getUsers(), [ new Author('aaa@github.com', 'Aahhhhh', 'aaa'), new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), new Author('mona@lisa.com', 'Mona Lisa', 'octocat'), @@ -130,7 +155,7 @@ describe('UserStore', function() { }); it('infers no-reply emails for users without a public email address', async function() { - RelayNetworkLayerManager.getEnvironmentForHost('https://api.github.com', '1234'); + await login.setToken('https://api.github.com', '1234'); const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); @@ -155,10 +180,13 @@ describe('UserStore', function() { }, }); - const store = new UserStore({repository}); + const store = new UserStore({repository, login}); + await nextUpdatePromise(store); resolve(); - await assert.async.deepEqual(store.getUsers(), [ + await nextUpdatePromise(store); + + assert.deepEqual(store.getUsers(), [ new Author('simurai@users.noreply.github.com', 'simurai', 'simurai'), ]); }); @@ -212,18 +240,18 @@ describe('UserStore', function() { const repository = await buildRepository(workdirPath); const store = new UserStore({repository}); - await assert.async.deepEqual(store.committer, new Author(FAKE_USER.email, FAKE_USER.name)); + await nextUpdatePromise(store); + assert.deepEqual(store.committer, new Author(FAKE_USER.email, FAKE_USER.name)); const newEmail = 'foo@bar.com'; - await repository.setConfig('user.email', newEmail); - - repository.refresh(); - await assert.async.deepEqual(store.committer, new Author(FAKE_USER.email, FAKE_USER.name)); - const newName = 'Foo Bar'; + + await repository.setConfig('user.email', newEmail); await repository.setConfig('user.name', newName); repository.refresh(); - await assert.async.deepEqual(store.committer, new Author(newEmail, newName)); + await nextUpdatePromise(store); + + assert.deepEqual(store.committer, new Author(newEmail, newName)); }); it('refetches users when HEAD changes', async function() { @@ -235,7 +263,8 @@ describe('UserStore', function() { await repository.checkout('master'); const store = new UserStore({repository}); - await assert.async.deepEqual(store.getUsers(), [ + await nextUpdatePromise(store); + assert.deepEqual(store.getUsers(), [ new Author('kuychaco@github.com', 'Katrina Uychaco'), ]); @@ -248,13 +277,76 @@ describe('UserStore', function() { Co-authored-by: New Author `, {allowEmpty: true}); - await assert.async.equal(store.addUsers.callCount, 1); + repository.refresh(); + await nextUpdatePromise(store); + + await assert.strictEqual(store.addUsers.callCount, 1); assert.isTrue(store.getUsers().some(user => { return user.getFullName() === 'New Author' && user.getEmail() === 'new-author@email.com'; })); // Change head due to branch checkout await repository.checkout('new-branch'); - await assert.async.equal(store.addUsers.callCount, 2); + repository.refresh(); + + await assert.async.strictEqual(store.addUsers.callCount, 2); + }); + + it('refetches users when a token becomes available', async function() { + const workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + + const gitAuthors = [ + new Author('kuychaco@github.com', 'Katrina Uychaco'), + ]; + + const graphqlAuthors = [ + new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), + new Author('mona@lisa.com', 'Mona Lisa', 'octocat'), + new Author('annthurium@github.com', 'Tilde Ann Thurium', 'annthurium'), + ]; + + const {resolve} = expectRelayQuery({ + name: 'GetMentionableUsers', + variables: {owner: 'me', name: 'stuff', first: 100, after: null}, + }, { + repository: { + mentionableUsers: { + nodes: [ + {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, + {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, + {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, + ], + pageInfo: { + hasNextPage: false, + endCursor: null, + }, + }, + }, + }); + resolve(); + + const store = new UserStore({repository, login}); + await nextUpdatePromise(store); + console.log('initial load complete'); + + assert.deepEqual(store.getUsers(), gitAuthors); + + await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); + await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); + + console.log('about to refresh repository'); + repository.refresh(); + console.log('updated after repository refresh'); + + // Token is not available, so authors are still queried from git + assert.deepEqual(store.getUsers(), gitAuthors); + + console.log('about to fire login update'); + await login.setToken('https://api.github.com', '1234'); + + await nextUpdatePromise(store); + console.log('updated after login update'); + assert.deepEqual(store.getUsers(), graphqlAuthors); }); }); From 138dadc562ad13b7aeacd57991ac130abf5751da Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 May 2018 12:35:58 -0400 Subject: [PATCH 0031/4847] Track the last source of users in a UserStore --- lib/models/user-store.js | 23 +++++++++++++++++++---- test/models/user-store.test.js | 7 ++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index f0898b8d4a..df3abf61c2 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -9,6 +9,12 @@ import ModelObserver from './model-observer'; // This is a guess about what a reasonable value is. Can adjust if performance is poor. const MAX_COMMITS = 5000; +export const source = { + PENDING: Symbol('pending'), + GITLOG: Symbol('git log'), + GITHUBAPI: Symbol('github API'), +}; + export default class UserStore { constructor({repository, login}) { this.emitter = new Emitter(); @@ -18,6 +24,10 @@ export default class UserStore { this.users = []; this.committer = nullAuthor; + this.last = { + source: source.PENDING, + }; + this.repositoryObserver = new ModelObserver({ fetchData: r => yubikiri({ committer: r.getCommitter(), @@ -42,10 +52,10 @@ export default class UserStore { } this.setCommitter(data.committer); - const githubRemotes = data.remotes.filter(remote => remote.isGithubRepo()); + if (githubRemotes.length === 0) { - this.addUsers(data.authors); + this.addUsers(data.authors, source.GITLOG); } else { await this.loadUsersFromGraphQL(githubRemotes); } @@ -108,14 +118,18 @@ export default class UserStore { } return new Author(node.email, node.name, node.login); - })); + }), source.GITHUBAPI); cursor = connection.pageInfo.endCursor; hasMore = connection.pageInfo.hasNextPage; } } - addUsers(users) { + addUsers(users, nextSource) { + if (nextSource !== this.last.source) { + this.allUsers.clear(); + } + let changed = false; for (const author of users) { if (!this.allUsers.has(author.getEmail())) { @@ -127,6 +141,7 @@ export default class UserStore { if (changed) { this.finalize(); } + this.last.source = nextSource; } finalize() { diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 7aac4b49ac..21663da61f 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -1,6 +1,6 @@ import dedent from 'dedent-js'; -import UserStore from '../../lib/models/user-store'; +import UserStore, {source} from '../../lib/models/user-store'; import Author, {nullAuthor} from '../../lib/models/author'; import GithubLoginModel from '../../lib/models/github-login-model'; import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; @@ -219,13 +219,14 @@ describe('UserStore', function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); const store = new UserStore({repository}); + await nextUpdatePromise(store); - await assert.async.lengthOf(store.getUsers(), 1); + assert.lengthOf(store.getUsers(), 1); store.addUsers([ new Author('mona@lisa.com', 'Mona Lisa'), new Author('hubot@github.com', 'Hubot Robot'), - ]); + ], source.GITLOG); assert.deepEqual(store.getUsers(), [ new Author('hubot@github.com', 'Hubot Robot'), From bb734d4a958c6018e4aa7e1b41e80146ac2bff7a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 May 2018 13:53:38 -0400 Subject: [PATCH 0032/4847] :fire: console.logs --- test/models/user-store.test.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 21663da61f..a516377bd2 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -329,25 +329,20 @@ describe('UserStore', function() { const store = new UserStore({repository, login}); await nextUpdatePromise(store); - console.log('initial load complete'); assert.deepEqual(store.getUsers(), gitAuthors); await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); - console.log('about to refresh repository'); repository.refresh(); - console.log('updated after repository refresh'); // Token is not available, so authors are still queried from git assert.deepEqual(store.getUsers(), gitAuthors); - console.log('about to fire login update'); await login.setToken('https://api.github.com', '1234'); await nextUpdatePromise(store); - console.log('updated after login update'); assert.deepEqual(store.getUsers(), graphqlAuthors); }); }); From 6bf5413b9c6ad48c4340f260ee670ba7f9aff4de Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 May 2018 14:39:38 -0400 Subject: [PATCH 0033/4847] Override results when the Repository has changed --- lib/models/user-store.js | 7 ++++++- test/models/user-store.test.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index df3abf61c2..45b2b50030 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -26,6 +26,7 @@ export default class UserStore { this.last = { source: source.PENDING, + repository: null, }; this.repositoryObserver = new ModelObserver({ @@ -126,7 +127,10 @@ export default class UserStore { } addUsers(users, nextSource) { - if (nextSource !== this.last.source) { + if ( + nextSource !== this.last.source || + this.repositoryObserver.getActiveModel() !== this.last.repository + ) { this.allUsers.clear(); } @@ -142,6 +146,7 @@ export default class UserStore { this.finalize(); } this.last.source = nextSource; + this.last.repository = this.repositoryObserver.getActiveModel(); } finalize() { diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index a516377bd2..41ad2de45f 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -345,4 +345,38 @@ describe('UserStore', function() { await nextUpdatePromise(store); assert.deepEqual(store.getUsers(), graphqlAuthors); }); + + it('refetches users when the repository changes', async function() { + const workdirPath0 = await cloneRepository('multiple-commits'); + const repository0 = await buildRepository(workdirPath0); + await repository0.setConfig('user.email', 'committer0@github.com'); + await repository0.setConfig('user.name', 'committer0'); + await repository0.commit('on repo 0', {allowEmpty: true}); + await repository0.setConfig('user.email', 'committer@github.com'); + await repository0.setConfig('user.name', 'committer'); + + const workdirPath1 = await cloneRepository('multiple-commits'); + const repository1 = await buildRepository(workdirPath1); + await repository1.setConfig('user.email', 'committer1@github.com'); + await repository1.setConfig('user.name', 'committer1'); + await repository1.commit('on repo 1', {allowEmpty: true}); + await repository1.setConfig('user.email', 'committer@github.com'); + await repository1.setConfig('user.name', 'committer'); + + const store = new UserStore({repository: repository0}); + await nextUpdatePromise(store); + + assert.deepEqual(store.getUsers(), [ + new Author('kuychaco@github.com', 'Katrina Uychaco'), + new Author('committer0@github.com', 'committer0'), + ]); + + store.setRepository(repository1); + await nextUpdatePromise(store); + + assert.deepEqual(store.getUsers(), [ + new Author('kuychaco@github.com', 'Katrina Uychaco'), + new Author('committer1@github.com', 'committer1'), + ]); + }); }); From 92a2cfad00d48dc28ce71fb95c2ba483399b2413 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 May 2018 15:18:39 -0400 Subject: [PATCH 0034/4847] Pass the GithubLoginModel to the UserStore --- lib/controllers/git-tab-controller.js | 7 ++++++- lib/controllers/root-controller.js | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index e57e06ff70..d773a5cee7 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -15,6 +15,7 @@ export default class GitTabController extends React.Component { static propTypes = { repository: PropTypes.object.isRequired, + loginModel: PropTypes.object.isRequired, lastCommit: CommitPropType.isRequired, recentCommits: PropTypes.arrayOf(CommitPropType).isRequired, @@ -65,7 +66,10 @@ export default class GitTabController extends React.Component { selectedCoAuthors: [], }; - this.userStore = new UserStore({repository: this.props.repository}); + this.userStore = new UserStore({ + repository: this.props.repository, + login: this.props.loginModel, + }); } render() { @@ -131,6 +135,7 @@ export default class GitTabController extends React.Component { componentDidUpdate() { this.userStore.setRepository(this.props.repository); + this.userStore.setLoginModel(this.props.loginModel); this.refreshResolutionProgress(false, false); } diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index ca1e10db50..3e9cde0d52 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -193,6 +193,7 @@ export default class RootController extends React.Component { confirm={this.props.confirm} config={this.props.config} repository={this.props.repository} + loginModel={this.loginModel} initializeRepo={this.initializeRepo} resolutionProgress={this.props.resolutionProgress} ensureGitTab={this.gitTabTracker.ensureVisible} From 79b10a1dc4ad495d1c3ec047baab2c9b16b24162 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 May 2018 15:18:54 -0400 Subject: [PATCH 0035/4847] Declare query variables --- lib/models/user-store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index 45b2b50030..cbd0e54c21 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -88,7 +88,7 @@ export default class UserStore { const response = await fetchQuery({ name: 'GetMentionableUsers', text: ` - query GetMentionableUsers { + query GetMentionableUsers($owner: String!, $name: String!, $first: Int!, $after: String) { repository(owner: $owner, name: $name) { mentionableUsers(first: $first, after: $after) { nodes { From 4f8906a14a9bb1b3c421a89f3ce5ddbc4e3efb18 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 May 2018 15:19:16 -0400 Subject: [PATCH 0036/4847] Change the loginModel --- lib/models/user-store.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index cbd0e54c21..0bc9a594c3 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -167,6 +167,11 @@ export default class UserStore { this.repositoryObserver.setActiveModel(repository); } + setLoginModel(login) { + this.loginObserver.setActiveModel(login); + console.log('setLoginModel login model:', login); + } + setCommitter(committer) { const changed = !this.committer.matches(committer); this.committer = committer; From 06c073a654e713ebc3fc8a93e631b6ee4a297d18 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 May 2018 14:08:59 -0400 Subject: [PATCH 0037/4847] Create and test for new Authors --- lib/models/author.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/models/author.js b/lib/models/author.js index f2f6f32660..4a699ecd82 100644 --- a/lib/models/author.js +++ b/lib/models/author.js @@ -1,10 +1,17 @@ +const NEW = Symbol('new'); + export const NO_REPLY_GITHUB_EMAIL = 'noreply@github.com'; export default class Author { - constructor(email, fullName, login = null) { + constructor(email, fullName, login = null, isNew = null) { this.email = email; this.fullName = fullName; this.login = login; + this.new = isNew === NEW; + } + + static createNew(email, fullName) { + return new this(email, fullName, null, NEW); } getEmail() { @@ -27,6 +34,10 @@ export default class Author { return this.login !== null; } + isNew() { + return this.new; + } + isPresent() { return true; } @@ -71,6 +82,10 @@ export const nullAuthor = { return false; }, + isNew() { + return false; + }, + isPresent() { return false; }, From 423f25807671b97c9d7682cd2f4fa4288a036cc6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 May 2018 14:09:14 -0400 Subject: [PATCH 0038/4847] Create Author instances in CoAuthorForm --- lib/views/co-author-form.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/views/co-author-form.js b/lib/views/co-author-form.js index a4aa6b0bbf..23d5f9f1ba 100644 --- a/lib/views/co-author-form.js +++ b/lib/views/co-author-form.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; +import Author from '../models/author'; import Commands, {Command} from '../atom/commands'; import {autobind} from '../helpers'; @@ -75,7 +76,7 @@ export default class CoAuthorForm extends React.Component { confirm() { if (this.isInputValid()) { - this.props.onSubmit({name: this.state.name, email: this.state.email}); + this.props.onSubmit(new Author(this.state.email, this.state.name)); } } From 137f61ab6a447358760a6b4ab5aec48c47ad4c64 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 May 2018 14:09:30 -0400 Subject: [PATCH 0039/4847] Use Author models in the CommitView co-author forms --- lib/views/commit-view.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/views/commit-view.js b/lib/views/commit-view.js index 9c79af933f..40b9b9ca07 100644 --- a/lib/views/commit-view.js +++ b/lib/views/commit-view.js @@ -8,6 +8,7 @@ import Tooltip from '../atom/tooltip'; import AtomTextEditor from '../atom/atom-text-editor'; import CoAuthorForm from './co-author-form'; import RefHolder from '../models/ref-holder'; +import Author from '../models/author'; import ObserveModel from './observe-model'; import {LINE_ENDING_REGEX, autobind} from '../helpers'; import {AuthorPropType, UserStorePropType} from '../prop-types'; @@ -260,7 +261,7 @@ export default class CommitView extends React.Component { placeholder="Co-Authors" arrowRenderer={null} options={mentionableUsers} - labelKey="name" + labelKey="fullName" valueKey="email" filterOptions={this.matchAuthors} optionRenderer={this.renderCoAuthorListItem} @@ -468,11 +469,12 @@ export default class CommitView extends React.Component { matchAuthors(authors, filterText, selectedAuthors) { const matchedAuthors = authors.filter((author, index) => { - const isAlreadySelected = selectedAuthors && selectedAuthors.find(selected => selected.email === author.email); - const matchesFilter = `${author.name}${author.email}`.toLowerCase().indexOf(filterText.toLowerCase()) !== -1; + const isAlreadySelected = selectedAuthors && selectedAuthors.find(selected => selected.matches(author)); + const matchesFilter = `${author.getFullName()}${author.getEmail()}`.toLowerCase() + .indexOf(filterText.toLowerCase()) !== -1; return !isAlreadySelected && matchesFilter; }); - matchedAuthors.push({name: filterText, email: 'Add new author', isNew: true}); + matchedAuthors.push(Author.createNew('Add new author', filterText)); return matchedAuthors; } @@ -488,24 +490,24 @@ export default class CommitView extends React.Component { renderCoAuthorListItem(author) { return ( -
- {this.renderCoAuthorListItemField('name', author.name)} - {this.renderCoAuthorListItemField('email', author.email)} +
+ {this.renderCoAuthorListItemField('name', author.getFullName())} + {this.renderCoAuthorListItemField('email', author.getEmail())}
); } renderCoAuthorValue(author) { return ( - {author.name} + {author.getFullName()} ); } onSelectedCoAuthorsChanged(selectedCoAuthors) { - const newAuthor = selectedCoAuthors.find(author => author.isNew); + const newAuthor = selectedCoAuthors.find(author => author.isNew()); if (newAuthor) { - this.setState({coAuthorInput: newAuthor.name, showCoAuthorForm: true}); + this.setState({coAuthorInput: newAuthor.getFullName(), showCoAuthorForm: true}); } else { this.props.updateSelectedCoAuthors(selectedCoAuthors); } From 90394fcdd5d4453d3251e2746f93267cda373ae6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 May 2018 14:25:18 -0400 Subject: [PATCH 0040/4847] Update CoAuthor form test --- test/views/co-author-form.test.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/views/co-author-form.test.js b/test/views/co-author-form.test.js index cc1167f82f..b2980682ce 100644 --- a/test/views/co-author-form.test.js +++ b/test/views/co-author-form.test.js @@ -2,6 +2,7 @@ import React from 'react'; import {mount} from 'enzyme'; import CoAuthorForm from '../../lib/views/co-author-form'; +import Author from '../../lib/models/author'; describe('CoAuthorForm', function() { let atomEnv; @@ -50,10 +51,7 @@ describe('CoAuthorForm', function() { wrapper.find('.btn-primary').simulate('click'); - assert.deepEqual(didSubmit.firstCall.args[0], { - name, - email, - }); + assert.deepEqual(didSubmit.firstCall.args[0], new Author(email, name)); }); it('submit button is initially disabled', function() { From 25c3edd64f55a93ad30076da8061cfae9ba1302f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 May 2018 14:37:24 -0400 Subject: [PATCH 0041/4847] :fire: console.log again --- lib/models/user-store.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index 0bc9a594c3..291c9dc861 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -169,7 +169,6 @@ export default class UserStore { setLoginModel(login) { this.loginObserver.setActiveModel(login); - console.log('setLoginModel login model:', login); } setCommitter(committer) { From db7e78f01e7f044d8021dee41cc75444d6ad470e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 May 2018 14:58:40 -0400 Subject: [PATCH 0042/4847] Create a helper for stubbing paginated data --- test/models/user-store.test.js | 144 +++++++++++++-------------------- 1 file changed, 56 insertions(+), 88 deletions(-) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 41ad2de45f..4a7d2d5f04 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -19,6 +19,38 @@ describe('UserStore', function() { }); } + function expectPagedRelayQueries(options, ...pages) { + const opts = { + owner: 'me', + name: 'stuff', + ...options, + }; + + let lastCursor = null; + return pages.map((page, index) => { + const isLast = index === pages.length - 1; + const nextCursor = isLast ? null : `page-${index + 1}`; + + const {resolve} = expectRelayQuery({ + name: 'GetMentionableUsers', + variables: {owner: opts.owner, name: opts.name, first: 100, after: lastCursor}, + }, { + repository: { + mentionableUsers: { + nodes: page, + pageInfo: { + hasNextPage: !isLast, + endCursor: nextCursor, + }, + }, + }, + }); + + lastCursor = nextCursor; + return resolve; + }); + } + beforeEach(function() { login = new GithubLoginModel(InMemoryStrategy); }); @@ -50,24 +82,11 @@ describe('UserStore', function() { await repository.setConfig('remote.old.url', 'git@sourceforge.com:me/stuff.git'); await repository.setConfig('remote.old.fetch', '+refs/heads/*:refs/remotes/old/*'); - const {resolve} = expectRelayQuery({ - name: 'GetMentionableUsers', - variables: {owner: 'me', name: 'stuff', first: 100, after: null}, - }, { - repository: { - mentionableUsers: { - nodes: [ - {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, - {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, - {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, - ], - pageInfo: { - hasNextPage: false, - endCursor: null, - }, - }, - }, - }); + const [resolve] = expectPagedRelayQueries({}, [ + {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, + {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, + {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, + ]); const store = new UserStore({repository, login}); await nextUpdatePromise(store); @@ -91,42 +110,17 @@ describe('UserStore', function() { await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); - const {resolve: resolve0} = expectRelayQuery({ - name: 'GetMentionableUsers', - variables: {owner: 'me', name: 'stuff', first: 100, after: null}, - }, { - repository: { - mentionableUsers: { - nodes: [ - {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, - {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, - {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, - ], - pageInfo: { - hasNextPage: true, - endCursor: 'foo', - }, - }, - }, - }); - - const {resolve: resolve1} = expectRelayQuery({ - name: 'GetMentionableUsers', - variables: {owner: 'me', name: 'stuff', first: 100, after: 'foo'}, - }, { - repository: { - mentionableUsers: { - nodes: [ - {login: 'zzz', email: 'zzz@github.com', name: 'Zzzzz'}, - {login: 'aaa', email: 'aaa@github.com', name: 'Aahhhhh'}, - ], - pageInfo: { - hasNextPage: false, - endCursor: 'bar', - }, - }, - }, - }); + const [resolve0, resolve1] = expectPagedRelayQueries({}, + [ + {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, + {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, + {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, + ], + [ + {login: 'zzz', email: 'zzz@github.com', name: 'Zzzzz'}, + {login: 'aaa', email: 'aaa@github.com', name: 'Aahhhhh'}, + ], + ); const store = new UserStore({repository, login}); @@ -163,22 +157,9 @@ describe('UserStore', function() { await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); - const {resolve} = expectRelayQuery({ - name: 'GetMentionableUsers', - variables: {owner: 'me', name: 'stuff', first: 100, after: null}, - }, { - repository: { - mentionableUsers: { - nodes: [ - {login: 'simurai', email: '', name: 'simurai'}, - ], - pageInfo: { - hasNextPage: false, - endCursor: null, - }, - }, - }, - }); + const [resolve] = expectPagedRelayQueries({}, [ + {login: 'simurai', email: '', name: 'simurai'}, + ]); const store = new UserStore({repository, login}); await nextUpdatePromise(store); @@ -307,24 +288,11 @@ describe('UserStore', function() { new Author('annthurium@github.com', 'Tilde Ann Thurium', 'annthurium'), ]; - const {resolve} = expectRelayQuery({ - name: 'GetMentionableUsers', - variables: {owner: 'me', name: 'stuff', first: 100, after: null}, - }, { - repository: { - mentionableUsers: { - nodes: [ - {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, - {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, - {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, - ], - pageInfo: { - hasNextPage: false, - endCursor: null, - }, - }, - }, - }); + const [resolve] = expectPagedRelayQueries({}, [ + {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, + {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, + {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, + ]); resolve(); const store = new UserStore({repository, login}); From 0d3b316f97ff63e2eddfad7532e8bfa1c7c29114 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 May 2018 16:27:31 -0400 Subject: [PATCH 0043/4847] getSlug() on Remote because "slug" is more fun than "nwo" --- lib/models/remote.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/models/remote.js b/lib/models/remote.js index e272d62767..d7002a3f13 100644 --- a/lib/models/remote.js +++ b/lib/models/remote.js @@ -33,6 +33,10 @@ export default class Remote { return this.getName(); } + getSlug() { + return `${this.owner}/${this.repo}`; + } + isPresent() { return true; } @@ -90,6 +94,10 @@ export const nullRemote = { return fallback; }, + getSlug() { + return ''; + }, + isPresent() { return false; }, From 25095cacbc25f44074c3660bf1807545c168a661 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 May 2018 16:27:55 -0400 Subject: [PATCH 0044/4847] Disable stubbed GraphQL queries --- lib/relay-network-layer-manager.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index cf1a821b79..390d01ba85 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -26,7 +26,9 @@ export function expectRelayQuery(operationPattern, response) { existing.push({promise, response, variables: operationPattern.variables || {}}); responsesByQuery.set(operationPattern.name, existing); - return {promise, resolve, reject}; + const disable = () => responsesByQuery.delete(operationPattern.name); + + return {promise, resolve, reject, disable}; } export function clearRelayExpectations() { From d687e7b7df50396601cd9fbf935ce492a29f6f93 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 May 2018 16:28:22 -0400 Subject: [PATCH 0045/4847] Cache GraphQL responses for an hour --- lib/models/user-store.js | 44 ++++++++++++++-- test/models/user-store.test.js | 95 +++++++++++++++++++++++++++++++--- 2 files changed, 130 insertions(+), 9 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index 291c9dc861..ca8cdb302e 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -15,6 +15,33 @@ export const source = { GITHUBAPI: Symbol('github API'), }; +class GraphQLCache { + // One hour + static MAX_AGE_MS = 3.6e6 + + constructor() { + this.bySlug = new Map(); + } + + get(remote) { + const slug = remote.getSlug(); + const {ts, data} = this.bySlug.get(slug) || { + ts: -Infinity, + data: {}, + }; + + if (Date.now() - ts > this.constructor.MAX_AGE_MS) { + this.bySlug.delete(slug); + return null; + } + return data; + } + + set(remote, data) { + this.bySlug.set(remote.getSlug(), {ts: Date.now(), data}); + } +} + export default class UserStore { constructor({repository, login}) { this.emitter = new Emitter(); @@ -28,6 +55,7 @@ export default class UserStore { source: source.PENDING, repository: null, }; + this.cache = new GraphQLCache(); this.repositoryObserver = new ModelObserver({ fetchData: r => yubikiri({ @@ -69,6 +97,12 @@ export default class UserStore { } async loadMentionableUsers(remote) { + const cached = this.cache.get(remote); + if (cached !== null) { + this.addUsers(cached, source.GITHUBAPI); + return; + } + const loginModel = this.loginObserver.getActiveModel(); if (!loginModel) { return; @@ -83,6 +117,7 @@ export default class UserStore { let hasMore = true; let cursor = null; + const remoteUsers = []; while (hasMore) { const response = await fetchQuery({ @@ -112,18 +147,21 @@ export default class UserStore { }); const connection = response.data.repository.mentionableUsers; - - this.addUsers(connection.nodes.map(node => { + const authors = connection.nodes.map(node => { if (node.email === '') { node.email = `${node.login}@users.noreply.github.com`; } return new Author(node.email, node.name, node.login); - }), source.GITHUBAPI); + }); + this.addUsers(authors, source.GITHUBAPI); + remoteUsers.push(...authors); cursor = connection.pageInfo.endCursor; hasMore = connection.pageInfo.hasNextPage; } + + this.cache.set(remote, remoteUsers); } addUsers(users, nextSource) { diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 4a7d2d5f04..a8f9e8e476 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -31,7 +31,7 @@ describe('UserStore', function() { const isLast = index === pages.length - 1; const nextCursor = isLast ? null : `page-${index + 1}`; - const {resolve} = expectRelayQuery({ + const result = expectRelayQuery({ name: 'GetMentionableUsers', variables: {owner: opts.owner, name: opts.name, first: 100, after: lastCursor}, }, { @@ -47,7 +47,7 @@ describe('UserStore', function() { }); lastCursor = nextCursor; - return resolve; + return result; }); } @@ -82,7 +82,7 @@ describe('UserStore', function() { await repository.setConfig('remote.old.url', 'git@sourceforge.com:me/stuff.git'); await repository.setConfig('remote.old.fetch', '+refs/heads/*:refs/remotes/old/*'); - const [resolve] = expectPagedRelayQueries({}, [ + const [{resolve}] = expectPagedRelayQueries({}, [ {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, @@ -110,7 +110,7 @@ describe('UserStore', function() { await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); - const [resolve0, resolve1] = expectPagedRelayQueries({}, + const [{resolve: resolve0}, {resolve: resolve1}] = expectPagedRelayQueries({}, [ {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, @@ -157,7 +157,7 @@ describe('UserStore', function() { await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); - const [resolve] = expectPagedRelayQueries({}, [ + const [{resolve}] = expectPagedRelayQueries({}, [ {login: 'simurai', email: '', name: 'simurai'}, ]); @@ -288,7 +288,7 @@ describe('UserStore', function() { new Author('annthurium@github.com', 'Tilde Ann Thurium', 'annthurium'), ]; - const [resolve] = expectPagedRelayQueries({}, [ + const [{resolve}] = expectPagedRelayQueries({}, [ {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, @@ -347,4 +347,87 @@ describe('UserStore', function() { new Author('committer1@github.com', 'committer1'), ]); }); + + describe('GraphQL response caching', function() { + it('caches mentionable users acquired from GraphQL', async function() { + await login.setToken('https://api.github.com', '1234'); + + const workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + + await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); + await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); + + const [{resolve, disable}] = expectPagedRelayQueries({}, [ + {login: 'annthurium', email: 'annthurium@github.com', name: 'Tilde Ann Thurium'}, + {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, + {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, + ]); + resolve(); + + const store = new UserStore({repository, login}); + sinon.spy(store, 'loadUsers'); + + // The first update is triggered by the commiter, the second from GraphQL results arriving. + await nextUpdatePromise(store); + await nextUpdatePromise(store); + + disable(); + + repository.refresh(); + + await assert.async.strictEqual(store.loadUsers.callCount, 2); + await store.loadUsers.returnValues[1]; + + assert.deepEqual(store.getUsers(), [ + new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), + new Author('mona@lisa.com', 'Mona Lisa', 'octocat'), + new Author('annthurium@github.com', 'Tilde Ann Thurium', 'annthurium'), + ]); + }); + + it('re-uses cached users per repository', async function() { + await login.setToken('https://api.github.com', '1234'); + + const workdirPath0 = await cloneRepository('multiple-commits'); + const repository0 = await buildRepository(workdirPath0); + await repository0.setConfig('remote.origin.url', 'git@github.com:me/zero.git'); + await repository0.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); + + const workdirPath1 = await cloneRepository('multiple-commits'); + const repository1 = await buildRepository(workdirPath1); + await repository1.setConfig('remote.origin.url', 'git@github.com:me/one.git'); + await repository1.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); + + const results = id => [ + {login: 'aaa', email: `aaa-${id}@a.com`, name: 'AAA'}, + {login: 'bbb', email: `bbb-${id}@b.com`, name: 'BBB'}, + {login: 'ccc', email: `ccc-${id}@c.com`, name: 'CCC'}, + ]; + const [{resolve: resolve0, disable: disable0}] = expectPagedRelayQueries({name: 'zero'}, results('0')); + const [{resolve: resolve1, disable: disable1}] = expectPagedRelayQueries({name: 'one'}, results('1')); + resolve0(); + resolve1(); + + const store = new UserStore({repository: repository0, login}); + await nextUpdatePromise(store); + await nextUpdatePromise(store); + + store.setRepository(repository1); + await nextUpdatePromise(store); + + sinon.spy(store, 'loadUsers'); + disable0(); + disable1(); + + store.setRepository(repository0); + await nextUpdatePromise(store); + + assert.deepEqual(store.getUsers(), [ + new Author('aaa-0@a.com', 'AAA', 'aaa'), + new Author('bbb-0@b.com', 'BBB', 'bbb'), + new Author('ccc-0@c.com', 'CCC', 'ccc'), + ]); + }); + }); }); From 3d8073f06e81ad9dfc0050e15730ecfe387c3c89 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 09:51:12 -0400 Subject: [PATCH 0046/4847] Check a token's OAuth scopes against the required ones on each getToken --- lib/models/github-login-model.js | 52 ++++++++++++++++++++++++-- lib/shared/keytar-strategy.js | 3 ++ test/models/github-login-model.test.js | 39 ++++++++++++++++++- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/lib/models/github-login-model.js b/lib/models/github-login-model.js index 7da9bc6e72..3934e3f8a6 100644 --- a/lib/models/github-login-model.js +++ b/lib/models/github-login-model.js @@ -1,10 +1,15 @@ +import crypto from 'crypto'; import {Emitter} from 'event-kit'; -import {UNAUTHENTICATED, createStrategy} from '../shared/keytar-strategy'; +import {UNAUTHENTICATED, INSUFFICIENT, createStrategy} from '../shared/keytar-strategy'; let instance = null; export default class GithubLoginModel { + // Be sure that we're requesting at least this many scopes on the token we grant through github.atom.io or we'll + // give everyone a really frustrating experience ;-) + static REQUIRED_SCOPES = ['repo', 'user:email'] + static get() { if (!instance) { instance = new GithubLoginModel(); @@ -16,6 +21,7 @@ export default class GithubLoginModel { this._Strategy = Strategy; this._strategy = null; this.emitter = new Emitter(); + this.checked = new Set(); } async getStrategy() { @@ -34,11 +40,34 @@ export default class GithubLoginModel { async getToken(account) { const strategy = await this.getStrategy(); - let password = await strategy.getPassword('atom-github', account); + const password = await strategy.getPassword('atom-github', account); if (!password) { // User is not logged in - password = UNAUTHENTICATED; + return UNAUTHENTICATED; } + + if (/^https?:/.test(account)) { + // Avoid storing tokens in memory longer than necessary. Let's cache token scope checks by storing a set of + // checksums instead. + const hash = crypto.createHash('md5'); + hash.update(password); + const fingerprint = hash.digest('base64'); + + if (!this.checked.has(fingerprint)) { + const scopes = new Set(await this.getScopes(account, password)); + + for (const scope of this.constructor.REQUIRED_SCOPES) { + if (!scopes.has(scope)) { + // Token doesn't have enough OAuth scopes, need to reauthenticate + return INSUFFICIENT; + } + } + + // We're good + this.checked.add(fingerprint); + } + } + return password; } @@ -54,6 +83,23 @@ export default class GithubLoginModel { this.didUpdate(); } + async getScopes(host, token) { + if (atom.inSpecMode()) { + throw new Error('Attempt to check token scopes in specs'); + } + + const response = await fetch(host, { + method: 'HEAD', + headers: {Authorization: `bearer ${token}`}, + }); + + if (response.status !== 200) { + throw new Error(`Unable to check token for OAuth scopes against ${host}: ${await response.text()}`); + } + + return response.headers.get('X-OAuth-Scopes').split(/\s*,\s*/); + } + didUpdate() { this.emitter.emit('did-update'); } diff --git a/lib/shared/keytar-strategy.js b/lib/shared/keytar-strategy.js index b68f71b0ce..86dcea24e2 100644 --- a/lib/shared/keytar-strategy.js +++ b/lib/shared/keytar-strategy.js @@ -18,6 +18,8 @@ if (typeof atom === 'undefined') { const UNAUTHENTICATED = Symbol('UNAUTHENTICATED'); +const INSUFFICIENT = Symbol('INSUFFICIENT'); + class KeytarStrategy { static get keytar() { return require('keytar'); @@ -245,6 +247,7 @@ async function createStrategy() { module.exports = { UNAUTHENTICATED, + INSUFFICIENT, KeytarStrategy, SecurityBinaryStrategy, InMemoryStrategy, diff --git a/test/models/github-login-model.test.js b/test/models/github-login-model.test.js index 0a3e03da85..2925e76e3e 100644 --- a/test/models/github-login-model.test.js +++ b/test/models/github-login-model.test.js @@ -1,5 +1,11 @@ import GithubLoginModel from '../../lib/models/github-login-model'; -import {KeytarStrategy, SecurityBinaryStrategy, InMemoryStrategy, UNAUTHENTICATED} from '../../lib/shared/keytar-strategy'; +import { + KeytarStrategy, + SecurityBinaryStrategy, + InMemoryStrategy, + UNAUTHENTICATED, + INSUFFICIENT, +} from '../../lib/shared/keytar-strategy'; describe('GithubLoginModel', function() { [null, KeytarStrategy, SecurityBinaryStrategy, InMemoryStrategy].forEach(function(Strategy) { @@ -23,4 +29,35 @@ describe('GithubLoginModel', function() { }); }); }); + + describe('required OAuth scopes', function() { + let loginModel; + + beforeEach(async function() { + loginModel = new GithubLoginModel(InMemoryStrategy); + await loginModel.setToken('https://api.github.com', '1234'); + }); + + it('returns INSUFFICIENT if scopes are present', async function() { + sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo'])); + + assert.strictEqual(await loginModel.getToken('https://api.github.com'), INSUFFICIENT); + }); + + it('returns the token if at least the required scopes are present', async function() { + sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'user:email', 'extra'])); + + assert.strictEqual(await loginModel.getToken('https://api.github.com'), '1234'); + }); + + it('caches checked tokens', async function() { + sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'user:email'])); + + assert.strictEqual(await loginModel.getToken('https://api.github.com'), '1234'); + assert.strictEqual(loginModel.getScopes.callCount, 1); + + assert.strictEqual(await loginModel.getToken('https://api.github.com'), '1234'); + assert.strictEqual(loginModel.getScopes.callCount, 1); + }); + }); }); From 875540ba40a8f7ba73c158303dbcc00475f4a1b6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 09:52:31 -0400 Subject: [PATCH 0047/4847] Handle an INSUFFICIENT result in UserStore --- lib/models/user-store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index ca8cdb302e..057d5ebda4 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -3,7 +3,7 @@ import {Emitter} from 'event-kit'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; import Author, {nullAuthor} from './author'; -import {UNAUTHENTICATED} from '../shared/keytar-strategy'; +import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; import ModelObserver from './model-observer'; // This is a guess about what a reasonable value is. Can adjust if performance is poor. @@ -109,7 +109,7 @@ export default class UserStore { } const token = await loginModel.getToken('https://api.github.com'); - if (token === UNAUTHENTICATED) { + if (token === UNAUTHENTICATED || token === INSUFFICIENT) { return; } From b5c49c635185fb5f2aa203faf94c63c4f5a58724 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 09:54:10 -0400 Subject: [PATCH 0048/4847] Stub getScopes in UserStore tests --- test/models/user-store.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index a8f9e8e476..241f7b0273 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -53,6 +53,7 @@ describe('UserStore', function() { beforeEach(function() { login = new GithubLoginModel(InMemoryStrategy); + sinon.stub(login, 'getScopes').returns(Promise.resolve(GithubLoginModel.REQUIRED_SCOPES)); }); it('loads store with local git users and committer in a repo with no GitHub remote', async function() { From 29e8590d2868f4fe96a79256f93f4c85ba2afb71 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 13:02:40 -0400 Subject: [PATCH 0049/4847] Log GraphQL expected variables in spec mode --- lib/relay-network-layer-manager.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index 390d01ba85..69e3e5cb68 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -1,3 +1,4 @@ +import util from 'util'; import {Environment, Network, RecordSource, Store} from 'relay-runtime'; import moment from 'moment'; @@ -58,7 +59,10 @@ function createFetchQuery(url) { if (!match) { // eslint-disable-next-line no-console - console.log(`GraphQL query ${operation.name} was:\n ${operation.text.replace(/\n/g, '\n ')}`); + console.log( + `GraphQL query ${operation.name} was:\n ${operation.text.replace(/\n/g, '\n ')}\n` + + util.inspect(variables), + ); const e = new Error(`Unexpected GraphQL query: ${operation.name}`); e.rawStack = e.stack; From 6faf54e52c8a01671f8ba7e5099e2c2175aba721 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 13:15:42 -0400 Subject: [PATCH 0050/4847] Handle errors during the getScopes() request --- lib/models/github-login-model.js | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/models/github-login-model.js b/lib/models/github-login-model.js index 3934e3f8a6..1c149235ae 100644 --- a/lib/models/github-login-model.js +++ b/lib/models/github-login-model.js @@ -46,7 +46,7 @@ export default class GithubLoginModel { return UNAUTHENTICATED; } - if (/^https?:/.test(account)) { + if (/^https?:\/\//.test(account)) { // Avoid storing tokens in memory longer than necessary. Let's cache token scope checks by storing a set of // checksums instead. const hash = crypto.createHash('md5'); @@ -54,17 +54,24 @@ export default class GithubLoginModel { const fingerprint = hash.digest('base64'); if (!this.checked.has(fingerprint)) { - const scopes = new Set(await this.getScopes(account, password)); - - for (const scope of this.constructor.REQUIRED_SCOPES) { - if (!scopes.has(scope)) { - // Token doesn't have enough OAuth scopes, need to reauthenticate - return INSUFFICIENT; + try { + const scopes = new Set(await this.getScopes(account, password)); + + for (const scope of this.constructor.REQUIRED_SCOPES) { + if (!scopes.has(scope)) { + // Token doesn't have enough OAuth scopes, need to reauthenticate + return INSUFFICIENT; + } } - } - // We're good - this.checked.add(fingerprint); + // We're good + this.checked.add(fingerprint); + } catch (e) { + // Bad credential most likely + // eslint-disable-next-line no-console + console.error(`Unable to validate token scopes against ${account}`, e); + return UNAUTHENTICATED; + } } } From 744c2674e8c30617d5a9154c0e60d91504c1629e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 13:17:21 -0400 Subject: [PATCH 0051/4847] Handle the "insufficient scopes" case in RemotePrController --- lib/controllers/remote-pr-controller.js | 52 ++++++----- lib/views/loading-view.js | 11 +++ test/controllers/remote-pr-controller.test.js | 91 +++++++++++++++++++ 3 files changed, 131 insertions(+), 23 deletions(-) create mode 100644 lib/views/loading-view.js create mode 100644 test/controllers/remote-pr-controller.test.js diff --git a/lib/controllers/remote-pr-controller.js b/lib/controllers/remote-pr-controller.js index 5c10783454..3e9a7c2a4a 100644 --- a/lib/controllers/remote-pr-controller.js +++ b/lib/controllers/remote-pr-controller.js @@ -4,9 +4,10 @@ import yubikiri from 'yubikiri'; import {shell} from 'electron'; import {RemotePropType, BranchSetPropType} from '../prop-types'; +import LoadingView from '../views/loading-view'; import GithubLoginView from '../views/github-login-view'; import ObserveModel from '../views/observe-model'; -import {UNAUTHENTICATED} from '../shared/keytar-strategy'; +import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; import {nullRemote} from '../models/remote'; import PrInfoController from './pr-info-controller'; import {autobind} from '../helpers'; @@ -49,29 +50,34 @@ export default class RemotePrController extends React.Component { ); } - renderWithData(loginData) { - const { - host, remote, branches, loginModel, selectedPrUrl, - aheadCount, pushInProgress, onSelectPr, onUnpinPr, - } = this.props; - const token = loginData.token; + renderWithData({token}) { + let inner; + if (token === null) { + inner = ; + } else if (token === UNAUTHENTICATED) { + inner = ; + } else if (token === INSUFFICIENT) { + inner = ; + } else { + const { + host, remote, branches, loginModel, selectedPrUrl, + aheadCount, pushInProgress, onSelectPr, onUnpinPr, + } = this.props; - return ( -
- {token && token !== UNAUTHENTICATED && - - } - {(!token || token === UNAUTHENTICATED) && } -
- ); + inner = ( + + ); + } + + return
{inner}
; } handleLogin(token) { diff --git a/lib/views/loading-view.js b/lib/views/loading-view.js new file mode 100644 index 0000000000..847496adb3 --- /dev/null +++ b/lib/views/loading-view.js @@ -0,0 +1,11 @@ +import React from 'react'; + +export default class LoadingView extends React.Component { + render() { + return ( +
+ +
+ ); + } +} diff --git a/test/controllers/remote-pr-controller.test.js b/test/controllers/remote-pr-controller.test.js new file mode 100644 index 0000000000..1be18cade4 --- /dev/null +++ b/test/controllers/remote-pr-controller.test.js @@ -0,0 +1,91 @@ +import React from 'react'; +import {mount} from 'enzyme'; + +import GithubLoginModel from '../../lib/models/github-login-model'; +import BranchSet from '../../lib/models/branch-set'; +import Remote from '../../lib/models/remote'; +import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; +import {InMemoryStrategy, UNAUTHENTICATED, INSUFFICIENT} from '../../lib/shared/keytar-strategy'; +import RemotePrController from '../../lib/controllers/remote-pr-controller'; + +describe('RemotePrController', function() { + let loginModel, remote, branchSet; + + beforeEach(function() { + loginModel = new GithubLoginModel(InMemoryStrategy); + sinon.stub(loginModel, 'getToken').returns(Promise.resolve('1234')); + + remote = new Remote('origin', 'git@github.com:atom/github'); + branchSet = new BranchSet(); + + expectRelayQuery({ + name: 'prInfoControllerByBranchQuery', + variables: {repoOwner: 'atom', repoName: 'github', branchName: ''}, + }, { + repository: { + defaultBranchRef: { + prefix: 'refs/heads', + name: 'master', + }, + pullRequests: { + totalCount: 0, + edges: [], + }, + id: '1', + }, + }); + }); + + function createApp(props = {}) { + const noop = () => {}; + + return ( + + ); + } + + it('renders a loading message while fetching the token', function() { + const wrapper = mount(createApp()); + assert.isTrue(wrapper.find('LoadingView').exists()); + }); + + it('shows the login view if unauthenticated', async function() { + loginModel.getToken.restore(); + sinon.stub(loginModel, 'getToken').returns(Promise.resolve(UNAUTHENTICATED)); + + const wrapper = mount(createApp()); + + await assert.async.isTrue(wrapper.update().find('GithubLoginView').exists()); + assert.isFalse(wrapper.find('GithubLoginView').prop('scopeExpansion')); + }); + + it('shows the login view if more scopes are required', async function() { + loginModel.getToken.restore(); + sinon.stub(loginModel, 'getToken').returns(Promise.resolve(INSUFFICIENT)); + + const wrapper = mount(createApp()); + + await assert.async.isTrue(wrapper.update().find('GithubLoginView').exists()); + assert.isTrue(wrapper.find('GithubLoginView').prop('scopeExpansion')); + }); + + it('renders pull request info if authenticated', async function() { + const wrapper = mount(createApp()); + + await assert.async.isTrue(wrapper.update().find('PrInfoController').exists()); + + const controller = wrapper.update().find('PrInfoController'); + assert.strictEqual(controller.prop('remote'), remote); + assert.strictEqual(controller.prop('branches'), branchSet); + assert.strictEqual(controller.prop('loginModel'), loginModel); + }); +}); From 7c24b6bbc05039de115151fb1a380edc0180e427 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 13:28:09 -0400 Subject: [PATCH 0052/4847] Oh GithubLoginView already lets you customize a message --- lib/controllers/remote-pr-controller.js | 10 ++++++++-- test/controllers/remote-pr-controller.test.js | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/controllers/remote-pr-controller.js b/lib/controllers/remote-pr-controller.js index 3e9a7c2a4a..19100aef4d 100644 --- a/lib/controllers/remote-pr-controller.js +++ b/lib/controllers/remote-pr-controller.js @@ -55,9 +55,15 @@ export default class RemotePrController extends React.Component { if (token === null) { inner = ; } else if (token === UNAUTHENTICATED) { - inner = ; + inner = ; } else if (token === INSUFFICIENT) { - inner = ; + inner = ( + +

+ Your token no longer has sufficient authorizations. Please re-authenticate and generate a new one. +

+
+ ); } else { const { host, remote, branches, loginModel, selectedPrUrl, diff --git a/test/controllers/remote-pr-controller.test.js b/test/controllers/remote-pr-controller.test.js index 1be18cade4..7a9e3a4462 100644 --- a/test/controllers/remote-pr-controller.test.js +++ b/test/controllers/remote-pr-controller.test.js @@ -65,7 +65,10 @@ describe('RemotePrController', function() { const wrapper = mount(createApp()); await assert.async.isTrue(wrapper.update().find('GithubLoginView').exists()); - assert.isFalse(wrapper.find('GithubLoginView').prop('scopeExpansion')); + assert.strictEqual( + wrapper.find('GithubLoginView').find('p').text(), + 'Log in to GitHub to access PR information and more!', + ); }); it('shows the login view if more scopes are required', async function() { @@ -75,7 +78,10 @@ describe('RemotePrController', function() { const wrapper = mount(createApp()); await assert.async.isTrue(wrapper.update().find('GithubLoginView').exists()); - assert.isTrue(wrapper.find('GithubLoginView').prop('scopeExpansion')); + assert.strictEqual( + wrapper.find('GithubLoginView').find('p').text(), + 'Your token no longer has sufficient authorizations. Please re-authenticate and generate a new one.', + ); }); it('renders pull request info if authenticated', async function() { From dbf5ac99f47f60300ebbcf6050ec1c86fbabd4c4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 13:34:38 -0400 Subject: [PATCH 0053/4847] Report GraphQL errors from non-200 responses --- lib/relay-network-layer-manager.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index 69e3e5cb68..10409ac9c9 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -73,10 +73,10 @@ function createFetchQuery(url) { }; } - return function fetchQuery(operation, variables, cacheConfig, uploadables) { + return async function fetchQuery(operation, variables, cacheConfig, uploadables) { const currentToken = tokenPerURL.get(url); - return fetch(url, { + const response = await fetch(url, { method: 'POST', headers: { 'content-type': 'application/json', @@ -87,13 +87,20 @@ function createFetchQuery(url) { query: operation.text, variables, }), - }).then(response => { - try { - atom && atom.inDevMode() && logRatelimitApi(response.headers); - } catch (_e) { /* do nothing */ } - - return response.json(); }); + + try { + atom && atom.inDevMode() && logRatelimitApi(response.headers); + } catch (_e) { /* do nothing */ } + + if (response.status !== 200) { + const e = new Error(`GraphQL API endpoint at ${url} returned ${response.status}`); + e.response = response; + e.rawStack = e.stack; + throw e; + } + + return response.json(); }; } From 930e89ffe72a5058adec7f804c60cd9519411dfb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 13:47:20 -0400 Subject: [PATCH 0054/4847] Don't lose the token on every launch :eyes: --- lib/relay-network-layer-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index 10409ac9c9..cd0c6c4982 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -113,7 +113,7 @@ export default class RelayNetworkLayerManager { if (!environment) { const source = new RecordSource(); const store = new Store(source); - network = Network.create(this.getFetchQuery(url)); + network = Network.create(this.getFetchQuery(url, token)); environment = new Environment({network, store}); relayEnvironmentPerGithubHost.set(host, {environment, network}); From e7523020cf67a38de2dd87ff243c503dd2b6f9f3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 13:47:30 -0400 Subject: [PATCH 0055/4847] Autocomplete on login --- lib/views/commit-view.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/views/commit-view.js b/lib/views/commit-view.js index 40b9b9ca07..053cd00d7c 100644 --- a/lib/views/commit-view.js +++ b/lib/views/commit-view.js @@ -470,8 +470,12 @@ export default class CommitView extends React.Component { matchAuthors(authors, filterText, selectedAuthors) { const matchedAuthors = authors.filter((author, index) => { const isAlreadySelected = selectedAuthors && selectedAuthors.find(selected => selected.matches(author)); - const matchesFilter = `${author.getFullName()}${author.getEmail()}`.toLowerCase() - .indexOf(filterText.toLowerCase()) !== -1; + const matchesFilter = [ + author.getLogin(), + author.getFullName(), + author.getEmail(), + ].some(field => field && field.toLowerCase().indexOf(filterText.toLowerCase()) !== -1); + return !isAlreadySelected && matchesFilter; }); matchedAuthors.push(Author.createNew('Add new author', filterText)); From cbf56abf15cef18a5e1cf186ff74e07692990847 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 13:55:12 -0400 Subject: [PATCH 0056/4847] Render a handle if we have one --- lib/views/commit-view.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/views/commit-view.js b/lib/views/commit-view.js index 053cd00d7c..141b063e27 100644 --- a/lib/views/commit-view.js +++ b/lib/views/commit-view.js @@ -496,15 +496,22 @@ export default class CommitView extends React.Component { return (
{this.renderCoAuthorListItemField('name', author.getFullName())} + {author.hasLogin() && this.renderCoAuthorListItemField('login', '@' + author.getLogin())} {this.renderCoAuthorListItemField('email', author.getEmail())}
); } renderCoAuthorValue(author) { - return ( - {author.getFullName()} - ); + const fullName = author.getFullName(); + if (fullName && fullName.length > 0) { + return {author.getFullName()}; + } + if (author.hasLogin()) { + return @{author.getLogin()}; + } + + return {author.getEmail()}; } onSelectedCoAuthorsChanged(selectedCoAuthors) { From 1948962788105f5ae0c1f222acbc71232a31e853 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 25 May 2018 14:00:18 -0400 Subject: [PATCH 0057/4847] Our tokens have read:org --- lib/models/github-login-model.js | 2 +- test/models/github-login-model.test.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/models/github-login-model.js b/lib/models/github-login-model.js index 1c149235ae..f37352a7f7 100644 --- a/lib/models/github-login-model.js +++ b/lib/models/github-login-model.js @@ -8,7 +8,7 @@ let instance = null; export default class GithubLoginModel { // Be sure that we're requesting at least this many scopes on the token we grant through github.atom.io or we'll // give everyone a really frustrating experience ;-) - static REQUIRED_SCOPES = ['repo', 'user:email'] + static REQUIRED_SCOPES = ['repo', 'read:org', 'user:email'] static get() { if (!instance) { diff --git a/test/models/github-login-model.test.js b/test/models/github-login-model.test.js index 2925e76e3e..9dd2ed41b8 100644 --- a/test/models/github-login-model.test.js +++ b/test/models/github-login-model.test.js @@ -39,19 +39,19 @@ describe('GithubLoginModel', function() { }); it('returns INSUFFICIENT if scopes are present', async function() { - sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo'])); + sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'read:org'])); assert.strictEqual(await loginModel.getToken('https://api.github.com'), INSUFFICIENT); }); it('returns the token if at least the required scopes are present', async function() { - sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'user:email', 'extra'])); + sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'read:org', 'user:email', 'extra'])); assert.strictEqual(await loginModel.getToken('https://api.github.com'), '1234'); }); it('caches checked tokens', async function() { - sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'user:email'])); + sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'read:org', 'user:email'])); assert.strictEqual(await loginModel.getToken('https://api.github.com'), '1234'); assert.strictEqual(loginModel.getScopes.callCount, 1); From 7a644237331618491e449e93ef87ab0214a9acbb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 29 May 2018 10:06:00 -0400 Subject: [PATCH 0058/4847] Never open panes if the StagingView does not have focus --- lib/views/staging-view.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/views/staging-view.js b/lib/views/staging-view.js index 11d9760665..0409f73dad 100644 --- a/lib/views/staging-view.js +++ b/lib/views/staging-view.js @@ -630,6 +630,10 @@ export default class StagingView extends React.Component { } async didSelectSingleItem(selectedItem, openNew = false) { + if (!this.hasFocus()) { + return; + } + if (this.state.selection.getActiveListKey() === 'conflicts') { if (openNew) { await this.showMergeConflictFileForPath(selectedItem.filePath, {activate: true}); @@ -812,4 +816,8 @@ export default class StagingView extends React.Component { return false; } + + hasFocus() { + return this.refRoot.contains(document.activeElement); + } } From 42ca1853370f4d978faac1f984a1e65b9df47b73 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 29 May 2018 10:06:10 -0400 Subject: [PATCH 0059/4847] Stub focus detection during tests --- test/views/staging-view.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/views/staging-view.test.js b/test/views/staging-view.test.js index ed0745aaf6..b266b7e785 100644 --- a/test/views/staging-view.test.js +++ b/test/views/staging-view.test.js @@ -331,6 +331,7 @@ describe('StagingView', function() { const wrapper = mount(React.cloneElement(app, { unstagedChanges: filePatches, })); + sinon.stub(wrapper.instance(), 'hasFocus').returns(true); const getPanesWithStalePendingFilePatchItem = sinon.stub( wrapper.instance(), @@ -401,6 +402,7 @@ describe('StagingView', function() { const wrapper = mount(React.cloneElement(app, { unstagedChanges: filePatches, })); + sinon.stub(wrapper.instance(), 'hasFocus').returns(true); const getPanesWithStalePendingFilePatchItem = sinon.stub( wrapper.instance(), @@ -482,6 +484,7 @@ describe('StagingView', function() { const wrapper = mount(React.cloneElement(app, { unstagedChanges: filePatches, })); + sinon.stub(wrapper.instance(), 'hasFocus').returns(true); let selectedItems = wrapper.instance().getSelectedItems(); assert.lengthOf(selectedItems, 1); @@ -501,6 +504,7 @@ describe('StagingView', function() { const wrapper = mount(React.cloneElement(app, { unstagedChanges: [{filePath: 'a.txt', status: 'modified'}], })); + sinon.stub(wrapper.instance(), 'hasFocus').returns(true); sinon.stub(wrapper.instance(), 'getPanesWithStalePendingFilePatchItem').returns(['item1']); wrapper.setProps({unstagedChanges: []}); // when repo is changed, lists are cleared out and data is fetched for new repo From 1ba6e5391ab0570c45078dd79e95ec8346875f31 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 29 May 2018 13:39:05 -0400 Subject: [PATCH 0060/4847] Prepare 0.15.2 release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c945151630..29802d7ca0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "github", "main": "./lib/index", - "version": "0.15.1", + "version": "0.15.2", "description": "GitHub integration", "repository": "https://github.com/atom/github", "license": "MIT", From f9f6ac7ab37719d80e43634e4bc052f369f7f328 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 29 May 2018 15:56:44 -0400 Subject: [PATCH 0061/4847] Pass UNAUTHENTICATED results through GithubLoginModel --- lib/models/github-login-model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/github-login-model.js b/lib/models/github-login-model.js index f37352a7f7..b9f6fe75c3 100644 --- a/lib/models/github-login-model.js +++ b/lib/models/github-login-model.js @@ -41,7 +41,7 @@ export default class GithubLoginModel { async getToken(account) { const strategy = await this.getStrategy(); const password = await strategy.getPassword('atom-github', account); - if (!password) { + if (!password || password === UNAUTHENTICATED) { // User is not logged in return UNAUTHENTICATED; } From 240c754fc09d56a7a79e86495b807d324bc147dd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 29 May 2018 15:57:38 -0400 Subject: [PATCH 0062/4847] Respect an excludedUsers config setting --- lib/models/user-store.js | 30 +++++- test/models/user-store.test.js | 192 ++++++++++++++++++++++++--------- 2 files changed, 167 insertions(+), 55 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index 057d5ebda4..e09da74add 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -1,5 +1,5 @@ import yubikiri from 'yubikiri'; -import {Emitter} from 'event-kit'; +import {Emitter, CompositeDisposable} from 'event-kit'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; import Author, {nullAuthor} from './author'; @@ -43,17 +43,20 @@ class GraphQLCache { } export default class UserStore { - constructor({repository, login}) { + constructor({repository, login, config}) { this.emitter = new Emitter(); + this.subs = new CompositeDisposable(); // TODO: [ku 3/2018] Consider using Dexie (indexDB wrapper) like Desktop and persist users across sessions this.allUsers = new Map(); + this.excludedUsers = new Set(); this.users = []; this.committer = nullAuthor; this.last = { source: source.PENDING, repository: null, + excludedUsers: this.excludedUsers, }; this.cache = new GraphQLCache(); @@ -71,6 +74,20 @@ export default class UserStore { didUpdate: () => this.loadUsers(), }); this.loginObserver.setActiveModel(login); + + this.subs.add( + config.observe('github.excludedUsers', value => { + this.excludedUsers = new Set( + (value || '').split(/\s*,\s*/).filter(each => each.length > 0), + ); + return this.loadUsers(); + }), + ); + } + + dispose() { + this.subs.dispose(); + this.emitter.dispose(); } async loadUsers() { @@ -165,14 +182,17 @@ export default class UserStore { } addUsers(users, nextSource) { + let changed = false; + if ( nextSource !== this.last.source || - this.repositoryObserver.getActiveModel() !== this.last.repository + this.repositoryObserver.getActiveModel() !== this.last.repository || + this.excludedUsers !== this.last.excludedUsers ) { + changed = true; this.allUsers.clear(); } - let changed = false; for (const author of users) { if (!this.allUsers.has(author.getEmail())) { changed = true; @@ -185,6 +205,7 @@ export default class UserStore { } this.last.source = nextSource; this.last.repository = this.repositoryObserver.getActiveModel(); + this.last.excludedUsers = this.excludedUsers; } finalize() { @@ -193,6 +214,7 @@ export default class UserStore { for (const author of this.allUsers.values()) { if (author.matches(this.committer)) { continue; } if (author.isNoReply()) { continue; } + if (this.excludedUsers.has(author.getEmail())) { continue; } users.push(author); } diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 241f7b0273..10ef5c993c 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -8,9 +8,24 @@ import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import {cloneRepository, buildRepository, FAKE_USER} from '../helpers'; describe('UserStore', function() { - let login; + let login, atomEnv, config, store; - function nextUpdatePromise(store) { + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + config = atomEnv.config; + + login = new GithubLoginModel(InMemoryStrategy); + sinon.stub(login, 'getScopes').returns(Promise.resolve(GithubLoginModel.REQUIRED_SCOPES)); + }); + + afterEach(function() { + if (store) { + store.dispose(); + } + atomEnv.destroy(); + }); + + function nextUpdatePromise() { return new Promise(resolve => { const sub = store.onDidUpdate(() => { sub.dispose(); @@ -51,21 +66,30 @@ describe('UserStore', function() { }); } - beforeEach(function() { - login = new GithubLoginModel(InMemoryStrategy); - sinon.stub(login, 'getScopes').returns(Promise.resolve(GithubLoginModel.REQUIRED_SCOPES)); - }); + async function commitAs(repository, ...accounts) { + const committerName = await repository.getConfig('user.name'); + const committerEmail = await repository.getConfig('user.email'); + + for (const {name, email} of accounts) { + await repository.setConfig('user.name', name); + await repository.setConfig('user.email', email); + await repository.commit('message', {allowEmpty: true}); + } + + await repository.setConfig('user.name', committerName); + await repository.setConfig('user.email', committerEmail); + } it('loads store with local git users and committer in a repo with no GitHub remote', async function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); - const store = new UserStore({repository}); + store = new UserStore({repository, config}); assert.deepEqual(store.getUsers(), []); assert.strictEqual(store.committer, nullAuthor); // Store is populated asynchronously - await nextUpdatePromise(store); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), [ new Author('kuychaco@github.com', 'Katrina Uychaco'), ]); @@ -89,11 +113,11 @@ describe('UserStore', function() { {login: 'smashwilson', email: 'smashwilson@github.com', name: 'Ash Wilson'}, ]); - const store = new UserStore({repository, login}); - await nextUpdatePromise(store); + store = new UserStore({repository, login, config}); + await nextUpdatePromise(); resolve(); - await nextUpdatePromise(store); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), [ new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), @@ -123,13 +147,13 @@ describe('UserStore', function() { ], ); - const store = new UserStore({repository, login}); + store = new UserStore({repository, login, config}); - await nextUpdatePromise(store); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), []); resolve0(); - await nextUpdatePromise(store); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), [ new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), @@ -138,7 +162,7 @@ describe('UserStore', function() { ]); resolve1(); - await nextUpdatePromise(store); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), [ new Author('aaa@github.com', 'Aahhhhh', 'aaa'), @@ -162,11 +186,11 @@ describe('UserStore', function() { {login: 'simurai', email: '', name: 'simurai'}, ]); - const store = new UserStore({repository, login}); - await nextUpdatePromise(store); + store = new UserStore({repository, login, config}); + await nextUpdatePromise(); resolve(); - await nextUpdatePromise(store); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), [ new Author('simurai@users.noreply.github.com', 'simurai', 'simurai'), @@ -176,7 +200,7 @@ describe('UserStore', function() { it('excludes committer and no reply user from `getUsers`', async function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); - const store = new UserStore({repository}); + store = new UserStore({repository, config}); await assert.async.lengthOf(store.getUsers(), 1); sinon.spy(store, 'addUsers'); @@ -200,8 +224,8 @@ describe('UserStore', function() { it('adds specified users and does not overwrite existing users', async function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); - const store = new UserStore({repository}); - await nextUpdatePromise(store); + store = new UserStore({repository, config}); + await nextUpdatePromise(); assert.lengthOf(store.getUsers(), 1); @@ -222,8 +246,8 @@ describe('UserStore', function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); - const store = new UserStore({repository}); - await nextUpdatePromise(store); + store = new UserStore({repository, config}); + await nextUpdatePromise(); assert.deepEqual(store.committer, new Author(FAKE_USER.email, FAKE_USER.name)); const newEmail = 'foo@bar.com'; @@ -232,7 +256,7 @@ describe('UserStore', function() { await repository.setConfig('user.email', newEmail); await repository.setConfig('user.name', newName); repository.refresh(); - await nextUpdatePromise(store); + await nextUpdatePromise(); assert.deepEqual(store.committer, new Author(newEmail, newName)); }); @@ -245,8 +269,8 @@ describe('UserStore', function() { await repository.commit('commit 2', {allowEmpty: true}); await repository.checkout('master'); - const store = new UserStore({repository}); - await nextUpdatePromise(store); + store = new UserStore({repository, config}); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), [ new Author('kuychaco@github.com', 'Katrina Uychaco'), ]); @@ -261,7 +285,7 @@ describe('UserStore', function() { `, {allowEmpty: true}); repository.refresh(); - await nextUpdatePromise(store); + await nextUpdatePromise(); await assert.strictEqual(store.addUsers.callCount, 1); assert.isTrue(store.getUsers().some(user => { @@ -296,8 +320,8 @@ describe('UserStore', function() { ]); resolve(); - const store = new UserStore({repository, login}); - await nextUpdatePromise(store); + store = new UserStore({repository, login, config}); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), gitAuthors); @@ -311,29 +335,21 @@ describe('UserStore', function() { await login.setToken('https://api.github.com', '1234'); - await nextUpdatePromise(store); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), graphqlAuthors); }); it('refetches users when the repository changes', async function() { const workdirPath0 = await cloneRepository('multiple-commits'); const repository0 = await buildRepository(workdirPath0); - await repository0.setConfig('user.email', 'committer0@github.com'); - await repository0.setConfig('user.name', 'committer0'); - await repository0.commit('on repo 0', {allowEmpty: true}); - await repository0.setConfig('user.email', 'committer@github.com'); - await repository0.setConfig('user.name', 'committer'); + await commitAs(repository0, {name: 'committer0', email: 'committer0@github.com'}); const workdirPath1 = await cloneRepository('multiple-commits'); const repository1 = await buildRepository(workdirPath1); - await repository1.setConfig('user.email', 'committer1@github.com'); - await repository1.setConfig('user.name', 'committer1'); - await repository1.commit('on repo 1', {allowEmpty: true}); - await repository1.setConfig('user.email', 'committer@github.com'); - await repository1.setConfig('user.name', 'committer'); + await commitAs(repository1, {name: 'committer1', email: 'committer1@github.com'}); - const store = new UserStore({repository: repository0}); - await nextUpdatePromise(store); + store = new UserStore({repository: repository0, config}); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), [ new Author('kuychaco@github.com', 'Katrina Uychaco'), @@ -341,7 +357,7 @@ describe('UserStore', function() { ]); store.setRepository(repository1); - await nextUpdatePromise(store); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), [ new Author('kuychaco@github.com', 'Katrina Uychaco'), @@ -366,12 +382,12 @@ describe('UserStore', function() { ]); resolve(); - const store = new UserStore({repository, login}); + store = new UserStore({repository, login, config}); sinon.spy(store, 'loadUsers'); // The first update is triggered by the commiter, the second from GraphQL results arriving. - await nextUpdatePromise(store); - await nextUpdatePromise(store); + await nextUpdatePromise(); + await nextUpdatePromise(); disable(); @@ -410,19 +426,19 @@ describe('UserStore', function() { resolve0(); resolve1(); - const store = new UserStore({repository: repository0, login}); - await nextUpdatePromise(store); - await nextUpdatePromise(store); + store = new UserStore({repository: repository0, login, config}); + await nextUpdatePromise(); + await nextUpdatePromise(); store.setRepository(repository1); - await nextUpdatePromise(store); + await nextUpdatePromise(); sinon.spy(store, 'loadUsers'); disable0(); disable1(); store.setRepository(repository0); - await nextUpdatePromise(store); + await nextUpdatePromise(); assert.deepEqual(store.getUsers(), [ new Author('aaa-0@a.com', 'AAA', 'aaa'), @@ -431,4 +447,78 @@ describe('UserStore', function() { ]); }); }); + + describe('excluded users', function() { + it('do not appear in the list from git', async function() { + config.set('github.excludedUsers', 'evil@evilcorp.org'); + + const workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + await commitAs(repository, + {name: 'evil0', email: 'evil@evilcorp.org'}, + {name: 'ok', email: 'ok@somewhere.net'}, + {name: 'evil1', email: 'evil@evilcorp.org'}, + ); + + store = new UserStore({repository, config}); + await nextUpdatePromise(); + + assert.deepEqual(store.getUsers(), [ + new Author('kuychaco@github.com', 'Katrina Uychaco'), + new Author('ok@somewhere.net', 'ok'), + ]); + }); + + it('do not appear in the list from GraphQL', async function() { + config.set('github.excludedUsers', 'evil@evilcorp.org, other@evilcorp.org'); + await login.setToken('https://api.github.com', '1234'); + + const workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); + await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); + + const [{resolve}] = expectPagedRelayQueries({}, [ + {login: 'evil0', email: 'evil@evilcorp.org', name: 'evil0'}, + {login: 'octocat', email: 'mona@lisa.com', name: 'Mona Lisa'}, + ]); + resolve(); + + store = new UserStore({repository, login, config}); + await nextUpdatePromise(); + await nextUpdatePromise(); + + assert.deepEqual(store.getUsers(), [ + new Author('mona@lisa.com', 'Mona Lisa', 'octocat'), + ]); + }); + + it('are updated when the config option changes', async function() { + config.set('github.excludedUsers', 'evil0@evilcorp.org'); + + const workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + await commitAs(repository, + {name: 'evil0', email: 'evil0@evilcorp.org'}, + {name: 'ok', email: 'ok@somewhere.net'}, + {name: 'evil1', email: 'evil1@evilcorp.org'}, + ); + + store = new UserStore({repository, config}); + await nextUpdatePromise(); + + assert.deepEqual(store.getUsers(), [ + new Author('kuychaco@github.com', 'Katrina Uychaco'), + new Author('evil1@evilcorp.org', 'evil1'), + new Author('ok@somewhere.net', 'ok'), + ]); + + config.set('github.excludedUsers', 'evil0@evilcorp.org, evil1@evilcorp.org'); + + assert.deepEqual(store.getUsers(), [ + new Author('kuychaco@github.com', 'Katrina Uychaco'), + new Author('ok@somewhere.net', 'ok'), + ]); + }); + }); }); From f2610c4b7f41c68fc99dd22a2216e501c1ef4938 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 29 May 2018 15:58:50 -0400 Subject: [PATCH 0063/4847] Include schema for excludedUsers --- package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/package.json b/package.json index c945151630..ed556aeb3f 100644 --- a/package.json +++ b/package.json @@ -150,6 +150,11 @@ "type": "boolean", "default": true, "description": "Resolve merge conflicts with in-editor controls" + }, + "excludedUsers": { + "type": "string", + "default": "", + "description": "Comma-separated list of email addresses to exclude from the co-author selection list" } }, "deserializers": { From b4073bd38958edefa91c5177f6f7a4a5a1de1337 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 30 May 2018 12:42:21 +1000 Subject: [PATCH 0064/4847] bump dugite to 2.17.1 for security fix --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29802d7ca0..bbc41482e3 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "babel-preset-react": "6.24.1", "classnames": "2.2.5", "compare-sets": "1.0.1", - "dugite": "1.64.0", + "dugite": "1.65.0", "event-kit": "2.5.0", "fs-extra": "4.0.3", "graphql": "0.13.2", From c11673d4289b3dd514d1ae316661cce6a3754479 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 30 May 2018 12:44:09 +1000 Subject: [PATCH 0065/4847] bump lockfile --- package-lock.json | 299 +++++++++++++--------------------------------- 1 file changed, 83 insertions(+), 216 deletions(-) diff --git a/package-lock.json b/package-lock.json index b7dc89e2ae..d971686c73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "github", - "version": "0.14.0-1", + "version": "0.15.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -251,7 +251,7 @@ }, "@sinonjs/formatio": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", "dev": true, "requires": { @@ -2021,6 +2021,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, "requires": { "hoek": "4.x.x" } @@ -2457,6 +2458,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, "requires": { "boom": "5.x.x" }, @@ -2465,6 +2467,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", "integrity": "sha1-XdnabuOl8wIHdDYpDLcX0/SlTgI=", + "dev": true, "requires": { "hoek": "4.x.x" } @@ -2771,26 +2774,16 @@ } }, "dugite": { - "version": "1.63.0", - "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.63.0.tgz", - "integrity": "sha1-bDkVYp1wBoJ30pzS6mFl4L1+HwU=", + "version": "1.65.0", + "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.65.0.tgz", + "integrity": "sha512-wswBIq3ygTt+2O44y+PXQwo1W/fFQmIuOxfmGyUrVTwDsmZkXxS4JqVSyoWn3XPll5WP8q1jPR9eGFDZiY8khw==", "requires": { "checksum": "^0.1.1", "mkdirp": "^0.5.1", "progress": "^2.0.0", - "request": "^2.85.0", + "request": "^2.86.0", "rimraf": "^2.5.4", "tar": "^4.0.2" - }, - "dependencies": { - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "requires": { - "glob": "^7.0.5" - } - } } }, "ecc-jsbn": { @@ -2803,26 +2796,15 @@ } }, "electron-devtools-installer": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-2.2.3.tgz", - "integrity": "sha1-WLmk7FBzd7xG4JHNQ3FBiODDab4=", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-2.2.4.tgz", + "integrity": "sha512-b5kcM3hmUqn64+RUcHjjr8ZMpHS2WJ5YO0pnG9+P/RTdx46of/JrEjuciHWux6pE+On6ynWhHJF53j/EDJN0PA==", "dev": true, "requires": { "7zip": "0.0.6", "cross-unzip": "0.0.2", "rimraf": "^2.5.2", "semver": "^5.3.0" - }, - "dependencies": { - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "requires": { - "glob": "^7.0.5" - } - } } }, "encoding": { @@ -3406,9 +3388,9 @@ } }, "event-kit": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.4.0.tgz", - "integrity": "sha1-cYqvIt92ZwAkrWaSJIPhu6BUTzM=" + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.0.tgz", + "integrity": "sha512-tUDxeNC9JzN2Tw/f8mLtksY34v1hHmaR7lV7X4p04XSjaeUhFMfzjF6Nwov9e0EKGEx63BaKcgXKxjpQaPo0wg==" }, "execa": { "version": "0.7.0", @@ -3811,26 +3793,19 @@ "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=" }, "fs-extra": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.0.tgz", - "integrity": "sha1-Dwr7KQuz3rh5eNqBb808d5fzqBc=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - } } }, "fs-minipass": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha1-BsJ3IYRU7CiN93raVKA7hwKqy50=", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "requires": { "minipass": "^2.2.1" } @@ -4097,8 +4072,7 @@ "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, "graceful-readlink": { "version": "1.0.1", @@ -4218,6 +4192,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", "integrity": "sha1-r02RTrBl+bXOTZ0RwcshJu7MMDg=", + "dev": true, "requires": { "boom": "4.x.x", "cryptiles": "3.x.x", @@ -4251,7 +4226,8 @@ "hoek": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha1-ljRQKqEsRF3Vp8VzS1cruHOKrLs=" + "integrity": "sha1-ljRQKqEsRF3Vp8VzS1cruHOKrLs=", + "dev": true }, "home-or-tmp": { "version": "2.0.0", @@ -4860,14 +4836,6 @@ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "requires": { "graceful-fs": "^4.1.6" - }, - "dependencies": { - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "optional": true - } } }, "jsprim": { @@ -5367,11 +5335,19 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" }, "lolex": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz", - "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.0.tgz", + "integrity": "sha512-uJkH2e0BVfU5KOJUevbTOtpDduooSarH5PopO+LfM/vZf8Z9sJzODqKev804JYM2i++ktJfUmC1le4LwFQ1VMg==", "dev": true }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "requires": { + "js-tokens": "^3.0.0" + } + }, "lru-cache": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", @@ -5468,18 +5444,25 @@ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "minipass": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz", - "integrity": "sha1-A8gk2EVR7Dio0btbw1Clowo1SkA=", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz", + "integrity": "sha512-/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw==", "requires": { - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } }, "minizlib": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz", - "integrity": "sha1-EeE2WM5GvDpwomeqxYNZ0eDCnOs=", + "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "requires": { "minipass": "^2.2.1" } @@ -5940,6 +5923,11 @@ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -6457,149 +6445,25 @@ } }, "react": { - "version": "16.3.2", - "resolved": "https://registry.npmjs.org/react/-/react-16.3.2.tgz", - "integrity": "sha1-/chCA5hTOh5Yhy9ZCRsnLOL5Hqk=", + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.4.0.tgz", + "integrity": "sha512-K0UrkLXSAekf5nJu89obKUM7o2vc6MMN9LYoKnCa+c+8MJRAT120xzPLENcWSRc7GYKIg0LlgJRDorrufdglQQ==", "requires": { "fbjs": "^0.8.16", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.0" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" - }, - "fbjs": { - "version": "0.8.16", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", - "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.9" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "requires": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" - } - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "^3.0.0" - } - }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - } } }, "react-dom": { - "version": "16.3.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.3.2.tgz", - "integrity": "sha1-y5DxB+CVNtaD2E7V1IiOlkDg5N8=", + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.0.tgz", + "integrity": "sha512-bbLd+HYpBEnYoNyxDe9XpSG2t9wypMohwQPvKw8Hov3nF7SJiJIgK56b46zHpBUpHb06a1iEuw7G3rbrsnNL6w==", "requires": { "fbjs": "^0.8.16", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.0" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" - }, - "fbjs": { - "version": "0.8.16", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", - "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.9" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "requires": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" - } - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "^3.0.0" - } - }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - } } }, "react-input-autosize": { @@ -7225,9 +7089,9 @@ } }, "request": { - "version": "2.85.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", - "integrity": "sha1-WgNhWkfGFCCz65m326IE+DYD4fo=", + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.6.0", @@ -7237,7 +7101,6 @@ "forever-agent": "~0.6.1", "form-data": "~2.3.1", "har-validator": "~5.0.3", - "hawk": "~6.0.2", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -7247,7 +7110,6 @@ "performance-now": "^2.1.0", "qs": "~6.5.1", "safe-buffer": "^5.1.1", - "stringstream": "~0.0.5", "tough-cookie": "~2.3.3", "tunnel-agent": "^0.6.0", "uuid": "^3.1.0" @@ -7318,6 +7180,14 @@ "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", "dev": true }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "^7.0.5" + } + }, "rst-selector-parser": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", @@ -7468,18 +7338,18 @@ } }, "sinon": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-5.0.6.tgz", - "integrity": "sha512-xn1jBaHFJMAUaYSa7Fr9gHGopcjSo128kQKDaLIUCM3s6x687nqdtjkxhu4IonbBS1qgXf/u17i7sEvwFgQyhg==", + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-5.0.10.tgz", + "integrity": "sha512-+YT7Mjr8BpNndQqUUydO/daggF4yuOAnsVjo+5Ayx3mLLUqojfkXhDkho4HB5VgfnZYSdhxVDPbfJ2EBXFMSvA==", "dev": true, "requires": { "@sinonjs/formatio": "^2.0.0", - "diff": "^3.1.0", + "diff": "^3.5.0", "lodash.get": "^4.4.2", - "lolex": "^2.2.0", - "nise": "^1.2.0", - "supports-color": "^5.1.0", - "type-detect": "^4.0.5" + "lolex": "^2.4.2", + "nise": "^1.3.3", + "supports-color": "^5.4.0", + "type-detect": "^4.0.8" }, "dependencies": { "supports-color": { @@ -7626,6 +7496,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", "integrity": "sha1-LGzsFP7cIiJznK+bXD2F0cxaLMg=", + "dev": true, "requires": { "hoek": "4.x.x" } @@ -7817,7 +7688,8 @@ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "is-fullwidth-code-point": { - "version": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" }, "string-width": { @@ -7847,11 +7719,6 @@ "safe-buffer": "~5.1.0" } }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -7936,13 +7803,13 @@ } }, "tar": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.2.tgz", - "integrity": "sha1-YGhSEbpGs4hHsa5+4aJNdEos1GI=", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.4.tgz", + "integrity": "sha512-mq9ixIYfNF9SK0IS/h2HKMu8Q2iaCuhDDsZhdEag/FHv8fOaYld4vN7ouMgcSSt5WKZzPs8atclTcJm36OTh4w==", "requires": { "chownr": "^1.0.1", "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", + "minipass": "^2.3.3", "minizlib": "^1.1.0", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", From 086ee0a20363ff802cb2c82bf3977621f2dce1bc Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 30 May 2018 07:54:39 -0400 Subject: [PATCH 0066/4847] Pass config to the UserStore initializer --- lib/controllers/git-tab-controller.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index d773a5cee7..ec38e5517d 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -69,6 +69,7 @@ export default class GitTabController extends React.Component { this.userStore = new UserStore({ repository: this.props.repository, login: this.props.loginModel, + config: this.props.config, }); } From 1ec5ed9d5b2387631db8bb004f3cf5028b5bdf93 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 30 May 2018 08:38:20 -0400 Subject: [PATCH 0067/4847] Gracefully handle GraphQL errors in the UserStore --- lib/models/user-store.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index e09da74add..2894c8c53d 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -163,6 +163,15 @@ export default class UserStore { after: cursor, }); + if (response.errors && response.errors.length > 1) { + // eslint-disable-next-line no-console + console.error(`Error fetching mentionable users:\n${response.errors.map(e => e.message).join('\n')}`); + } + + if (!response.data) { + break; + } + const connection = response.data.repository.mentionableUsers; const authors = connection.nodes.map(node => { if (node.email === '') { From a82ce61e0d790ed7a77f0199c225f28f81892240 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 30 May 2018 08:38:37 -0400 Subject: [PATCH 0068/4847] Exclude co-authors on shift-delete --- keymaps/git.cson | 1 + lib/views/commit-view.js | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/keymaps/git.cson b/keymaps/git.cson index af3ff892bf..1f24a4282f 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -70,3 +70,4 @@ 'home': 'github:co-author:home' 'end': 'github:co-author:end' 'delete': 'github:co-author:delete' + 'shift-backspace': 'github:co-author-exclude' diff --git a/lib/views/commit-view.js b/lib/views/commit-view.js index 141b063e27..debdea7442 100644 --- a/lib/views/commit-view.js +++ b/lib/views/commit-view.js @@ -57,7 +57,7 @@ export default class CommitView extends React.Component { this, 'submitNewCoAuthor', 'cancelNewCoAuthor', 'didChangeCommitMessage', 'didMoveCursor', 'toggleHardWrap', 'toggleCoAuthorInput', 'abortMerge', 'commit', 'amendLastCommit', 'toggleExpandedCommitMessageEditor', - 'renderCoAuthorListItem', 'onSelectedCoAuthorsChanged', + 'renderCoAuthorListItem', 'onSelectedCoAuthorsChanged', 'excludeCoAuthor', ); this.state = { @@ -132,6 +132,7 @@ export default class CommitView extends React.Component { 'github:co-author:home': this.proxyKeyCode(36), 'github:co-author:delete': this.proxyKeyCode(46), 'github:co-author:escape': this.proxyKeyCode(27), + 'github:co-author-exclude': this.excludeCoAuthor, }), this.props.config.onDidChange('github.automaticCommitMessageWrapping', () => this.forceUpdate()), ); @@ -386,6 +387,20 @@ export default class CommitView extends React.Component { }); } + excludeCoAuthor() { + const author = this.refCoAuthorSelect.map(c => c.getFocusedOption()); + if (!author || author.isNew()) { + return; + } + + let excluded = this.props.config.get('github.excludedUsers'); + if (excluded && excluded !== '') { + excluded += ', '; + } + excluded += author.getEmail(); + this.props.config.set('github.excludedUsers', excluded); + } + abortMerge() { this.props.abortMerge(); } From dd9647641beb263253c5678b888b7964c5c675cb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 30 May 2018 08:49:20 -0400 Subject: [PATCH 0069/4847] Initialize UserStore correctly in tests --- test/controllers/commit-controller.test.js | 2 +- test/views/commit-view.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/controllers/commit-controller.test.js b/test/controllers/commit-controller.test.js index fa0b7d867a..2988d871e4 100644 --- a/test/controllers/commit-controller.test.js +++ b/test/controllers/commit-controller.test.js @@ -25,7 +25,7 @@ describe('CommitController', function() { lastCommit = new Commit({sha: 'a1e23fd45', message: 'last commit message'}); const noop = () => {}; - const store = new UserStore({}); + const store = new UserStore({config}); app = ( {}; const returnTruthyPromise = () => Promise.resolve(true); - const store = new UserStore({}); + const store = new UserStore({config}); app = ( Date: Wed, 30 May 2018 19:58:51 -0400 Subject: [PATCH 0070/4847] :arrow_up: dugite --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index d971686c73..270ba9928f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1058,7 +1058,7 @@ "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", "dev": true }, "to-fast-properties": { @@ -1313,13 +1313,13 @@ "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=", "dev": true }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", "dev": true }, "to-fast-properties": { @@ -1715,7 +1715,7 @@ "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", "dev": true } } @@ -2774,9 +2774,9 @@ } }, "dugite": { - "version": "1.65.0", - "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.65.0.tgz", - "integrity": "sha512-wswBIq3ygTt+2O44y+PXQwo1W/fFQmIuOxfmGyUrVTwDsmZkXxS4JqVSyoWn3XPll5WP8q1jPR9eGFDZiY8khw==", + "version": "1.66.0", + "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.66.0.tgz", + "integrity": "sha512-H5Dmc5HZIj1RKUCcgNvocSBXjoimWgcAXzwHEHXnQXJTv9ZYaCP/ZD7njmE635ShJ22xXAWz5Xm+tf4Klj181g==", "requires": { "checksum": "^0.1.1", "mkdirp": "^0.5.1", diff --git a/package.json b/package.json index 81f7360a1c..32827f830e 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "babel-preset-react": "6.24.1", "classnames": "2.2.5", "compare-sets": "1.0.1", - "dugite": "1.65.0", + "dugite": "^1.66.0", "event-kit": "2.5.0", "fs-extra": "4.0.3", "graphql": "0.13.2", From 916781ae6db0b431546ee0f6238958b939a7160d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 30 May 2018 20:00:49 -0400 Subject: [PATCH 0071/4847] npm audit fix SMASH --- package-lock.json | 232 ++++++++++++---------------------------------- 1 file changed, 58 insertions(+), 174 deletions(-) diff --git a/package-lock.json b/package-lock.json index 270ba9928f..bfec30fb92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -563,7 +563,6 @@ "requires": { "browser-stdout": "1.3.0", "commander": "2.9.0", - "debug": "2.6.8", "diff": "3.2.0", "escape-string-regexp": "1.0.5", "glob": "7.1.1", @@ -691,9 +690,9 @@ } }, "babel-core": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", - "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", "requires": { "babel-code-frame": "^6.26.0", "babel-generator": "^6.26.0", @@ -705,45 +704,17 @@ "babel-traverse": "^6.26.0", "babel-types": "^6.26.0", "babylon": "^6.18.0", - "convert-source-map": "^1.5.0", - "debug": "^2.6.8", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", "json5": "^0.5.1", "lodash": "^4.17.4", "minimatch": "^3.0.4", "path-is-absolute": "^1.0.1", - "private": "^0.1.7", + "private": "^0.1.8", "slash": "^1.0.0", - "source-map": "^0.5.6" + "source-map": "^0.5.7" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -795,73 +766,12 @@ "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, "to-fast-properties": { "version": "1.0.3", @@ -1139,7 +1049,6 @@ "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true, "requires": { "babel-runtime": "^6.22.0" } @@ -1805,7 +1714,7 @@ "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=" + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" } } }, @@ -2498,19 +2407,12 @@ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } } }, "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { "ms": "2.0.0" } @@ -3375,8 +3277,7 @@ "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, "ev-store": { "version": "7.0.0", @@ -3805,7 +3706,7 @@ "fs-minipass": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "integrity": "sha1-BsJ3IYRU7CiN93raVKA7hwKqy50=", "requires": { "minipass": "^2.2.1" } @@ -3910,13 +3811,6 @@ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } } }, "github-from-package": { @@ -4236,18 +4130,6 @@ "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.1" - }, - "dependencies": { - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - } } }, "hosted-git-info": { @@ -5190,13 +5072,6 @@ "dev": true, "optional": true }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", - "dev": true, - "optional": true - }, "tough-cookie": { "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", "integrity": "sha512-42UXjmzk88F7URyg9wDV/dlQ7hXtl/SDV6xIMVdDq82cnDGQDyg8mI8xGBPOwpEfbhvrja6cJ8H1wr0xxykBKA==", @@ -5438,6 +5313,14 @@ "dom-walk": "^0.1.0" } }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", @@ -5446,7 +5329,7 @@ "minipass": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz", - "integrity": "sha512-/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw==", + "integrity": "sha1-p9zIt7gz9dNodZzOVE3MtV9Q8jM=", "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5462,7 +5345,7 @@ "minizlib": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz", - "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", + "integrity": "sha1-EeE2WM5GvDpwomeqxYNZ0eDCnOs=", "requires": { "minipass": "^2.2.1" } @@ -5611,8 +5494,7 @@ }, "stringstream": { "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "resolved": "", "dev": true } } @@ -5636,9 +5518,9 @@ "dev": true }, "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -5723,12 +5605,6 @@ } } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "supports-color": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", @@ -6094,6 +5970,11 @@ } } }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, "os-locale": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", @@ -6105,6 +5986,11 @@ "mem": "^1.1.0" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -6171,6 +6057,11 @@ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, "path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", @@ -6268,7 +6159,7 @@ "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=" + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" }, "process": { "version": "0.5.2", @@ -7054,7 +6945,7 @@ "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", "dev": true } } @@ -7522,16 +7413,9 @@ "source-map-support": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8=", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "requires": { "source-map": "^0.5.6" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - } } }, "source-map-url": { @@ -7624,9 +7508,9 @@ "dev": true }, "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", + "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -7636,13 +7520,6 @@ "getpass": "^0.1.1", "jsbn": "~0.1.0", "tweetnacl": "~0.14.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } } }, "static-extend": { @@ -7719,6 +7596,13 @@ "safe-buffer": "~5.1.0" } }, + "stringstream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "dev": true, + "optional": true + }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -7805,7 +7689,7 @@ "tar": { "version": "4.4.4", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.4.tgz", - "integrity": "sha512-mq9ixIYfNF9SK0IS/h2HKMu8Q2iaCuhDDsZhdEag/FHv8fOaYld4vN7ouMgcSSt5WKZzPs8atclTcJm36OTh4w==", + "integrity": "sha1-7IQJ+un2ZaQ1XMO0CH0IICMruM0=", "requires": { "chownr": "^1.0.1", "fs-minipass": "^1.2.5", From 61c7fb836f6b18fab875637f758435cd736960f9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 30 May 2018 21:03:06 -0400 Subject: [PATCH 0072/4847] Prepare 0.16.0 release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 32827f830e..e08372b170 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "github", "main": "./lib/index", - "version": "0.15.2", + "version": "0.16.0", "description": "GitHub integration", "repository": "https://github.com/atom/github", "license": "MIT", From f7609a7e0ed455ff28ea108b09fd2402aa198cce Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 09:07:19 -0400 Subject: [PATCH 0073/4847] Create a Promise that resolves when a RefHolder becomes available --- lib/models/ref-holder.js | 13 +++++++++++++ test/models/ref-holder.test.js | 11 +++++++++++ 2 files changed, 24 insertions(+) diff --git a/lib/models/ref-holder.js b/lib/models/ref-holder.js index b90e9fbd21..4c12b9c8b4 100644 --- a/lib/models/ref-holder.js +++ b/lib/models/ref-holder.js @@ -65,6 +65,19 @@ export default class RefHolder { return this.value; } + getPromise() { + if (this.isEmpty()) { + return new Promise(resolve => { + const sub = this.observe(value => { + resolve(value); + sub.dispose(); + }); + }); + } + + return Promise.resolve(this.get()); + } + map(block) { if (!this.isEmpty()) { return block(this.get()); diff --git a/test/models/ref-holder.test.js b/test/models/ref-holder.test.js index 97a62791fd..e7d5a22dc2 100644 --- a/test/models/ref-holder.test.js +++ b/test/models/ref-holder.test.js @@ -52,6 +52,17 @@ describe('RefHolder', function() { assert.isTrue(callback.calledWith(12)); }); + it('resolves a promise when it becomes available', async function() { + const thing = Symbol('Thing'); + const h = new RefHolder(); + + const promise = h.getPromise(); + + h.setter(thing); + assert.strictEqual(await promise, thing); + assert.strictEqual(await h.getPromise(), thing); + }); + describe('.on()', function() { it('returns an existing RefHolder as-is', function() { const original = new RefHolder(); From d5a40ee8381435451db646710274df8bec5226bb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 09:07:35 -0400 Subject: [PATCH 0074/4847] Implement getRealItemPromise() on the item proxy --- lib/helpers.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/helpers.js b/lib/helpers.js index 18bcadbe45..52901c3373 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -353,6 +353,8 @@ export function createItem(node, componentHolder = null, uri = null, extra = {}) getRealItem: () => componentHolder.get(), + getRealItemPromise: () => componentHolder.getPromise(), + ...extra, }; From 44b7be23de04e53d86eca04e62a6fd2d0b7ce809 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 09:08:18 -0400 Subject: [PATCH 0075/4847] Forward declarative method calls from GitTabItem to GitTabController --- lib/controllers/git-tab-controller.js | 9 ++++++- lib/items/git-tab-item.js | 34 ++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index ec38e5517d..5451cfddf2 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -5,7 +5,9 @@ import PropTypes from 'prop-types'; import GitTabView from '../views/git-tab-view'; import UserStore from '../models/user-store'; -import {CommitPropType, BranchPropType, FilePatchItemPropType, MergeConflictItemPropType} from '../prop-types'; +import { + CommitPropType, BranchPropType, FilePatchItemPropType, MergeConflictItemPropType, RefHolderPropType, +} from '../prop-types'; import {autobind} from '../helpers'; export default class GitTabController extends React.Component { @@ -46,6 +48,7 @@ export default class GitTabController extends React.Component { discardWorkDirChangesForPaths: PropTypes.func.isRequired, openFiles: PropTypes.func.isRequired, initializeRepo: PropTypes.func.isRequired, + controllerRef: RefHolderPropType, }; constructor(props, context) { @@ -132,6 +135,10 @@ export default class GitTabController extends React.Component { componentDidMount() { this.refreshResolutionProgress(false, false); this.refView.refRoot.addEventListener('focusin', this.rememberLastFocus); + + if (this.props.controllerRef) { + this.props.controllerRef.setter(this); + } } componentDidUpdate() { diff --git a/lib/items/git-tab-item.js b/lib/items/git-tab-item.js index 144e1b2deb..ad5b775e9c 100644 --- a/lib/items/git-tab-item.js +++ b/lib/items/git-tab-item.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; +import RefHolder from '../models/ref-holder'; import GitTabContainer from '../containers/git-tab-container'; export default class GitTabItem extends React.Component { @@ -8,9 +9,18 @@ export default class GitTabItem extends React.Component { repository: PropTypes.object.isRequired, } + constructor(props) { + super(props); + + this.refController = new RefHolder(); + } + render() { return ( - + ); } @@ -44,4 +54,26 @@ export default class GitTabItem extends React.Component { getWorkingDirectory() { return this.props.repository.getWorkingDirectoryPath(); } + + // Forwarded to the controller instance when one is present + + rememberLastFocus(...args) { + return this.refController.map(c => c.rememberLastFocus(...args)); + } + + restoreFocus(...args) { + return this.refController.map(c => c.restoreFocus(...args)); + } + + hasFocus(...args) { + return this.refController.map(c => c.hasFocus(...args)); + } + + focusAndSelectStagingItem(...args) { + return this.refController.map(c => c.focusAndSelectStagingItem(...args)); + } + + quietlySelectItem(...args) { + return this.refController.map(c => c.quietlySelectItem(...args)); + } } From 0854e577f6c6073646eb78d09335d6b01aed0348 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 09:08:35 -0400 Subject: [PATCH 0076/4847] Rename "gitTabController" to "gitTabItem" because it holds an item now --- lib/controllers/root-controller.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 3e9cde0d52..a10a28980f 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -83,12 +83,12 @@ export default class RootController extends React.Component { credentialDialogQuery: null, }; - this.refGitTabController = new RefHolder(); + this.refGitTabItem = new RefHolder(); this.refGitHubTabController = new RefHolder(); this.gitTabTracker = new TabTracker('git', { uri: 'atom-github://dock-item/git', - getController: () => this.refGitTabController.get(), + getController: () => this.refGitTabItem.get(), getWorkspace: () => this.props.workspace, }); @@ -180,10 +180,10 @@ export default class RootController extends React.Component { workspace={this.props.workspace} onDidCloseItem={this.props.destroyGitTabItem} stubItem={this.props.gitTabStubItem} - itemHolder={this.refGitTabController} + itemHolder={this.refGitTabItem} activate={this.props.startOpen}> { + this.refGitTabItem.map(c => { return c.focusAndSelectStagingItem(filePath, stagingStatus); }); } @@ -482,7 +482,7 @@ export default class RootController extends React.Component { } quietlySelectItem(filePath, stagingStatus) { - return this.refGitTabController.map(c => { + return this.refGitTabItem.map(c => { return c.quietlySelectItem(filePath, stagingStatus); }); } From 8a35a7cb862515f388b1837a6492588a0f2c7eff Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 09:53:17 -0400 Subject: [PATCH 0077/4847] Change .map() to be more map-like --- lib/models/ref-holder.js | 7 ++---- test/models/ref-holder.test.js | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/lib/models/ref-holder.js b/lib/models/ref-holder.js index 4c12b9c8b4..61e24956ae 100644 --- a/lib/models/ref-holder.js +++ b/lib/models/ref-holder.js @@ -78,11 +78,8 @@ export default class RefHolder { return Promise.resolve(this.get()); } - map(block) { - if (!this.isEmpty()) { - return block(this.get()); - } - return null; + map(present, absent = () => this) { + return RefHolder.on(this.isEmpty() ? absent() : present(this.get())); } setter = value => { diff --git a/test/models/ref-holder.test.js b/test/models/ref-holder.test.js index e7d5a22dc2..2ff29bb4e7 100644 --- a/test/models/ref-holder.test.js +++ b/test/models/ref-holder.test.js @@ -26,6 +26,51 @@ describe('RefHolder', function() { assert.strictEqual(h.get(), 1234); }); + describe('map', function() { + it('returns an empty RefHolder as-is', function() { + const h = new RefHolder(); + assert.strictEqual(h.map(() => 14), h); + }); + + it('returns a new RefHolder wrapping the value returned from its present block', function() { + const h = new RefHolder(); + h.setter(12); + assert.strictEqual(h.map(x => x + 1).get(), 13); + }); + + it('returns a RefHolder returned from its present block', function() { + const h0 = new RefHolder(); + h0.setter(14); + + const o = h0.map(() => { + const h1 = new RefHolder(); + h1.setter(12); + return h1; + }); + + assert.notStrictEqual(0, h0); + assert.strictEqual(o.get(), 12); + }); + + it('returns a new RefHolder wrapping the value returned from its absent block', function() { + const h = new RefHolder(); + + const o = h.map(x => 1, () => 2); + assert.strictEqual(o.get(), 2); + }); + + it('returns a RefHolder returned from its absent block', function() { + const h0 = new RefHolder(); + + const o = h0.map(x => 1, () => { + const h1 = new RefHolder(); + h1.setter(1); + return h1; + }); + assert.strictEqual(o.get(), 1); + }); + }); + it('notifies subscribers when it becomes available', function() { const h = new RefHolder(); const callback = sinon.spy(); From 023fda0664f7f779d6ef2180c57b019db69076c2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 11:32:33 -0400 Subject: [PATCH 0078/4847] Update callers of RefHolder.map() that use the return value --- lib/views/commit-view.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/views/commit-view.js b/lib/views/commit-view.js index debdea7442..dc2756426b 100644 --- a/lib/views/commit-view.js +++ b/lib/views/commit-view.js @@ -388,7 +388,7 @@ export default class CommitView extends React.Component { } excludeCoAuthor() { - const author = this.refCoAuthorSelect.map(c => c.getFocusedOption()); + const author = this.refCoAuthorSelect.map(c => c.getFocusedOption()).getOr(null); if (!author || author.isNew()) { return; } @@ -548,15 +548,15 @@ export default class CommitView extends React.Component { return CommitView.focus.EDITOR; } - if (this.refAbortMergeButton.map(e => e.contains(event.target))) { + if (this.refAbortMergeButton.map(e => e.contains(event.target)).getOr(false)) { return CommitView.focus.ABORT_MERGE_BUTTON; } - if (this.refCommitButton.map(e => e.contains(event.target))) { + if (this.refCommitButton.map(e => e.contains(event.target)).getOr(false)) { return CommitView.focus.COMMIT_BUTTON; } - if (this.refCoAuthorSelect.map(c => c.wrapper.contains(event.target))) { + if (this.refCoAuthorSelect.map(c => c.wrapper.contains(event.target)).getOr(false)) { return CommitView.focus.COAUTHOR_INPUT; } From c77a9dc7129a4e056e07908aa6073ae4daaa871b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 12:56:25 -0400 Subject: [PATCH 0079/4847] Split the commit message wrapping test case --- test/controllers/commit-controller.test.js | 71 ++++++++++++---------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/test/controllers/commit-controller.test.js b/test/controllers/commit-controller.test.js index 2988d871e4..bf6e3b7871 100644 --- a/test/controllers/commit-controller.test.js +++ b/test/controllers/commit-controller.test.js @@ -159,44 +159,53 @@ describe('CommitController', function() { }); describe('message formatting', function() { - let commitSpy; + let commitSpy, wrapper; + beforeEach(function() { commitSpy = sinon.stub().returns(Promise.resolve()); app = React.cloneElement(app, {commit: commitSpy}); + wrapper = shallow(app, {disableLifecycleMethods: true}); }); - it('wraps the commit message body at 72 characters if github.automaticCommitMessageWrapping is true', async function() { - config.set('github.automaticCommitMessageWrapping', false); + describe('with automatic wrapping disabled', function() { + beforeEach(function() { + config.set('github.automaticCommitMessageWrapping', false); + }); - const wrapper = shallow(app, {disableLifecycleMethods: true}); + it('passes commit messages through unchanged', async function() { + await wrapper.instance().commit([ + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor', + '', + 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', + ].join('\n')); + + assert.strictEqual(commitSpy.args[0][0], [ + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor', + '', + 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', + ].join('\n')); + }); + }); + + describe('with automatic wrapping enabled', function() { + beforeEach(function() { + config.set('github.automaticCommitMessageWrapping', true); + }); - await wrapper.instance().commit([ - 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor', - '', - 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', - ].join('\n')); - - assert.deepEqual(commitSpy.args[0][0].split('\n'), [ - 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor', - '', - 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', - ]); - - commitSpy.reset(); - config.set('github.automaticCommitMessageWrapping', true); - - await wrapper.instance().commit([ - 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor', - '', - 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', - ].join('\n')); - - assert.deepEqual(commitSpy.args[0][0].split('\n'), [ - 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor', - '', - 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ', - 'ut aliquip ex ea commodo consequat.', - ]); + it('wraps lines within the commit body at 72 characters', async function() { + await wrapper.instance().commit([ + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor', + '', + 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', + ].join('\n')); + + assert.strictEqual(commitSpy.args[0][0], [ + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor', + '', + 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ', + 'ut aliquip ex ea commodo consequat.', + ].join('\n')); + }); }); }); From 915910a655a1fadcc0c440e4940c251a39d9002c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 15:32:33 -0400 Subject: [PATCH 0080/4847] Exploratory test that's totally passing --- test/controllers/commit-controller.test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/controllers/commit-controller.test.js b/test/controllers/commit-controller.test.js index bf6e3b7871..6e450533f9 100644 --- a/test/controllers/commit-controller.test.js +++ b/test/controllers/commit-controller.test.js @@ -206,6 +206,11 @@ describe('CommitController', function() { 'ut aliquip ex ea commodo consequat.', ].join('\n')); }); + + it('preserves existing line wraps within the commit body', async function() { + await wrapper.instance().commit('a\n\nb\n\nc'); + assert.strictEqual(commitSpy.args[0][0], 'a\n\nb\n\nc'); + }); }); }); From 6c37c8ed575c1d5b2d7941d38cc71f9995fe6685 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 15:33:10 -0400 Subject: [PATCH 0081/4847] Test for commit message preservation while amending --- test/git-strategies.test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index dfd69a19da..8c2399fb9a 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -791,6 +791,17 @@ import {normalizeGitHelperPath, getTempDir} from '../lib/helpers'; assert.notDeepEqual(lastCommit, amendedCommit); assert.deepEqual(lastCommitParent, amendedCommitParent); }); + + it('leaves the commit message unchanged', async function() { + const workingDirPath = await cloneRepository('multiple-commits'); + const git = createTestStrategy(workingDirPath); + await git.commit('first\n\nsecond\n\nthird', {allowEmpty: true}); + + await git.commit('', {amend: true, allowEmpty: true}); + const amendedCommit = await git.getHeadCommit(); + assert.strictEqual(amendedCommit.messageSubject, 'first'); + assert.strictEqual(amendedCommit.messageBody, 'second\n\nthird'); + }); }); }); From eb25e67013d63c9231f8a4eb4a1a921b910760d7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 15:33:39 -0400 Subject: [PATCH 0082/4847] Test for reading commit message bodies containing newlines --- test/git-strategies.test.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 8c2399fb9a..8a63117fe6 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -133,6 +133,7 @@ import {normalizeGitHelperPath, getTempDir} from '../lib/helpers'; assert.lengthOf(commits, 1); assert.isTrue(commits[0].unbornRef); }); + it('returns an empty array when the include unborn option is not passed', async function() { const workingDirPath = await initRepository(); const git = createTestStrategy(workingDirPath); @@ -223,6 +224,26 @@ import {normalizeGitHelperPath, getTempDir} from '../lib/helpers'; }, ]); }); + + it('preserves newlines and whitespace in the original commit body', async function() { + const workingDirPath = await cloneRepository('multiple-commits'); + const git = createTestStrategy(workingDirPath); + + await git.commit(dedent` + Implemented feature + + Detailed explanation paragraph 1 + + Detailed explanation paragraph 2 + #123 with an issue reference + `.trim(), {allowEmpty: true}); + + const commits = await git.getCommits({max: 1}); + assert.lengthOf(commits, 1); + assert.strictEqual(commits[0].messageSubject, 'Implemented feature'); + assert.strictEqual(commits[0].messageBody, + 'Detailed explanation paragraph 1\n\nDetailed explanation paragraph 2\n#123 with an issue reference'); + }); }); describe('getAuthors', function() { @@ -751,6 +772,7 @@ import {normalizeGitHelperPath, getTempDir} from '../lib/helpers'; describe('commit(message, options)', function() { describe('formatting commit message', function() { let message; + beforeEach(function() { message = [ ' Make a commit ', @@ -788,6 +810,8 @@ import {normalizeGitHelperPath, getTempDir} from '../lib/helpers'; await git.commit('amend last commit', {amend: true, allowEmpty: true}); const amendedCommit = await git.getHeadCommit(); const amendedCommitParent = await git.getCommit('HEAD~'); + + assert.strictEqual(amendedCommit.messageSubject, 'amend last commit'); assert.notDeepEqual(lastCommit, amendedCommit); assert.deepEqual(lastCommitParent, amendedCommitParent); }); From 79f3600723eba3d48eabb3ef5fc5a0f2489b3f33 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 15:34:21 -0400 Subject: [PATCH 0083/4847] Join raw message lines with \n --- lib/helpers.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/helpers.js b/lib/helpers.js index 52901c3373..c9cc420648 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -332,19 +332,21 @@ export function destroyEmptyFilePatchPaneItems(workspace) { } export function extractCoAuthorsAndRawCommitMessage(commitMessage) { - let rawMessage = ''; - const coAuthors = commitMessage.split(LINE_ENDING_REGEX).reduce((authors, line) => { + const messageLines = []; + const coAuthors = []; + + for (const line of commitMessage.split(LINE_ENDING_REGEX)) { const match = line.match(CO_AUTHOR_REGEX); if (match) { // eslint-disable-next-line no-unused-vars const [_, name, email] = match; - authors.push({name, email}); + coAuthors.push({name, email}); } else { - rawMessage += line; + messageLines.push(line); } - return authors; - }, []); - return {message: rawMessage, coAuthors}; + } + + return {message: messageLines.join('\n'), coAuthors}; } export function createItem(node, componentHolder = null, uri = null, extra = {}) { From c190cec6b9e86544fca4cb90f0a3ef63fd77c01e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 15:35:03 -0400 Subject: [PATCH 0084/4847] Apply --cleanup=verbatim when amending and re-using the message --- lib/git-shell-out-strategy.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 31cb766d1a..a58bc8f906 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -438,14 +438,18 @@ export default class GitShellOutStrategy { } async commit(rawMessage, {allowEmpty, amend, coAuthors} = {}) { - const args = ['commit', '--cleanup=strip']; - + const args = ['commit']; let msg; // if amending and no new message is passed, use last commit's message if (amend && rawMessage.length === 0) { const {unbornRef, messageBody, messageSubject} = await this.getHeadCommit(); - msg = unbornRef ? rawMessage : `${messageSubject}\n\n${messageBody}`.trim(); + if (unbornRef) { + msg = rawMessage; + } else { + msg = `${messageSubject}\n\n${messageBody}`.trim(); + args.push('--cleanup=verbatim'); + } } else { msg = rawMessage; } From 4b79bbab0fadc6641ae3127f7ce94dbc22d7e351 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 15:57:10 -0400 Subject: [PATCH 0085/4847] Infer the --cleanup mode for git commit from config or an option --- lib/git-shell-out-strategy.js | 16 +++++++++++++--- test/git-strategies.test.js | 28 +++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index a58bc8f906..a5f7cb48a2 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -437,23 +437,33 @@ export default class GitShellOutStrategy { return this.exec(args, {stdin: patch, writeOperation: true}); } - async commit(rawMessage, {allowEmpty, amend, coAuthors} = {}) { + async commit(rawMessage, {allowEmpty, amend, coAuthors, verbatim} = {}) { const args = ['commit']; let msg; - // if amending and no new message is passed, use last commit's message + // if amending and no new message is passed, use last commit's message. Ensure that we don't + // mangle it in the process. if (amend && rawMessage.length === 0) { const {unbornRef, messageBody, messageSubject} = await this.getHeadCommit(); if (unbornRef) { msg = rawMessage; } else { msg = `${messageSubject}\n\n${messageBody}`.trim(); - args.push('--cleanup=verbatim'); + verbatim = true; } } else { msg = rawMessage; } + // Determine the cleanup mode. + if (verbatim) { + args.push('--cleanup=verbatim'); + } else { + const configured = await this.getConfig('commit.cleanup'); + const mode = (configured && configured !== 'default') ? configured : 'strip'; + args.push(`--cleanup=${mode}`); + } + // add co-author commit trailers if necessary if (coAuthors && coAuthors.length > 0) { msg = await this.addCoAuthorsToMessage(msg, coAuthors); diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 8a63117fe6..c88c4d116f 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -784,7 +784,7 @@ import {normalizeGitHelperPath, getTempDir} from '../lib/helpers'; '', 'other stuff ', '', - '', + 'and things', '', ].join('\n'); }); @@ -792,12 +792,34 @@ import {normalizeGitHelperPath, getTempDir} from '../lib/helpers'; it('strips out comments and whitespace from message passed', async function() { const workingDirPath = await cloneRepository('multiple-commits'); const git = createTestStrategy(workingDirPath); + await git.setConfig('commit.cleanup', 'default'); await git.commit(message, {allowEmpty: true}); const lastCommit = await git.getHeadCommit(); - assert.deepEqual(lastCommit.messageSubject, 'Make a commit'); - assert.deepEqual(lastCommit.messageBody, 'other stuff'); + assert.strictEqual(lastCommit.messageSubject, 'Make a commit'); + assert.strictEqual(lastCommit.messageBody, 'other stuff\n\nand things'); + }); + + it('passes a message through verbatim', async function() { + const workingDirPath = await cloneRepository('multiple-commits'); + const git = createTestStrategy(workingDirPath); + await git.setConfig('commit.cleanup', 'default'); + + await git.commit(message, {allowEmpty: true, verbatim: true}); + + const lastCommit = await git.getHeadCommit(); + assert.strictEqual(lastCommit.messageSubject, 'Make a commit'); + assert.strictEqual(lastCommit.messageBody, [ + '# Comments:', + '# blah blah blah', + '', + '', + '', + 'other stuff ', + '', + 'and things', + ].join('\n')); }); }); From 3de2cceb376d2e38bc6f0becd0a25dcf3e640011 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 May 2018 16:05:36 -0400 Subject: [PATCH 0086/4847] Pass verbatim to commit() in other test cases --- test/git-strategies.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index c88c4d116f..858c9c08f2 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -236,7 +236,7 @@ import {normalizeGitHelperPath, getTempDir} from '../lib/helpers'; Detailed explanation paragraph 2 #123 with an issue reference - `.trim(), {allowEmpty: true}); + `.trim(), {allowEmpty: true, verbatim: true}); const commits = await git.getCommits({max: 1}); assert.lengthOf(commits, 1); @@ -960,7 +960,7 @@ import {normalizeGitHelperPath, getTempDir} from '../lib/helpers'; command: 'commit', progressiveTense: 'committing', usesPromptServerAlready: false, - action: () => git.commit('message'), + action: () => git.commit('message', {verbatim: true}), }, { command: 'merge', From 581e675a61d6c383e905347f3c4204aa1463a275 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 08:13:25 -0400 Subject: [PATCH 0087/4847] Postprocess the MERGE_MSG to ensure it works with --cleanup=verbatim --- lib/models/repository.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/repository.js b/lib/models/repository.js index b785b55f01..a38dda8e04 100644 --- a/lib/models/repository.js +++ b/lib/models/repository.js @@ -132,7 +132,7 @@ export default class Repository { async getMergeMessage() { try { const contents = await fs.readFile(path.join(this.getGitDirectoryPath(), 'MERGE_MSG'), {encoding: 'utf8'}); - return contents; + return contents.split(/\n/).filter(line => line.length > 0 && !line.startsWith('#')).join('\n'); } catch (e) { return null; } From b95cc7535785b510c3da64c8e197981aba16f9d9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 09:15:09 -0400 Subject: [PATCH 0088/4847] Call commit() with verbatim: true from mini editor --- lib/controllers/commit-controller.js | 8 ++++--- test/controllers/commit-controller.test.js | 28 ++++++++++++++++++---- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/lib/controllers/commit-controller.js b/lib/controllers/commit-controller.js index 240d4a618d..b0e233a0d4 100644 --- a/lib/controllers/commit-controller.js +++ b/lib/controllers/commit-controller.js @@ -122,16 +122,18 @@ export default class CommitController extends React.Component { this.subscriptions.dispose(); } - commit(message, coAuthors = [], amend) { - let msg; + commit(message, coAuthors = [], amend = false) { + let msg, verbatim; if (this.isCommitMessageEditorExpanded()) { msg = this.getCommitMessageEditors()[0].getText(); + verbatim = false; } else { const wrapMessage = this.props.config.get('github.automaticCommitMessageWrapping'); msg = wrapMessage ? wrapCommitMessage(message) : message; + verbatim = true; } - return this.props.commit(msg.trim(), {amend, coAuthors}); + return this.props.commit(msg.trim(), {amend, coAuthors, verbatim}); } setCommitMessage(message) { diff --git a/test/controllers/commit-controller.test.js b/test/controllers/commit-controller.test.js index 6e450533f9..858a8fe0fd 100644 --- a/test/controllers/commit-controller.test.js +++ b/test/controllers/commit-controller.test.js @@ -117,12 +117,12 @@ describe('CommitController', function() { }); describe('committing', function() { - let workdirPath, repository; + let workdirPath, repository, commit; beforeEach(async function() { workdirPath = await cloneRepository('three-files'); repository = await buildRepositoryWithPipeline(workdirPath, {confirm, notificationManager, workspace}); - const commit = message => repository.commit(message); + commit = sinon.stub().callsFake((...args) => repository.commit(...args)); app = React.cloneElement(app, {repository, commit}); }); @@ -139,6 +139,20 @@ describe('CommitController', function() { assert.strictEqual(repository.getCommitMessage(), ''); }); + it('sets the verbatim flag when committing from the mini editor', async function() { + await fs.writeFile(path.join(workdirPath, 'a.txt'), 'some changes', {encoding: 'utf8'}); + await repository.git.exec(['add', '.']); + + const wrapper = shallow(app, {disableLifecycleMethods: true}); + await wrapper.instance().commit('message\n\n#123 do some things'); + + assert.isTrue(commit.calledWith('message\n\n#123 do some things', { + amend: false, + coAuthors: [], + verbatim: true, + })); + }); + it('issues a notification on failure', async function() { repository.setCommitMessage('some message'); @@ -306,10 +320,14 @@ describe('CommitController', function() { const editor = workspace.getActiveTextEditor(); editor.setText('message in editor'); await editor.save(); - wrapper.find('CommitView').prop('commit')('message in box'); - await assert.async.strictEqual((await repository.getLastCommit()).getMessageSubject(), 'message in editor'); - await assert.async.isFalse(fs.existsSync(wrapper.instance().getCommitMessagePath())); + await wrapper.find('CommitView').prop('commit')('message in box'); + + assert.strictEqual((await repository.getLastCommit()).getMessageSubject(), 'message in editor'); + assert.isFalse(fs.existsSync(wrapper.instance().getCommitMessagePath())); + assert.isTrue(commit.calledWith('message in editor', { + amend: false, coAuthors: [], verbatim: false, + })); }); it('asks user to confirm if commit editor has unsaved changes', async function() { From 99519fdd18324d74b2c0b503f237d996d3e13ca1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 09:27:36 -0400 Subject: [PATCH 0089/4847] Fix GitTabController tests that set expectations on commit() args --- test/controllers/git-tab-controller.test.js | 25 ++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/test/controllers/git-tab-controller.test.js b/test/controllers/git-tab-controller.test.js index 2a6abbb17a..9c6dfbd12b 100644 --- a/test/controllers/git-tab-controller.test.js +++ b/test/controllers/git-tab-controller.test.js @@ -572,7 +572,10 @@ describe('GitTabController', function() { assert.strictEqual(wrapper.find('CommitView').instance().editor.getText(), ''); commandRegistry.dispatch(workspaceElement, 'github:amend-last-commit'); - await assert.async.deepEqual(repository.commit.args[0][1], {amend: true, coAuthors: []}); + await assert.async.deepEqual( + repository.commit.args[0][1], + {amend: true, coAuthors: [], verbatim: true}, + ); // amending should commit all unstaged changes await updateWrapper(repository, wrapper); @@ -594,7 +597,10 @@ describe('GitTabController', function() { assert.lengthOf(wrapper.find('GitTabView').prop('stagedChanges'), 0); commandRegistry.dispatch(workspaceElement, 'github:amend-last-commit'); - await assert.async.deepEqual(repository.commit.args[0][1], {amend: true, coAuthors: []}); + await assert.async.deepEqual( + repository.commit.args[0][1], + {amend: true, coAuthors: [], verbatim: true}, + ); await updateWrapper(repository, wrapper); // new commit message is used @@ -617,7 +623,10 @@ describe('GitTabController', function() { commandRegistry.dispatch(workspaceElement, 'github:amend-last-commit'); // verify that coAuthor was passed - await assert.async.deepEqual(repository.commit.args[0][1], {amend: true, coAuthors: [author]}); + await assert.async.deepEqual( + repository.commit.args[0][1], + {amend: true, coAuthors: [author], verbatim: true}, + ); await repository.commit.returnValues[0]; await updateWrapper(repository, wrapper); @@ -640,7 +649,10 @@ describe('GitTabController', function() { commandRegistry.dispatch(workspaceElement, 'github:amend-last-commit'); // verify that coAuthor was passed - await assert.async.deepEqual(repository.commit.args[0][1], {amend: true, coAuthors: [author]}); + await assert.async.deepEqual( + repository.commit.args[0][1], + {amend: true, coAuthors: [author], verbatim: true}, + ); await repository.commit.returnValues[0]; await updateWrapper(repository, wrapper); @@ -673,7 +685,10 @@ describe('GitTabController', function() { // amend again commandRegistry.dispatch(workspaceElement, 'github:amend-last-commit'); // verify that NO coAuthor was passed - await assert.async.deepEqual(repository.commit.args[0][1], {amend: true, coAuthors: []}); + await assert.async.deepEqual( + repository.commit.args[0][1], + {amend: true, coAuthors: [], verbatim: true}, + ); await repository.commit.returnValues[0]; await updateWrapper(repository, wrapper); From 46c153464c60f084656423443fa366566d8abcac Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 30 May 2018 14:55:21 -0400 Subject: [PATCH 0090/4847] Band-aid --- lib/controllers/git-tab-controller.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index 5451cfddf2..9a5708fcae 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -319,6 +319,10 @@ export default class GitTabController extends React.Component { } rememberLastFocus(event) { + if (!this.refView) { + return; + } + this.lastFocus = this.refView.rememberFocus(event) || GitTabView.focus.STAGING; } From 4eb4805fe68a92a79edae504f48a5affb217bfe4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 30 May 2018 15:00:35 -0400 Subject: [PATCH 0091/4847] Another band-aid --- lib/views/commit-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/commit-view.js b/lib/views/commit-view.js index dc2756426b..2796f88e58 100644 --- a/lib/views/commit-view.js +++ b/lib/views/commit-view.js @@ -556,7 +556,7 @@ export default class CommitView extends React.Component { return CommitView.focus.COMMIT_BUTTON; } - if (this.refCoAuthorSelect.map(c => c.wrapper.contains(event.target)).getOr(false)) { + if (this.refCoAuthorSelect.map(c => c.wrapper && c.wrapper.contains(event.target)).getOr(false)) { return CommitView.focus.COAUTHOR_INPUT; } From d88d7ca4611e991bd9d2f174a8f27153ec832aae Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 10:29:57 -0400 Subject: [PATCH 0092/4847] Compute the size, in bytes, of a FilePatch --- lib/models/file-patch.js | 8 ++++++++ lib/models/hunk-line.js | 4 ++++ lib/models/hunk.js | 4 ++++ test/models/file-patch.test.js | 17 +++++++++++++++++ 4 files changed, 33 insertions(+) diff --git a/lib/models/file-patch.js b/lib/models/file-patch.js index beb1e76b88..0e0a91cf0f 100644 --- a/lib/models/file-patch.js +++ b/lib/models/file-patch.js @@ -55,6 +55,10 @@ class Patch { return this.hunks; } + getByteSize() { + return this.getHunks().reduce((acc, hunk) => acc + hunk.getByteSize(), 0); + } + clone(opts = {}) { return new Patch({ status: opts.status !== undefined ? opts.status : this.status, @@ -120,6 +124,10 @@ export default class FilePatch { return this.getNewFile().getSymlink(); } + getByteSize() { + return this.getPatch().getByteSize(); + } + didChangeExecutableMode() { const oldMode = this.getOldMode(); const newMode = this.getNewMode(); diff --git a/lib/models/hunk-line.js b/lib/models/hunk-line.js index 439ac90e8e..fcf4826e17 100644 --- a/lib/models/hunk-line.js +++ b/lib/models/hunk-line.js @@ -86,4 +86,8 @@ export default class HunkLine { toString() { return this.getOrigin() + (this.getStatus() === 'nonewline' ? ' ' : '') + this.getText(); } + + getByteSize() { + return Buffer.byteLength(this.getText(), 'utf8'); + } } diff --git a/lib/models/hunk.js b/lib/models/hunk.js index 9a4c2fb779..600b230ae9 100644 --- a/lib/models/hunk.js +++ b/lib/models/hunk.js @@ -76,4 +76,8 @@ export default class Hunk { toString() { return this.getLines().reduce((a, b) => a + b.toString() + '\n', this.getHeader()); } + + getByteSize() { + return this.getLines().reduce((acc, line) => acc + line.getByteSize(), 0); + } } diff --git a/test/models/file-patch.test.js b/test/models/file-patch.test.js index 17b0728e56..e0e7aab8c2 100644 --- a/test/models/file-patch.test.js +++ b/test/models/file-patch.test.js @@ -370,4 +370,21 @@ describe('FilePatch', function() { `); }); }); + + it('returns the size in bytes from getByteSize()', function() { + const filePatch = createFilePatch('a.txt', 'a.txt', 'modified', [ + new Hunk(1, 1, 1, 3, '', [ + new HunkLine('line-1', 'added', -1, 1), + new HunkLine('line-2', 'added', -1, 2), + new HunkLine('line-3', 'unchanged', 1, 3), + ]), + new Hunk(5, 7, 5, 4, '', [ + new HunkLine('line-4', 'unchanged', 5, 7), + new HunkLine('line-5', 'deleted', 6, -1), + new HunkLine('line-6', 'deleted', 7, -1), + ]), + ]); + + assert.strictEqual(filePatch.getByteSize(), 36); + }); }); From b70a85a6d419181dbf78993a61fb0fe5f91de95c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 10:47:27 -0400 Subject: [PATCH 0093/4847] Use a byte threshold instead of a line threshold --- lib/controllers/file-patch-controller.js | 8 +++----- test/controllers/file-patch-controller.test.js | 9 ++++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/controllers/file-patch-controller.js b/lib/controllers/file-patch-controller.js index ffe6bc062e..050aa62822 100644 --- a/lib/controllers/file-patch-controller.js +++ b/lib/controllers/file-patch-controller.js @@ -12,7 +12,7 @@ import {autobind} from '../helpers'; export default class FilePatchController extends React.Component { static propTypes = { - largeDiffLineThreshold: PropTypes.number, + largeDiffByteThreshold: PropTypes.number, getRepositoryForWorkdir: PropTypes.func.isRequired, workingDirectoryPath: PropTypes.string.isRequired, commandRegistry: PropTypes.object.isRequired, @@ -30,7 +30,7 @@ export default class FilePatchController extends React.Component { } static defaultProps = { - largeDiffLineThreshold: 1000, + largeDiffByteThreshold: 1000, switchboard: new Switchboard(), } @@ -254,9 +254,7 @@ export default class FilePatchController extends React.Component { return true; } - const lineCount = filePatch.getHunks().reduce((acc, hunk) => hunk.getLines().length, 0); - this.lineCount = lineCount; - return lineCount < this.props.largeDiffLineThreshold; + return filePatch.getByteSize() < this.props.largeDiffByteThreshold; } onDidChangeTitle(callback) { diff --git a/test/controllers/file-patch-controller.test.js b/test/controllers/file-patch-controller.test.js index e42723e154..9643787e71 100644 --- a/test/controllers/file-patch-controller.test.js +++ b/test/controllers/file-patch-controller.test.js @@ -97,9 +97,8 @@ describe('FilePatchController', function() { getFilePatchForPath = sinon.stub(repository, 'getFilePatchForPath'); }); - describe('when the FilePatch has many lines', function() { + describe('when the FilePatch is too large', function() { it('renders a confirmation widget', async function() { - const hunk1 = new Hunk(0, 0, 1, 1, '', [ new HunkLine('line-1', 'added', 1, 1), new HunkLine('line-2', 'added', 2, 2), @@ -112,7 +111,7 @@ describe('FilePatchController', function() { getFilePatchForPath.returns(filePatch); - const wrapper = mount(React.cloneElement(component, {largeDiffLineThreshold: 5})); + const wrapper = mount(React.cloneElement(component, {largeDiffByteThreshold: 5})); await assert.async.match(wrapper.text(), /large diff/); }); @@ -129,7 +128,7 @@ describe('FilePatchController', function() { const filePatch = createFilePatch(filePath, filePath, 'modified', [hunk]); getFilePatchForPath.returns(filePatch); - const wrapper = mount(React.cloneElement(component, {largeDiffLineThreshold: 5})); + const wrapper = mount(React.cloneElement(component, {largeDiffByteThreshold: 5})); await assert.async.isTrue(wrapper.update().find('.large-file-patch').exists()); wrapper.find('.large-file-patch').find('button').simulate('click'); @@ -152,7 +151,7 @@ describe('FilePatchController', function() { getFilePatchForPath.returns(filePatch1); const wrapper = mount(React.cloneElement(component, { - filePath: filePatch1.getPath(), largeDiffLineThreshold: 5, + filePath: filePatch1.getPath(), largeDiffByteThreshold: 5, })); await assert.async.isTrue(wrapper.update().find('.large-file-patch').exists()); From 6b3256d90e1446d18e3197da92d2a5f816ea7b4b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 11:40:57 -0400 Subject: [PATCH 0094/4847] Set the "large diff" threshold at 32k --- lib/controllers/file-patch-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controllers/file-patch-controller.js b/lib/controllers/file-patch-controller.js index 050aa62822..cecb38378b 100644 --- a/lib/controllers/file-patch-controller.js +++ b/lib/controllers/file-patch-controller.js @@ -30,7 +30,7 @@ export default class FilePatchController extends React.Component { } static defaultProps = { - largeDiffByteThreshold: 1000, + largeDiffByteThreshold: 32768, switchboard: new Switchboard(), } From 21d4cb0526f48ab1028ea2cbd9963735c50bda0c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 11:41:50 -0400 Subject: [PATCH 0095/4847] Shhh eslint --- lib/views/file-patch-view.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/views/file-patch-view.js b/lib/views/file-patch-view.js index 5251ac7284..ad0f69c5e7 100644 --- a/lib/views/file-patch-view.js +++ b/lib/views/file-patch-view.js @@ -82,7 +82,8 @@ export default class FilePatchView extends React.Component { this.disposables.add(new Disposable(() => window.removeEventListener('mouseup', this.mouseup))); } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase + UNSAFE_componentWillReceiveProps(nextProps) { const hunksChanged = this.props.hunks.length !== nextProps.hunks.length || this.props.hunks.some((hunk, index) => hunk !== nextProps.hunks[index]); From 96afaa4f1f149f9a0cbd6b8047ca921d674eacb5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 11:47:07 -0400 Subject: [PATCH 0096/4847] Show the byte count of large diffs --- lib/controllers/file-patch-controller.js | 5 +++-- lib/views/file-patch-view.js | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/controllers/file-patch-controller.js b/lib/controllers/file-patch-controller.js index cecb38378b..43919171b3 100644 --- a/lib/controllers/file-patch-controller.js +++ b/lib/controllers/file-patch-controller.js @@ -218,7 +218,7 @@ export default class FilePatchController extends React.Component { commandRegistry={this.props.commandRegistry} tooltips={this.props.tooltips} displayLargeDiffMessage={!this.shouldDisplayLargeDiff(this.state.filePatch)} - lineCount={this.lineCount} + byteCount={this.byteCount} handleShowDiffClick={this.handleShowDiffClick} hunks={hunks} executableModeChange={executableModeChange} @@ -254,7 +254,8 @@ export default class FilePatchController extends React.Component { return true; } - return filePatch.getByteSize() < this.props.largeDiffByteThreshold; + this.byteCount = filePatch.getByteSize(); + return this.byteCount < this.props.largeDiffByteThreshold; } onDidChangeTitle(callback) { diff --git a/lib/views/file-patch-view.js b/lib/views/file-patch-view.js index ad0f69c5e7..2e3fe5a649 100644 --- a/lib/views/file-patch-view.js +++ b/lib/views/file-patch-view.js @@ -48,7 +48,7 @@ export default class FilePatchView extends React.Component { didDiveIntoCorrespondingFilePatch: PropTypes.func.isRequired, switchboard: PropTypes.instanceOf(Switchboard), displayLargeDiffMessage: PropTypes.bool, - lineCount: PropTypes.number, + byteCount: PropTypes.number, handleShowDiffClick: PropTypes.func.isRequired, } @@ -150,7 +150,7 @@ export default class FilePatchView extends React.Component { return (

- This is a large diff of {this.props.lineCount} lines. For performance reasons, it is not rendered by default. + This is a large diff of {this.props.byteCount} bytes. For performance reasons, it is not rendered by default.

From a6a14a359306483bea642a787b7e5859f7904d58 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 11:47:53 -0400 Subject: [PATCH 0097/4847] Let's use bytes to humanize that byte count --- package-lock.json | 52 ++++++++++++++++++++++++++--------------------- package.json | 1 + 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index bfec30fb92..d596b2da7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "github", - "version": "0.15.2", + "version": "0.16.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -252,7 +252,7 @@ "@sinonjs/formatio": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", - "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", + "integrity": "sha1-hNt+nrVTHfGKjF4L+25EnlXmVLI=", "dev": true, "requires": { "samsam": "1.3.0" @@ -692,7 +692,7 @@ "babel-core": { "version": "6.26.3", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "integrity": "sha1-suLwnjQtDwyI4vAuBneUEl51wgc=", "requires": { "babel-code-frame": "^6.26.0", "babel-generator": "^6.26.0", @@ -2019,6 +2019,11 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -2412,7 +2417,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "requires": { "ms": "2.0.0" } @@ -2678,7 +2683,7 @@ "dugite": { "version": "1.66.0", "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.66.0.tgz", - "integrity": "sha512-H5Dmc5HZIj1RKUCcgNvocSBXjoimWgcAXzwHEHXnQXJTv9ZYaCP/ZD7njmE635ShJ22xXAWz5Xm+tf4Klj181g==", + "integrity": "sha1-X9q2aDwLU4p5vb7Emenz0+pyEPk=", "requires": { "checksum": "^0.1.1", "mkdirp": "^0.5.1", @@ -2700,7 +2705,7 @@ "electron-devtools-installer": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-2.2.4.tgz", - "integrity": "sha512-b5kcM3hmUqn64+RUcHjjr8ZMpHS2WJ5YO0pnG9+P/RTdx46of/JrEjuciHWux6pE+On6ynWhHJF53j/EDJN0PA==", + "integrity": "sha1-JhpQM343Eh0zi5ZvB5IutJOah2M=", "dev": true, "requires": { "7zip": "0.0.6", @@ -3291,7 +3296,7 @@ "event-kit": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.0.tgz", - "integrity": "sha512-tUDxeNC9JzN2Tw/f8mLtksY34v1hHmaR7lV7X4p04XSjaeUhFMfzjF6Nwov9e0EKGEx63BaKcgXKxjpQaPo0wg==" + "integrity": "sha1-L3KxHitfUzzByVA4cEBiSkoCX+g=" }, "execa": { "version": "0.7.0", @@ -3696,7 +3701,7 @@ "fs-extra": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "integrity": "sha1-DYUhIuW8W+tFP7Ao6cDJvzY0DJQ=", "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -3977,7 +3982,7 @@ "graphql": { "version": "0.13.2", "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.13.2.tgz", - "integrity": "sha512-QZ5BL8ZO/B20VA8APauGBg3GyEgZ19eduvpLWoq5x7gMmWnHoy8rlQWPLmWgFvo1yNgjSEFMesmS4R6pPr7xog==", + "integrity": "sha1-THQK48Iigj5wBAlvgy57k7IQgnA=", "requires": { "iterall": "^1.2.1" } @@ -4741,7 +4746,7 @@ "just-extend": { "version": "1.1.27", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", + "integrity": "sha1-7G55QQ/5FORyZSq/oOYDwD1g6QU=", "dev": true }, "keytar": { @@ -5212,7 +5217,7 @@ "lolex": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.0.tgz", - "integrity": "sha512-uJkH2e0BVfU5KOJUevbTOtpDduooSarH5PopO+LfM/vZf8Z9sJzODqKev804JYM2i++ktJfUmC1le4LwFQ1VMg==", + "integrity": "sha1-nAh6aexEDjnT95Z2fPGyzcQ9XqU=", "dev": true }, "loose-envify": { @@ -5316,7 +5321,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "requires": { "brace-expansion": "^1.1.7" } @@ -5494,7 +5499,8 @@ }, "stringstream": { "version": "0.0.5", - "resolved": "", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", "dev": true } } @@ -6159,7 +6165,7 @@ "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=" }, "process": { "version": "0.5.2", @@ -6338,7 +6344,7 @@ "react": { "version": "16.4.0", "resolved": "https://registry.npmjs.org/react/-/react-16.4.0.tgz", - "integrity": "sha512-K0UrkLXSAekf5nJu89obKUM7o2vc6MMN9LYoKnCa+c+8MJRAT120xzPLENcWSRc7GYKIg0LlgJRDorrufdglQQ==", + "integrity": "sha1-QCwtuDM1M2+6GWLAi5jGJyYX1YU=", "requires": { "fbjs": "^0.8.16", "loose-envify": "^1.1.0", @@ -6349,7 +6355,7 @@ "react-dom": { "version": "16.4.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.0.tgz", - "integrity": "sha512-bbLd+HYpBEnYoNyxDe9XpSG2t9wypMohwQPvKw8Hov3nF7SJiJIgK56b46zHpBUpHb06a1iEuw7G3rbrsnNL6w==", + "integrity": "sha1-CZ8GfdWCfONqKer5ps3Hy/Yhax4=", "requires": { "fbjs": "^0.8.16", "loose-envify": "^1.1.0", @@ -6982,7 +6988,7 @@ "request": { "version": "2.87.0", "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", - "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "integrity": "sha1-MvACNc0I1IK00NaNuTqCnA7VdW4=", "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.6.0", @@ -7074,7 +7080,7 @@ "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", "requires": { "glob": "^7.0.5" } @@ -7130,7 +7136,7 @@ "samsam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", + "integrity": "sha1-jR2TUOJWItow3j5EumkrUiGrfFA=", "dev": true }, "semver": { @@ -7231,7 +7237,7 @@ "sinon": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/sinon/-/sinon-5.0.10.tgz", - "integrity": "sha512-+YT7Mjr8BpNndQqUUydO/daggF4yuOAnsVjo+5Ayx3mLLUqojfkXhDkho4HB5VgfnZYSdhxVDPbfJ2EBXFMSvA==", + "integrity": "sha1-ooKzanR1ZkyfmHGRCOVUaQcSkCM=", "dev": true, "requires": { "@sinonjs/formatio": "^2.0.0", @@ -7246,7 +7252,7 @@ "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -7413,7 +7419,7 @@ "source-map-support": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "integrity": "sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8=", "requires": { "source-map": "^0.5.6" } @@ -7599,7 +7605,7 @@ "stringstream": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", - "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "integrity": "sha1-eIAiWw1K0Q4wkn0Weh1vL9OzOnI=", "dev": true, "optional": true }, diff --git a/package.json b/package.json index e08372b170..088c4681a0 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", "babel-plugin-transform-object-rest-spread": "6.26.0", "babel-preset-react": "6.24.1", + "bytes": "^3.0.0", "classnames": "2.2.5", "compare-sets": "1.0.1", "dugite": "^1.66.0", From c3b337aa2693df4ca2d61429793fe3bb0bebbb98 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 11:54:21 -0400 Subject: [PATCH 0098/4847] Render the bytes in a nice humanized format --- lib/controllers/file-patch-controller.js | 1 - lib/views/file-patch-view.js | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/controllers/file-patch-controller.js b/lib/controllers/file-patch-controller.js index 43919171b3..90d6a67df8 100644 --- a/lib/controllers/file-patch-controller.js +++ b/lib/controllers/file-patch-controller.js @@ -1,5 +1,4 @@ import path from 'path'; - import React from 'react'; import PropTypes from 'prop-types'; import {Point} from 'atom'; diff --git a/lib/views/file-patch-view.js b/lib/views/file-patch-view.js index 2e3fe5a649..e8067025dc 100644 --- a/lib/views/file-patch-view.js +++ b/lib/views/file-patch-view.js @@ -1,8 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; - import {CompositeDisposable, Disposable} from 'event-kit'; import cx from 'classnames'; +import bytes from 'bytes'; import HunkView from './hunk-view'; import SimpleTooltip from '../atom/simple-tooltip'; @@ -147,10 +147,12 @@ export default class FilePatchView extends React.Component { } renderLargeDiffMessage() { + const human = bytes.format(this.props.byteCount); + return (

- This is a large diff of {this.props.byteCount} bytes. For performance reasons, it is not rendered by default. + This is a large {human} diff. For performance reasons, it is not rendered by default.

From 2c61b2efaaa5152919457337b0789a7692312355 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 12:29:16 -0400 Subject: [PATCH 0099/4847] Regexps --- test/controllers/file-patch-controller.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/controllers/file-patch-controller.test.js b/test/controllers/file-patch-controller.test.js index 9643787e71..a7b075e8ec 100644 --- a/test/controllers/file-patch-controller.test.js +++ b/test/controllers/file-patch-controller.test.js @@ -113,7 +113,7 @@ describe('FilePatchController', function() { const wrapper = mount(React.cloneElement(component, {largeDiffByteThreshold: 5})); - await assert.async.match(wrapper.text(), /large diff/); + await assert.async.match(wrapper.text(), /large .+ diff/); }); it('renders the full diff when the confirmation is clicked', async function() { From e655ac13f9b5b14763335e37d1198a97d81c4836 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Jun 2018 14:57:42 -0400 Subject: [PATCH 0100/4847] Draft draft draft Co-Authored-By: simurai --- docs/rfcs/004-issueish-list.md | 98 ++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 docs/rfcs/004-issueish-list.md diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md new file mode 100644 index 0000000000..4e57988e6e --- /dev/null +++ b/docs/rfcs/004-issueish-list.md @@ -0,0 +1,98 @@ +# Issueish List + +## Status + +Proposed + +## Summary + +Display a list of all open pull requests in the current repository in the GitHub tab. + +## Motivation + +To provide a navigational element that makes sense even if you aren't on an active feature branch. + +To give users a way to see an overview of what's going on in the repository. + +As an initial building block toward a pull request review workflow. + +## Explanation + +### Accordion Lists + +Within the GitHub panel, render a vertical stack of two collapsible lists of _issueish_ (pull request or issue) items: + +_First list: current pull request_. If the active branch is associated with one or more open pull requests on the GitHub repository, render an item for each. + +_Second list: all open pull requests_. List all open pull requests on the GitHub repository. + +Each list has a "collapse arrow" in its header. Clicking the collapse arrow toggles the visibility of that list's items, accordion-style. + +If either list exceeds 20 items, truncate the list and render a "More" link after its final item. Clicking "more" opens the corresponding search on GitHub. + +Each list item renders a tile containing a compact set of information about that pull request: + +* Mini author avatar +* Title, truncated if necessary +* Terse relative timestamp (1d, 2h, 30m) +* Pull request state: open, closed, merged +* Status check summary + +_TBD: Tile design_ + +Clicking on a list item opens an issueish pane item for the chosen issueish in the same pane container as the parent component (by default, the right dock). If the issuish pane item is already open, it is activated instead. + +### Issueish Pane Item: Pull Request + +For a pull request, the issueish pane shows: + +* Author avatar +* Title +* Controls for actions: + * "Checkout" to fetch (if necessary) and check out the pull request. Only enabled if the current pull request is not the current one. + * "Browse" to launch a browser on the corresponding GitHub page. + * "Merge" to merge the pull request on GitHub if it is open. + * "Close" to close the pull request, unmerged, if it is open. + * "Re-open" to re-open a pull request if it is closed. +* Pull request overview details: commit count, files changed. +* Full description as rendered markdown. +* Reaction emoji and counts. +* Details and links for all status checks. + +_TBD: Issueish pane item design_ + +## Drawbacks + +This does not offer a mechanism to create _new_ pull requests, which we have now. We also lose timeline events on the pull request. + +## Rationale and alternatives + +Our current GitHub panel focuses on showing you stuff about _the pull request that's associated with your current branch._ The problem is, it's difficult to unambiguously determine that in the general case. + +The first thing you see today when you open the GitHub panel on the `master` branch of an active repository is not very helpful: + +![wat](https://user-images.githubusercontent.com/17565/40857603-99b92304-65a9-11e8-986e-0f14290bda8a.png) + +This is a list of _all pull requests on GitHub that have a head ref called "master", from any head repository_. You can then "pin" any of them to see that pull request's details. This isn't useful on master and it's unclear to users what this is supposed to accomplish. Pinning was intended to be an infrequent edge case when we couldn't find the right PR for a given ref, not the first interaction you have with the package. + +Showing a PR list instead provides a uniform, more easily understood entry point to the package's GitHub functionality, and paves the way to other pull-request-focused activities in the future. "All open PRs" seems like a reasonable starting point, and "current PRs" preserves the ability to take advantage of your local editor context. + +With that said, the choices for the specific lists we show are a bit arbitrary. We'll need to research and iterate on them quite a bit to find what's most useful for the most people, but for now we need to start with something. + +## Unresolved questions + +### Before RFC merge: + +- [ ] How can we still offer "push/publish+new pull request"? +- [ ] What else from the existing issueish pane should we keep? Comments, timeline events? +- [ ] Are there other pull request actions it would be useful to support? + +### Out of scope: + +- [ ] How can we allow a user to customize the lists? +- [ ] How can we notify a user about updated activity on a visible PR? + +## Implementation phases + +1. Accordion list infrastructure: search model, collapsible list component. +2. Revisit the issueish pane item and add action controls. From 1cc3e7183edbcdc715c09d7e8808055e902661e4 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Fri, 1 Jun 2018 23:36:59 +0000 Subject: [PATCH 0101/4847] fix(package): update moment to version 2.22.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 088c4681a0..1c9ec04c62 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "graphql": "0.13.2", "keytar": "4.2.1", "lodash.memoize": "4.1.2", - "moment": "2.22.1", + "moment": "2.22.2", "prop-types": "15.6.1", "react": "16.4.0", "react-dom": "16.4.0", From 02d556c70e14155a2a0220d96f98511b92cb7ea6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Jun 2018 08:37:47 -0400 Subject: [PATCH 0102/4847] Flag deprecated lifecycle methods with UNSAFE_ --- lib/controllers/commit-controller.js | 6 ++++-- lib/views/commit-view.js | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/controllers/commit-controller.js b/lib/controllers/commit-controller.js index b0e233a0d4..f30a334fb8 100644 --- a/lib/controllers/commit-controller.js +++ b/lib/controllers/commit-controller.js @@ -47,7 +47,8 @@ export default class CommitController extends React.Component { this.refCommitView = null; } - componentWillMount() { + // eslint-disable-next-line camelcase + UNSAFE_componentWillMount() { this.subscriptions.add( this.props.workspace.onDidAddTextEditor(({textEditor}) => { if (this.props.repository.isPresent() && textEditor.getPath() === this.getCommitMessagePath()) { @@ -112,7 +113,8 @@ export default class CommitController extends React.Component { ); } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase + UNSAFE_componentWillReceiveProps(nextProps) { if (!this.props.isMerging && nextProps.isMerging && !this.getCommitMessage()) { this.setCommitMessage(nextProps.mergeMessage || ''); } diff --git a/lib/views/commit-view.js b/lib/views/commit-view.js index 2796f88e58..fd75fa813a 100644 --- a/lib/views/commit-view.js +++ b/lib/views/commit-view.js @@ -111,7 +111,8 @@ export default class CommitView extends React.Component { }; } - componentWillMount() { + // eslint-disable-next-line camelcase + UNSAFE_componentWillMount() { this.scheduleShowWorking(this.props); this.subscriptions = new CompositeDisposable( @@ -353,7 +354,8 @@ export default class CommitView extends React.Component { }); } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase + UNSAFE_componentWillReceiveProps(nextProps) { this.scheduleShowWorking(nextProps); } From 17d4c02c1e94309ad104cf97af14407d33d83aad Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Jun 2018 08:38:02 -0400 Subject: [PATCH 0103/4847] Call forceUpdate() after closing commit message editors --- lib/controllers/commit-controller.js | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/controllers/commit-controller.js b/lib/controllers/commit-controller.js index f30a334fb8..87f89d7471 100644 --- a/lib/controllers/commit-controller.js +++ b/lib/controllers/commit-controller.js @@ -170,7 +170,8 @@ export default class CommitController extends React.Component { async toggleExpandedCommitMessageEditor(messageFromBox) { if (this.isCommitMessageEditorExpanded()) { if (this.commitMessageEditorIsInForeground()) { - this.closeAllOpenCommitMessageEditors(); + await this.closeAllOpenCommitMessageEditors(); + this.forceUpdate(); } else { this.activateCommitMessageEditor(); } @@ -203,16 +204,20 @@ export default class CommitController extends React.Component { } closeAllOpenCommitMessageEditors() { - this.props.workspace.getPanes().forEach(pane => { - pane.getItems().forEach(async item => { - if (item && item.getPath && item.getPath() === this.getCommitMessagePath()) { - const destroyed = await pane.destroyItem(item); - if (!destroyed) { - pane.activateItem(item); - } - } - }); - }); + return Promise.all( + this.props.workspace.getPanes().map(pane => { + return Promise.all( + pane.getItems().map(async item => { + if (item && item.getPath && item.getPath() === this.getCommitMessagePath()) { + const destroyed = await pane.destroyItem(item); + if (!destroyed) { + pane.activateItem(item); + } + } + }), + ); + }), + ); } async openCommitMessageEditor(messageFromBox) { From 01e5668f14f7d37bd2f21287c559de4521c8d71e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Jun 2018 09:27:04 -0400 Subject: [PATCH 0104/4847] Prepare 0.17.0 release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1c9ec04c62..a4aa06961b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "github", "main": "./lib/index", - "version": "0.16.0", + "version": "0.17.0", "description": "GitHub integration", "repository": "https://github.com/atom/github", "license": "MIT", From eecd177e993ac4bf27b5bc252206206a9752248b Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 5 Jun 2018 14:00:14 +0900 Subject: [PATCH 0105/4847] Add tile mockup --- docs/rfcs/004-issueish-list.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index 4e57988e6e..0906273a4f 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -38,7 +38,7 @@ Each list item renders a tile containing a compact set of information about that * Pull request state: open, closed, merged * Status check summary -_TBD: Tile design_ +![tile](https://user-images.githubusercontent.com/378023/40955959-8458ae7c-68c8-11e8-974e-40441a3b5679.png) Clicking on a list item opens an issueish pane item for the chosen issueish in the same pane container as the parent component (by default, the right dock). If the issuish pane item is already open, it is activated instead. From 45b116b7c8e93639de3d96f3d18390e29efa482d Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 5 Jun 2018 17:37:11 +0900 Subject: [PATCH 0106/4847] Add lists mockup --- docs/rfcs/004-issueish-list.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index 0906273a4f..d5cb404716 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -30,6 +30,8 @@ Each list has a "collapse arrow" in its header. Clicking the collapse arrow togg If either list exceeds 20 items, truncate the list and render a "More" link after its final item. Clicking "more" opens the corresponding search on GitHub. +![Lists](https://user-images.githubusercontent.com/378023/40964722-ceb9d95a-68e6-11e8-90b3-1c155cdc2c00.png) + Each list item renders a tile containing a compact set of information about that pull request: * Mini author avatar @@ -38,7 +40,7 @@ Each list item renders a tile containing a compact set of information about that * Pull request state: open, closed, merged * Status check summary -![tile](https://user-images.githubusercontent.com/378023/40955959-8458ae7c-68c8-11e8-974e-40441a3b5679.png) +![List item](https://user-images.githubusercontent.com/378023/40964791-f4b28fbc-68e6-11e8-907b-c7d436d0d315.png) Clicking on a list item opens an issueish pane item for the chosen issueish in the same pane container as the parent component (by default, the right dock). If the issuish pane item is already open, it is activated instead. From 059099b02c1b54df8b5f8bf40952700d0b8d55ab Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 08:43:58 -0400 Subject: [PATCH 0107/4847] Render child components of an AtomTextEditor --- lib/atom/atom-text-editor.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/atom/atom-text-editor.js b/lib/atom/atom-text-editor.js index 01cdbdc4f2..03b1d025c1 100644 --- a/lib/atom/atom-text-editor.js +++ b/lib/atom/atom-text-editor.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {Fragment} from 'react'; import PropTypes from 'prop-types'; import {CompositeDisposable} from 'event-kit'; @@ -41,6 +41,7 @@ export default class AtomTextEditor extends React.PureComponent { text: PropTypes.string, didChange: PropTypes.func, didChangeCursorPosition: PropTypes.func, + children: PropTypes.element, } static defaultProps = { @@ -62,7 +63,10 @@ export default class AtomTextEditor extends React.PureComponent { render() { return ( - + + + {this.props.children} + ); } From 1345795ca65c7dda9d045153c66f23f9ee981691 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 08:44:13 -0400 Subject: [PATCH 0108/4847] Manage MarkerLayers --- lib/atom/marker-layer.js | 84 ++++++++++++++++++++++++++++++++++ test/atom/marker-layer.test.js | 53 +++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 lib/atom/marker-layer.js create mode 100644 test/atom/marker-layer.test.js diff --git a/lib/atom/marker-layer.js b/lib/atom/marker-layer.js new file mode 100644 index 0000000000..1f98dc7607 --- /dev/null +++ b/lib/atom/marker-layer.js @@ -0,0 +1,84 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Disposable} from 'event-kit'; + +import {autobind} from '../helpers'; +import RefHolder from '../models/ref-holder'; + +const markerLayerProps = { + maintainHistory: PropTypes.bool, + persistent: PropTypes.bool, +}; + +export default class MarkerLayer extends React.Component { + static propTypes = { + ...markerLayerProps, + editor: PropTypes.object, + children: PropTypes.element, + }; + + constructor(props) { + super(props); + + autobind(this, 'createLayer'); + + this.sub = new Disposable(); + this.layer = null; + this.state = { + editorHolder: RefHolder.on(this.props.editor), + }; + } + + static getDerivedStateFromProps(props, state) { + if (state.editorHolder.map(e => e === props.editor).getOr(props.editor === undefined)) { + return null; + } + + return { + editorHolder: RefHolder.on(props.editor), + }; + } + + componentDidMount() { + this.observeEditor(); + } + + render() { + return this.props.children || null; + } + + componentDidUpdate(prevProps, prevState) { + if (this.state.editorHolder !== prevState.editorHolder) { + this.observeEditor(); + } + } + + componentWillUnmount() { + if (this.layer) { + this.layer.destroy(); + } + this.sub.dispose(); + } + + observeEditor() { + this.sub.dispose(); + this.sub = this.state.editorHolder.observe(this.createLayer); + } + + createLayer() { + if (this.layer) { + this.layer.destroy(); + } + + const options = Object.keys(markerLayerProps).reduce((opts, propName) => { + opts[propName] = this.props[propName]; + return opts; + }, {}); + + this.layer = this.state.editorHolder.map(editor => editor.addMarkerLayer(options)).getOr(null); + } + + getID() { + return this.layer ? this.layer.id : undefined; + } +} diff --git a/test/atom/marker-layer.test.js b/test/atom/marker-layer.test.js new file mode 100644 index 0000000000..6b395997a1 --- /dev/null +++ b/test/atom/marker-layer.test.js @@ -0,0 +1,53 @@ +import React from 'react'; +import {shallow, mount} from 'enzyme'; + +import MarkerLayer from '../../lib/atom/marker-layer'; +import AtomTextEditor from '../../lib/atom/atom-text-editor'; + +describe('MarkerLayer', function() { + let atomEnv, editor; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + editor = await atomEnv.workspace.open(__filename); + }); + + it('adds its layer on mount', function() { + const app = ( + + ); + const wrapper = shallow(app); + const id = wrapper.instance().getID(); + + const layer = editor.getMarkerLayer(id); + assert.isTrue(layer.bufferMarkerLayer.maintainHistory); + assert.isTrue(layer.bufferMarkerLayer.persistent); + }); + + it('removes its layer on unmount', function() { + const app = ; + const wrapper = shallow(app); + const id = wrapper.instance().getID(); + + assert.isDefined(editor.getMarkerLayer(id)); + wrapper.unmount(); + assert.isUndefined(editor.getMarkerLayer(id)); + }); + + it('inherits an editor from a parent node', function() { + const app = ( + + + + ); + const wrapper = mount(app); + const theEditor = wrapper.instance().getModel(); + const id = wrapper.find('MarkerLayer').instance().getID(); + + assert.isDefined(theEditor.getMarkerLayer(id)); + }); +}); From 7ed0fabb77665a8146e87a879445e616b5a43757 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 09:39:37 -0400 Subject: [PATCH 0109/4847] Use a temporary fork of the Enzyme React 16 adapter for Context support --- package.json | 2 +- test/runner.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a4aa06961b..6534aefe4a 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "dedent-js": "1.0.1", "electron-devtools-installer": "2.2.4", "enzyme": "3.3.0", - "enzyme-adapter-react-16": "1.1.1", + "@smashwilson/enzyme-adapter-react-16": "1.0.2", "eslint": "4.19.1", "eslint-config-fbjs-opensource": "1.0.0", "hock": "1.3.2", diff --git a/test/runner.js b/test/runner.js index 1ac8176e0a..32abefb5f8 100644 --- a/test/runner.js +++ b/test/runner.js @@ -17,7 +17,7 @@ module.exports = createRunner({ overrideTestPaths: [/spec$/, /test/], }, mocha => { const Enzyme = require('enzyme'); - const Adapter = require('enzyme-adapter-react-16'); + const Adapter = require('@smashwilson/enzyme-adapter-react-16'); Enzyme.configure({adapter: new Adapter()}); require('mocha-stress'); From a00b0d97871bc05e24f33e8ca4fcec6acc48806f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 09:53:19 -0400 Subject: [PATCH 0110/4847] Provide a TextEditor model to children --- lib/atom/atom-text-editor.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/atom/atom-text-editor.js b/lib/atom/atom-text-editor.js index 03b1d025c1..f017382c71 100644 --- a/lib/atom/atom-text-editor.js +++ b/lib/atom/atom-text-editor.js @@ -35,6 +35,8 @@ const editorProps = { showCursorOnSelection: PropTypes.bool, }; +export const TextEditorContext = React.createContext(); + export default class AtomTextEditor extends React.PureComponent { static propTypes = { ...editorProps, @@ -48,7 +50,6 @@ export default class AtomTextEditor extends React.PureComponent { text: '', didChange: () => {}, didChangeCursorPosition: () => {}, - refElement: () => {}, } constructor(props, context) { @@ -59,13 +60,20 @@ export default class AtomTextEditor extends React.PureComponent { this.suppressChange = false; this.refElement = new RefHolder(); + this.refModel = new RefHolder(); + + this.subs.add( + this.refElement.observe(element => this.refModel.setter(element.getModel())), + ); } render() { return ( - {this.props.children} + + {this.props.children} + ); } From 421fa4cf696a81b580397f0351849df1538ab953 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 09:54:15 -0400 Subject: [PATCH 0111/4847] Optionally consume a TextEditor from context --- lib/atom/marker-layer.js | 19 +++++++++++++++++- test/atom/marker-layer.test.js | 35 +++++++++++++++++----------------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/lib/atom/marker-layer.js b/lib/atom/marker-layer.js index 1f98dc7607..f854ba8f4c 100644 --- a/lib/atom/marker-layer.js +++ b/lib/atom/marker-layer.js @@ -4,19 +4,25 @@ import {Disposable} from 'event-kit'; import {autobind} from '../helpers'; import RefHolder from '../models/ref-holder'; +import {TextEditorContext} from './atom-text-editor'; const markerLayerProps = { maintainHistory: PropTypes.bool, persistent: PropTypes.bool, }; -export default class MarkerLayer extends React.Component { +class WrappedMarkerLayer extends React.Component { static propTypes = { ...markerLayerProps, editor: PropTypes.object, children: PropTypes.element, + handleID: PropTypes.func, }; + static defaultProps = { + handleID: () => {}, + } + constructor(props) { super(props); @@ -76,9 +82,20 @@ export default class MarkerLayer extends React.Component { }, {}); this.layer = this.state.editorHolder.map(editor => editor.addMarkerLayer(options)).getOr(null); + this.props.handleID(this.getID()); } getID() { return this.layer ? this.layer.id : undefined; } } + +export default class MarkerLayer extends React.Component { + render() { + return ( + + {editor => } + + ); + } +} diff --git a/test/atom/marker-layer.test.js b/test/atom/marker-layer.test.js index 6b395997a1..ec758d5dd1 100644 --- a/test/atom/marker-layer.test.js +++ b/test/atom/marker-layer.test.js @@ -1,53 +1,52 @@ import React from 'react'; -import {shallow, mount} from 'enzyme'; +import {mount} from 'enzyme'; import MarkerLayer from '../../lib/atom/marker-layer'; import AtomTextEditor from '../../lib/atom/atom-text-editor'; describe('MarkerLayer', function() { - let atomEnv, editor; + let atomEnv, editor, layerID; beforeEach(async function() { atomEnv = global.buildAtomEnvironment(); editor = await atomEnv.workspace.open(__filename); }); + function setLayerID(id) { + layerID = id; + } + it('adds its layer on mount', function() { - const app = ( + mount( + handleID={setLayerID} + />, ); - const wrapper = shallow(app); - const id = wrapper.instance().getID(); - const layer = editor.getMarkerLayer(id); + const layer = editor.getMarkerLayer(layerID); assert.isTrue(layer.bufferMarkerLayer.maintainHistory); assert.isTrue(layer.bufferMarkerLayer.persistent); }); it('removes its layer on unmount', function() { - const app = ; - const wrapper = shallow(app); - const id = wrapper.instance().getID(); + const wrapper = mount(); - assert.isDefined(editor.getMarkerLayer(id)); + assert.isDefined(editor.getMarkerLayer(layerID)); wrapper.unmount(); - assert.isUndefined(editor.getMarkerLayer(id)); + assert.isUndefined(editor.getMarkerLayer(layerID)); }); it('inherits an editor from a parent node', function() { - const app = ( + const wrapper = mount( - - + + , ); - const wrapper = mount(app); const theEditor = wrapper.instance().getModel(); - const id = wrapper.find('MarkerLayer').instance().getID(); - assert.isDefined(theEditor.getMarkerLayer(id)); + assert.isDefined(theEditor.getMarkerLayer(layerID)); }); }); From deb790af9da1eb44e75928beb1ce4c7b30cffe8f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 11:37:22 -0400 Subject: [PATCH 0112/4847] Start the Marker type --- lib/atom/marker.js | 155 +++++++++++++++++++++++++++++++++++++++ test/atom/marker.test.js | 40 ++++++++++ 2 files changed, 195 insertions(+) create mode 100644 lib/atom/marker.js create mode 100644 test/atom/marker.test.js diff --git a/lib/atom/marker.js b/lib/atom/marker.js new file mode 100644 index 0000000000..118ea4b2b1 --- /dev/null +++ b/lib/atom/marker.js @@ -0,0 +1,155 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Disposable} from 'event-kit'; +import {Range, Point} from 'atom'; + +import {autobind} from '../helpers'; +import {RefHolderPropType} from '../prop-types'; +import RefHolder from '../models/ref-holder'; + +const MarkablePropType = PropTypes.shape({ + markBufferRange: PropTypes.func.isRequired, + markScreenRange: PropTypes.func.isRequired, + markBufferPosition: PropTypes.func.isRequired, + markScreenPosition: PropTypes.func.isRequired, +}); + +const RangePropType = PropTypes.oneOfType([ + PropTypes.array, + PropTypes.instanceOf(Range), +]); + +const PointPropType = PropTypes.oneOfType([ + PropTypes.array, + PropTypes.instanceOf(Point), +]); + +const markerProps = { + maintainHistory: PropTypes.bool, + reversed: PropTypes.bool, + invalidate: PropTypes.oneOf(['never', 'surround', 'overlap', 'inside', 'touch']), +}; + +class WrappedMarker extends React.Component { + static propTypes = { + ...markerProps, + bufferRange: RangePropType, + bufferPosition: PointPropType, + screenRange: RangePropType, + screenPosition: PointPropType, + markableHolder: RefHolderPropType, + children: PropTypes.element, + handleID: PropTypes.func, + } + + static defaultProps = { + handleID: () => {}, + } + + constructor(props) { + super(props); + + autobind(this, 'createMarker'); + + this.sub = new Disposable(); + this.marker = null; + } + + componentDidMount() { + this.observeMarkable(); + } + + render() { + return this.props.children || null; + } + + componentDidUpdate(prevProps) { + if (this.props.markableHolder !== prevProps.markableHolder) { + this.observeMarkable(); + } + } + + componentWillUnmount() { + if (this.marker) { + this.marker.destroy(); + } + this.sub.dispose(); + } + + observeMarkable() { + this.sub.dispose(); + this.sub = this.props.markableHolder.observe(this.createMarker); + } + + createMarker() { + if (this.marker) { + this.marker.destroy(); + } + + const options = Object.keys(markerProps).reduce((opts, propName) => { + if (this.props[propName] !== undefined) { + opts[propName] = this.props[propName]; + } + return opts; + }, {}); + + this.marker = this.props.markableHolder.map(markable => { + if (this.props.bufferRange) { + return markable.markBufferRange(this.props.bufferRange, options); + } + + if (this.props.screenRange) { + return markable.markScreenRange(this.props.screenRange, options); + } + + if (this.props.bufferPosition) { + return markable.markBufferPosition(this.props.bufferPosition, options); + } + + if (this.props.screenPosition) { + return markable.markScreenPosition(this.props.screenPosition, options); + } + + throw new Error('Expected one of bufferRange, screenRange, bufferPosition, or screenPosition to be set'); + }).getOr(null); + + if (this.marker) { + this.props.handleID(this.marker.id); + } + } +} + +export default class Marker extends React.Component { + static propTypes = { + editor: MarkablePropType, + layer: MarkablePropType, + } + + constructor(props) { + super(props); + + this.state = { + markableHolder: RefHolder.on(props.layer || props.editor), + }; + } + + static getDerivedStateFromProps(props, state) { + const markable = props.layer || props.editor; + + if (state.markableHolder.map(m => m === markable).getOr(markable === undefined)) { + return {}; + } + + return { + markableHolder: RefHolder.on(markable), + }; + } + + render() { + if (!this.state.markableHolder.isEmpty()) { + return ; + } + + return ; + } +} diff --git a/test/atom/marker.test.js b/test/atom/marker.test.js new file mode 100644 index 0000000000..5e462ca965 --- /dev/null +++ b/test/atom/marker.test.js @@ -0,0 +1,40 @@ +import React from 'react'; +import {mount} from 'enzyme'; + +import Marker from '../../lib/atom/marker'; +import AtomTextEditor from '../../lib/atom/atom-text-editor'; + +describe('Marker', function() { + let atomEnv, editor, markerID; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + editor = await atomEnv.workspace.open(__filename); + }); + + function setMarkerID(id) { + markerID = id; + } + + it('adds its marker on mount with default properties', function() { + mount( + , + ); + + const marker = editor.getMarker(markerID); + assert.isTrue(marker.getBufferRange().isEqual([[0, 0], [10, 0]])); + assert.strictEqual(marker.bufferMarker.invalidate, 'overlap'); + assert.isFalse(marker.isReversed()); + assert.isFalse(marker.bufferMarker.layer.maintainHistory); + }); + + it('configures its marker'); + + it('prefers marking a MarkerLayer to a TextEditor'); + + it('removes its layer on unmount'); + + it('marks an editor from a parent node'); + + it('marks a marker layer from a parent node'); +}); From e4eedd12788fdfb9a2bd8a7898f98fb76ce9d34a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 11:48:38 -0400 Subject: [PATCH 0113/4847] Refactor out an extractProps helper --- lib/atom/atom-text-editor.js | 9 ++------- lib/atom/marker-layer.js | 7 ++----- lib/atom/marker.js | 10 ++-------- lib/helpers.js | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/lib/atom/atom-text-editor.js b/lib/atom/atom-text-editor.js index f017382c71..73139403e3 100644 --- a/lib/atom/atom-text-editor.js +++ b/lib/atom/atom-text-editor.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {CompositeDisposable} from 'event-kit'; import RefHolder from '../models/ref-holder'; -import {autobind} from '../helpers'; +import {autobind, extractProps} from '../helpers'; const editorProps = { autoIndent: PropTypes.bool, @@ -106,12 +106,7 @@ export default class AtomTextEditor extends React.PureComponent { } setAttributesOnElement(theProps) { - const modelProps = Object.keys(editorProps).reduce((ps, key) => { - if (theProps[key] !== undefined) { - ps[key] = theProps[key]; - } - return ps; - }, {}); + const modelProps = extractProps(this.props, editorProps); const editor = this.getModel(); editor.update(modelProps); diff --git a/lib/atom/marker-layer.js b/lib/atom/marker-layer.js index f854ba8f4c..ea029ba343 100644 --- a/lib/atom/marker-layer.js +++ b/lib/atom/marker-layer.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {Disposable} from 'event-kit'; -import {autobind} from '../helpers'; +import {autobind, extractProps} from '../helpers'; import RefHolder from '../models/ref-holder'; import {TextEditorContext} from './atom-text-editor'; @@ -76,10 +76,7 @@ class WrappedMarkerLayer extends React.Component { this.layer.destroy(); } - const options = Object.keys(markerLayerProps).reduce((opts, propName) => { - opts[propName] = this.props[propName]; - return opts; - }, {}); + const options = extractProps(this.props, markerLayerProps); this.layer = this.state.editorHolder.map(editor => editor.addMarkerLayer(options)).getOr(null); this.props.handleID(this.getID()); diff --git a/lib/atom/marker.js b/lib/atom/marker.js index 118ea4b2b1..025cdde683 100644 --- a/lib/atom/marker.js +++ b/lib/atom/marker.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {Disposable} from 'event-kit'; import {Range, Point} from 'atom'; -import {autobind} from '../helpers'; +import {autobind, extractProps} from '../helpers'; import {RefHolderPropType} from '../prop-types'; import RefHolder from '../models/ref-holder'; @@ -25,7 +25,6 @@ const PointPropType = PropTypes.oneOfType([ ]); const markerProps = { - maintainHistory: PropTypes.bool, reversed: PropTypes.bool, invalidate: PropTypes.oneOf(['never', 'surround', 'overlap', 'inside', 'touch']), }; @@ -86,12 +85,7 @@ class WrappedMarker extends React.Component { this.marker.destroy(); } - const options = Object.keys(markerProps).reduce((opts, propName) => { - if (this.props[propName] !== undefined) { - opts[propName] = this.props[propName]; - } - return opts; - }, {}); + const options = extractProps(this.props, markerProps); this.marker = this.props.markableHolder.map(markable => { if (this.props.bufferRange) { diff --git a/lib/helpers.js b/lib/helpers.js index c9cc420648..0a70358ceb 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -14,6 +14,38 @@ export function autobind(self, ...methods) { } } +// Extract a subset of props chosen from a propTypes object from a component's props to pass to a different API. +// +// Usage: +// +// ```js +// const apiProps = { +// zero: PropTypes.number.isRequired, +// one: PropTypes.string, +// two: PropTypes.object, +// }; +// +// class Component extends React.Component { +// static propTypes = { +// ...apiProps, +// extra: PropTypes.func, +// } +// +// action() { +// const options = extractProps(this.props, apiProps); +// // options contains zero, one, and two, but not extra +// } +// } +// ``` +export function extractProps(props, propTypes) { + return Object.keys(propTypes).reduce((opts, propName) => { + if (props[propName] !== undefined) { + opts[propName] = props[propName]; + } + return opts; + }, {}); +} + export function getPackageRoot() { const {resourcePath} = atom.getLoadSettings(); const currentFileWasRequiredFromSnapshot = !path.isAbsolute(__dirname); From b1499bfebc5a90e763727714474d5acd8ce29a30 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 13:07:53 -0400 Subject: [PATCH 0114/4847] Store the MarkerLayer in a RefHolder to pass it to children --- lib/atom/marker-layer.js | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/atom/marker-layer.js b/lib/atom/marker-layer.js index ea029ba343..0ff781c1e2 100644 --- a/lib/atom/marker-layer.js +++ b/lib/atom/marker-layer.js @@ -11,6 +11,8 @@ const markerLayerProps = { persistent: PropTypes.bool, }; +export const MarkerLayerContext = React.createContext(); + class WrappedMarkerLayer extends React.Component { static propTypes = { ...markerLayerProps, @@ -29,7 +31,7 @@ class WrappedMarkerLayer extends React.Component { autobind(this, 'createLayer'); this.sub = new Disposable(); - this.layer = null; + this.layerHolder = new RefHolder(); this.state = { editorHolder: RefHolder.on(this.props.editor), }; @@ -50,7 +52,11 @@ class WrappedMarkerLayer extends React.Component { } render() { - return this.props.children || null; + return ( + + {this.props.children} + + ); } componentDidUpdate(prevProps, prevState) { @@ -60,9 +66,7 @@ class WrappedMarkerLayer extends React.Component { } componentWillUnmount() { - if (this.layer) { - this.layer.destroy(); - } + this.layerHolder.map(layer => layer.destroy()); this.sub.dispose(); } @@ -72,18 +76,19 @@ class WrappedMarkerLayer extends React.Component { } createLayer() { - if (this.layer) { - this.layer.destroy(); - } + this.layerHolder.map(layer => layer.destroy()); const options = extractProps(this.props, markerLayerProps); - this.layer = this.state.editorHolder.map(editor => editor.addMarkerLayer(options)).getOr(null); + + this.layerHolder.setter( + this.state.editorHolder.map(editor => editor.addMarkerLayer(options)).getOr(null), + ); this.props.handleID(this.getID()); } getID() { - return this.layer ? this.layer.id : undefined; + return this.layerHolder.map(layer => layer.id).getOr(undefined); } } From 439733ef05a11ce36dfe0710f36de207b43f02b3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 13:08:14 -0400 Subject: [PATCH 0115/4847] Destroy the atomEnv when we're done with it --- test/atom/marker-layer.test.js | 4 ++++ test/atom/marker.test.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/test/atom/marker-layer.test.js b/test/atom/marker-layer.test.js index ec758d5dd1..6fe699f2a1 100644 --- a/test/atom/marker-layer.test.js +++ b/test/atom/marker-layer.test.js @@ -12,6 +12,10 @@ describe('MarkerLayer', function() { editor = await atomEnv.workspace.open(__filename); }); + afterEach(function() { + atomEnv.destroy(); + }); + function setLayerID(id) { layerID = id; } diff --git a/test/atom/marker.test.js b/test/atom/marker.test.js index 5e462ca965..ef6f9616d6 100644 --- a/test/atom/marker.test.js +++ b/test/atom/marker.test.js @@ -12,6 +12,10 @@ describe('Marker', function() { editor = await atomEnv.workspace.open(__filename); }); + afterEach(function() { + atomEnv.destroy(); + }); + function setMarkerID(id) { markerID = id; } From 0d8623011ca9c9809810e42c26d2259fa633c194 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 13:09:13 -0400 Subject: [PATCH 0116/4847] Create Markers on a containing MarkerLayer or AtomTextEditor --- lib/atom/marker.js | 68 ++++++++++++++++++++++--------------- test/atom/marker.test.js | 72 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 107 insertions(+), 33 deletions(-) diff --git a/lib/atom/marker.js b/lib/atom/marker.js index 025cdde683..6900e0aadf 100644 --- a/lib/atom/marker.js +++ b/lib/atom/marker.js @@ -6,6 +6,8 @@ import {Range, Point} from 'atom'; import {autobind, extractProps} from '../helpers'; import {RefHolderPropType} from '../prop-types'; import RefHolder from '../models/ref-holder'; +import {TextEditorContext} from './atom-text-editor'; +import {MarkerLayerContext} from './marker-layer'; const MarkablePropType = PropTypes.shape({ markBufferRange: PropTypes.func.isRequired, @@ -51,7 +53,7 @@ class WrappedMarker extends React.Component { autobind(this, 'createMarker'); this.sub = new Disposable(); - this.marker = null; + this.markerHolder = new RefHolder(); } componentDidMount() { @@ -69,9 +71,7 @@ class WrappedMarker extends React.Component { } componentWillUnmount() { - if (this.marker) { - this.marker.destroy(); - } + this.markerHolder.map(marker => marker.destroy()); this.sub.dispose(); } @@ -81,35 +81,33 @@ class WrappedMarker extends React.Component { } createMarker() { - if (this.marker) { - this.marker.destroy(); - } + this.markerHolder.map(marker => marker.destroy()); const options = extractProps(this.props, markerProps); - this.marker = this.props.markableHolder.map(markable => { - if (this.props.bufferRange) { - return markable.markBufferRange(this.props.bufferRange, options); - } + this.markerHolder.setter( + this.props.markableHolder.map(markable => { + if (this.props.bufferRange) { + return markable.markBufferRange(this.props.bufferRange, options); + } - if (this.props.screenRange) { - return markable.markScreenRange(this.props.screenRange, options); - } + if (this.props.screenRange) { + return markable.markScreenRange(this.props.screenRange, options); + } - if (this.props.bufferPosition) { - return markable.markBufferPosition(this.props.bufferPosition, options); - } + if (this.props.bufferPosition) { + return markable.markBufferPosition(this.props.bufferPosition, options); + } - if (this.props.screenPosition) { - return markable.markScreenPosition(this.props.screenPosition, options); - } + if (this.props.screenPosition) { + return markable.markScreenPosition(this.props.screenPosition, options); + } - throw new Error('Expected one of bufferRange, screenRange, bufferPosition, or screenPosition to be set'); - }).getOr(null); + throw new Error('Expected one of bufferRange, screenRange, bufferPosition, or screenPosition to be set'); + }).getOr(null), + ); - if (this.marker) { - this.props.handleID(this.marker.id); - } + this.markerHolder.map(marker => this.props.handleID(marker.id)); } } @@ -141,9 +139,25 @@ export default class Marker extends React.Component { render() { if (!this.state.markableHolder.isEmpty()) { - return ; + return ; } - return ; + /* eslint-disable react/jsx-key */ + return ( + + {layerHolder => { + if (layerHolder) { + return ; + } else { + return ( + + {editorHolder => } + + ); + } + }} + + ); + /* eslint-enable react/jsx-key */ } } diff --git a/test/atom/marker.test.js b/test/atom/marker.test.js index ef6f9616d6..b965b0018d 100644 --- a/test/atom/marker.test.js +++ b/test/atom/marker.test.js @@ -3,6 +3,7 @@ import {mount} from 'enzyme'; import Marker from '../../lib/atom/marker'; import AtomTextEditor from '../../lib/atom/atom-text-editor'; +import MarkerLayer from '../../lib/atom/marker-layer'; describe('Marker', function() { let atomEnv, editor, markerID; @@ -29,16 +30,75 @@ describe('Marker', function() { assert.isTrue(marker.getBufferRange().isEqual([[0, 0], [10, 0]])); assert.strictEqual(marker.bufferMarker.invalidate, 'overlap'); assert.isFalse(marker.isReversed()); - assert.isFalse(marker.bufferMarker.layer.maintainHistory); }); - it('configures its marker'); + it('configures its marker', function() { + mount( + , + ); + + const marker = editor.getMarker(markerID); + assert.isTrue(marker.getScreenRange().isEqual([[1, 2], [3, 4]])); + assert.isTrue(marker.isReversed()); + assert.strictEqual(marker.bufferMarker.invalidate, 'never'); + }); + + it('prefers marking a MarkerLayer to a TextEditor', function() { + const layer = editor.addMarkerLayer(); + + mount( + , + ); - it('prefers marking a MarkerLayer to a TextEditor'); + const marker = layer.getMarker(markerID); + assert.strictEqual(marker.layer, layer); + }); - it('removes its layer on unmount'); + it('destroys its marker on unmount', function() { + const wrapper = mount(); - it('marks an editor from a parent node'); + assert.isDefined(editor.getMarker(markerID)); + wrapper.unmount(); + assert.isUndefined(editor.getMarker(markerID)); + }); - it('marks a marker layer from a parent node'); + it('marks an editor from a parent node', function() { + const wrapper = mount( + + + , + ); + + const theEditor = wrapper.instance().getModel(); + const marker = theEditor.getMarker(markerID); + assert.isTrue(marker.getBufferRange().isEqual([[0, 0], [0, 0]])); + }); + + it('marks a marker layer from a parent node', function() { + let layerID; + const wrapper = mount( + + { layerID = id; }}> + + + , + ); + + const theEditor = wrapper.instance().getModel(); + const layer = theEditor.getMarkerLayer(layerID); + const marker = layer.getMarker(markerID); + assert.isTrue(marker.getBufferRange().isEqual([[0, 0], [0, 0]])); + }); }); From ea4631d457e0a5c2412285e2b799aa9f5aa4a019 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 13:16:59 -0400 Subject: [PATCH 0117/4847] Mocha doesn't heart arrow functions --- test/atom/decoration.test.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/test/atom/decoration.test.js b/test/atom/decoration.test.js index 32ca70513d..14bf96db49 100644 --- a/test/atom/decoration.test.js +++ b/test/atom/decoration.test.js @@ -4,10 +4,10 @@ import {mount} from 'enzyme'; import Decoration from '../../lib/atom/decoration'; -describe('Decoration', () => { +describe('Decoration', function() { let atomEnv, editor, marker; - beforeEach(async () => { + beforeEach(async function() { atomEnv = global.buildAtomEnvironment(); const workspace = atomEnv.workspace; @@ -15,9 +15,11 @@ describe('Decoration', () => { marker = editor.markBufferRange([[2, 0], [6, 0]]); }); - afterEach(() => atomEnv.destroy()); + afterEach(function() { + atomEnv.destroy(); + }); - it('decorates its marker on render', () => { + it('decorates its marker on render', function() { const app = ( { assert.lengthOf(editor.getLineDecorations({position: 'head', class: 'something'}), 1); }); - describe('with a subtree', () => { - beforeEach(() => { + describe('with a subtree', function() { + beforeEach(function() { sinon.spy(editor, 'decorateMarker'); }); - it('creates a block decoration', () => { + it('creates a block decoration', function() { const app = (
@@ -55,7 +57,7 @@ describe('Decoration', () => { assert.equal(child.textContent, 'This is a subtree'); }); - it('creates an overlay decoration', () => { + it('creates an overlay decoration', function() { const app = (
@@ -73,7 +75,7 @@ describe('Decoration', () => { assert.equal(child.textContent, 'This is a subtree'); }); - it('creates a gutter decoration', () => { + it('creates a gutter decoration', function() { const app = (
@@ -92,7 +94,7 @@ describe('Decoration', () => { }); }); - it('destroys its decoration on unmount', () => { + it('destroys its decoration on unmount', function() { const app = ( Date: Tue, 5 Jun 2018 14:01:01 -0400 Subject: [PATCH 0118/4847] Find a Decoration's editor and marker from React context --- lib/atom/decoration.js | 152 +++++++++++++++++++++++------------ lib/atom/marker.js | 8 +- test/atom/decoration.test.js | 15 ++++ 3 files changed, 124 insertions(+), 51 deletions(-) diff --git a/lib/atom/decoration.js b/lib/atom/decoration.js index 2f2dd93f75..121f9c46ed 100644 --- a/lib/atom/decoration.js +++ b/lib/atom/decoration.js @@ -1,15 +1,18 @@ import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; -import {CompositeDisposable} from 'event-kit'; +import {Disposable} from 'event-kit'; -import {createItem} from '../helpers'; +import {createItem, autobind} from '../helpers'; import {RefHolderPropType} from '../prop-types'; +import {TextEditorContext} from './atom-text-editor'; +import {MarkerContext} from './marker'; +import RefHolder from '../models/ref-holder'; -export default class Decoration extends React.Component { +class WrappedDecoration extends React.Component { static propTypes = { - editor: PropTypes.object.isRequired, - marker: PropTypes.object.isRequired, + editorHolder: RefHolderPropType.isRequired, + markerHolder: RefHolderPropType.isRequired, type: PropTypes.oneOf(['line', 'line-number', 'highlight', 'overlay', 'gutter', 'block']).isRequired, position: PropTypes.oneOf(['head', 'tail', 'before', 'after']), className: PropTypes.string, @@ -26,10 +29,14 @@ export default class Decoration extends React.Component { constructor(props, context) { super(props, context); - this.decoration = null; - this.subscriptions = new CompositeDisposable(); + autobind(this, 'observeParents'); + + this.decorationHolder = new RefHolder(); + this.editorSub = new Disposable(); + this.markerSub = new Disposable(); this.domNode = null; + this.item = null; if (['gutter', 'overlay', 'block'].includes(this.props.type)) { this.domNode = document.createElement('div'); this.domNode.className = 'react-atom-decoration'; @@ -41,40 +48,20 @@ export default class Decoration extends React.Component { } componentDidMount() { - this.setupDecoration(); + this.editorSub = this.props.editorHolder.observe(this.observeParents); + this.markerSub = this.props.markerHolder.observe(this.observeParents); } - shouldComponentUpdate(nextProps) { - if ( - this.props.editor !== nextProps.editor || - this.props.marker !== nextProps.marker || - this.props.type !== nextProps.type || - this.props.position !== nextProps.position || - this.props.className !== nextProps.className || - this.props.children !== nextProps.children - ) { return true; } - - // Compare additional options. - const optionKeys = Object.keys(this.props.options); - const nextOptionKeys = Object.keys(nextProps.options); - - if (optionKeys.length !== nextOptionKeys.length) { - return true; - } else { - for (let i = 0; i < optionKeys.length; i++) { - const key = optionKeys[i]; - if (this.props.options[key] !== nextProps.options[key]) { - return true; - } - } + componentDidUpdate(prevProps) { + if (this.props.editorHolder !== prevProps.editorHolder) { + this.editorSub.dispose(); + this.editorSub = this.state.editorHolder.observe(this.observeParents); } - return false; - } - - componentDidUpdate() { - this.decoration && this.decoration.destroy(); - this.setupDecoration(); + if (this.props.markerHolder !== prevProps.markerHolder) { + this.markerSub.dispose(); + this.markerSub = this.state.markerHolder.observe(this.observeParents); + } } render() { @@ -88,14 +75,19 @@ export default class Decoration extends React.Component { } } - setupDecoration() { - if (this.decoration) { + observeParents() { + if (this.props.editorHolder.isEmpty() || this.props.markerHolder.isEmpty()) { return; } - let item = null; - if (this.usesItem()) { - item = createItem(this.domNode, this.props.itemHolder); + this.createDecoration(); + } + + createDecoration() { + this.decorationHolder.map(decoration => decoration.destroy()); + + if (!this.item) { + this.item = createItem(this.domNode, this.props.itemHolder); } const options = { @@ -103,18 +95,78 @@ export default class Decoration extends React.Component { type: this.props.type, position: this.props.position, class: this.props.className, - item, + item: this.item, }; - this.decoration = this.props.editor.decorateMarker(this.props.marker, options); - this.subscriptions.add(this.decoration.onDidDestroy(() => { - this.decoration = null; - this.subscriptions.dispose(); - })); + const editor = this.props.editorHolder.get(); + const marker = this.props.markerHolder.get(); + + this.decorationHolder.setter( + editor.decorateMarker(marker, options), + ); } componentWillUnmount() { - this.decoration && this.decoration.destroy(); - this.subscriptions.dispose(); + this.decorationHolder.map(decoration => decoration.destroy()); + this.editorSub.dispose(); + this.markerSub.dispose(); + } +} + +export default class Decoration extends React.Component { + static propTypes = { + editor: PropTypes.object, + marker: PropTypes.object, + } + + constructor(props) { + super(props); + + this.state = { + editorHolder: RefHolder.on(this.props.editor), + markerHolder: RefHolder.on(this.props.marker), + }; + } + + static getDerivedStateFromProps(props, state) { + const editorChanged = state.editorHolder.map(editor => editor !== props.editor).getOr(props.editor !== undefined); + const markerChanged = state.markerHolder.map(marker => marker !== props.marker).getOr(props.marker !== undefined); + + if (!editorChanged && !markerChanged) { + return null; + } + + const nextState = {}; + if (editorChanged) { + nextState.editorHolder = RefHolder.on(props.editor); + } + if (markerChanged) { + nextState.markerHolder = RefHolder.on(props.marker); + } + return nextState; + } + + render() { + if (!this.state.editorHolder.isEmpty() && !this.state.markerHolder.isEmpty()) { + return ( + + ); + } + + return ( + + {editorHolder => ( + + {markerHolder => ( + + )} + + )} + + ); } } diff --git a/lib/atom/marker.js b/lib/atom/marker.js index 6900e0aadf..34ed5db4f4 100644 --- a/lib/atom/marker.js +++ b/lib/atom/marker.js @@ -31,6 +31,8 @@ const markerProps = { invalidate: PropTypes.oneOf(['never', 'surround', 'overlap', 'inside', 'touch']), }; +export const MarkerContext = React.createContext(); + class WrappedMarker extends React.Component { static propTypes = { ...markerProps, @@ -61,7 +63,11 @@ class WrappedMarker extends React.Component { } render() { - return this.props.children || null; + return ( + + {this.props.children} + + ); } componentDidUpdate(prevProps) { diff --git a/test/atom/decoration.test.js b/test/atom/decoration.test.js index 14bf96db49..45feeaee37 100644 --- a/test/atom/decoration.test.js +++ b/test/atom/decoration.test.js @@ -3,6 +3,8 @@ import sinon from 'sinon'; import {mount} from 'enzyme'; import Decoration from '../../lib/atom/decoration'; +import AtomTextEditor from '../../lib/atom/atom-text-editor'; +import Marker from '../../lib/atom/marker'; describe('Decoration', function() { let atomEnv, editor, marker; @@ -111,4 +113,17 @@ describe('Decoration', function() { assert.lengthOf(editor.getLineDecorations({class: 'whatever'}), 0); }); + + it('decorates a parent Marker', function() { + const wrapper = mount( + + + + + , + ); + const theEditor = wrapper.instance().getModel(); + + assert.lengthOf(theEditor.getLineDecorations({position: 'head', class: 'whatever'}), 1); + }); }); From c1da7f1db7ee12802ac524cfc2602e2c978be878 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Jun 2018 14:27:35 -0400 Subject: [PATCH 0119/4847] :art: spelling --- lib/models/repository-states/present.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index bd8c2fb7c9..44ec3099e9 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -787,7 +787,7 @@ function buildHunksFromDiff(diff) { } else if (status === 'nonewline') { hunkLine = new HunkLine(text.substr(1), status, -1, -1, diffLineNumber++); } else { - throw new Error(`unknow status type: ${status}`); + throw new Error(`unknown status type: ${status}`); } return hunkLine; }); From 8a9a17f57528353309af8ead46b9ab4b610c6f81 Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 6 Jun 2018 08:16:22 +0900 Subject: [PATCH 0120/4847] Add pane mockup --- docs/rfcs/004-issueish-list.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index d5cb404716..5bcfbc4107 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -61,7 +61,7 @@ For a pull request, the issueish pane shows: * Reaction emoji and counts. * Details and links for all status checks. -_TBD: Issueish pane item design_ +![pane](https://user-images.githubusercontent.com/378023/41007657-cfc8d3c0-6961-11e8-9bf7-7d5b7353199c.png) ## Drawbacks From 0e84984eaf3bf4324a85436f3c0f251d2207d1cd Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 6 Jun 2018 08:18:19 +0900 Subject: [PATCH 0121/4847] Update pane title --- docs/rfcs/004-issueish-list.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index 5bcfbc4107..c37724d0fb 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -61,7 +61,7 @@ For a pull request, the issueish pane shows: * Reaction emoji and counts. * Details and links for all status checks. -![pane](https://user-images.githubusercontent.com/378023/41007657-cfc8d3c0-6961-11e8-9bf7-7d5b7353199c.png) +![pane](https://user-images.githubusercontent.com/378023/41007709-0f9ba9a0-6962-11e8-8b2f-bf6aee8cf8fc.png) ## Drawbacks From 2e133b91f65c35914d27455ef88c6b550af35a93 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 6 Jun 2018 07:17:06 +0000 Subject: [PATCH 0122/4847] chore(package): update sinon to version 5.1.0 Closes #1442 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6534aefe4a..39bda68bd6 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "mocha-stress": "1.0.0", "node-fetch": "2.1.2", "relay-compiler": "1.6.0", - "sinon": "5.0.10", + "sinon": "5.1.0", "test-until": "1.1.1" }, "consumedServices": { From db263ce30317c2f672bc35726361ca2d50834e05 Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 6 Jun 2018 19:47:51 +0900 Subject: [PATCH 0123/4847] Update PR detail pane --- docs/rfcs/004-issueish-list.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index c37724d0fb..fe19cf55e9 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -50,18 +50,24 @@ For a pull request, the issueish pane shows: * Author avatar * Title +* Link to .com. -> [atom/github#1503](https://github.com/atom/github/pull/1503) +* PR status badge. -> `Open`. +* Branches -> `master` < `aw/rfc-pr-list` +* `Commits` with count, links to .com (for now) +* `Checks` with count, links to .com (for now) +* `Files changed` with count, links to .com (for now) + * Plus a "Checkout" button to fetch (if necessary) and check out the pull request. Only enabled if the current pull request is not the current one. +* `Conversation` with comment count. + * Reaction emoji and counts. + * Full description as rendered markdown. + * Comments as rendered markdown. * Controls for actions: - * "Checkout" to fetch (if necessary) and check out the pull request. Only enabled if the current pull request is not the current one. - * "Browse" to launch a browser on the corresponding GitHub page. - * "Merge" to merge the pull request on GitHub if it is open. + * Mergability status -> `Able to merge`, links to the [Merging controls at the bottom](https://github.com/atom/github/pull/1503#partial-pull-merging) + * "Merge PR" to merge the pull request on GitHub if it is open. * "Close" to close the pull request, unmerged, if it is open. - * "Re-open" to re-open a pull request if it is closed. -* Pull request overview details: commit count, files changed. -* Full description as rendered markdown. -* Reaction emoji and counts. -* Details and links for all status checks. + * "Re-open PR" to re-open a pull request if it is closed. -![pane](https://user-images.githubusercontent.com/378023/41007709-0f9ba9a0-6962-11e8-8b2f-bf6aee8cf8fc.png) +![pane](https://user-images.githubusercontent.com/378023/41033008-0900b4ec-69c0-11e8-9def-68e6f5b40901.png) ## Drawbacks From d83ebfed9a85b9724ed58990a63003368b098d8e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Jun 2018 08:36:42 -0400 Subject: [PATCH 0124/4847] Trigger refModel after the has been initialized --- lib/atom/atom-text-editor.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/atom/atom-text-editor.js b/lib/atom/atom-text-editor.js index 73139403e3..ab7eedf561 100644 --- a/lib/atom/atom-text-editor.js +++ b/lib/atom/atom-text-editor.js @@ -61,10 +61,6 @@ export default class AtomTextEditor extends React.PureComponent { this.refElement = new RefHolder(); this.refModel = new RefHolder(); - - this.subs.add( - this.refElement.observe(element => this.refModel.setter(element.getModel())), - ); } render() { @@ -81,11 +77,19 @@ export default class AtomTextEditor extends React.PureComponent { componentDidMount() { this.setAttributesOnElement(this.props); - const editor = this.getModel(); - this.subs.add( - editor.onDidChange(this.didChange), - editor.onDidChangeCursorPosition(this.didChangeCursorPosition), - ); + this.refElement.map(element => { + const editor = element.getModel(); + + this.refModel.setter(editor); + + this.subs.add( + editor.onDidChange(this.didChange), + editor.onDidChangeCursorPosition(this.didChangeCursorPosition), + ); + + // shhh, eslint. shhhh + return null; + }); } componentDidUpdate(prevProps) { From f04bb7d18b5c18f64719a7f22f7e4a5c06627166 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Jun 2018 09:14:30 -0400 Subject: [PATCH 0125/4847] It begins --- lib/containers/file-patch-container.js | 53 ++ lib/controllers/file-patch-controller.js | 543 +------------- lib/controllers/file-patch-controller.old.js | 550 ++++++++++++++ lib/controllers/root-controller.js | 24 +- lib/items/file-patch-item.js | 91 +++ lib/views/file-patch-view.js | 717 ++----------------- lib/views/file-patch-view.old.js | 716 ++++++++++++++++++ 7 files changed, 1462 insertions(+), 1232 deletions(-) create mode 100644 lib/containers/file-patch-container.js create mode 100644 lib/controllers/file-patch-controller.old.js create mode 100644 lib/items/file-patch-item.js create mode 100644 lib/views/file-patch-view.old.js diff --git a/lib/containers/file-patch-container.js b/lib/containers/file-patch-container.js new file mode 100644 index 0000000000..9e5d5a4eee --- /dev/null +++ b/lib/containers/file-patch-container.js @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import yubikiri from 'yubikiri'; + +import {autobind} from '../helpers'; +import ObserveModel from '../views/observe-model'; +import FilePatchController from '../controllers/file-patch-controller'; + +export default class FilePatchContainer extends React.Component { + static propTypes = { + repository: PropTypes.object.isRequired, + stagingStatus: PropTypes.oneOf(['staged', 'unstaged']), + relPath: PropTypes.string.isRequired, + + tooltips: PropTypes.object.isRequired, + } + + constructor(props) { + super(props); + + autobind(this, 'fetchData', 'renderWithData'); + } + + fetchData(repository) { + return yubikiri({ + filePatch: repository.getFilePatchForPath(this.props.relPath, {staged: this.props.stagingStatus === 'staged'}), + isPartiallyStaged: repository.isPartiallyStaged(this.props.relPath), + }); + } + + render() { + return ( + + {this.renderWithData} + + ); + } + + renderWithData(data) { + if (data === null) { + return null; + } + + return ( + + ); + } +} diff --git a/lib/controllers/file-patch-controller.js b/lib/controllers/file-patch-controller.js index 90d6a67df8..3df858ab0a 100644 --- a/lib/controllers/file-patch-controller.js +++ b/lib/controllers/file-patch-controller.js @@ -1,550 +1,9 @@ -import path from 'path'; import React from 'react'; -import PropTypes from 'prop-types'; -import {Point} from 'atom'; -import {Emitter, CompositeDisposable} from 'event-kit'; -import Switchboard from '../switchboard'; import FilePatchView from '../views/file-patch-view'; -import ModelObserver from '../models/model-observer'; -import {autobind} from '../helpers'; export default class FilePatchController extends React.Component { - static propTypes = { - largeDiffByteThreshold: PropTypes.number, - getRepositoryForWorkdir: PropTypes.func.isRequired, - workingDirectoryPath: PropTypes.string.isRequired, - commandRegistry: PropTypes.object.isRequired, - deserializers: PropTypes.object.isRequired, - tooltips: PropTypes.object.isRequired, - filePath: PropTypes.string.isRequired, - lineNumber: PropTypes.number, - initialStagingStatus: PropTypes.oneOf(['unstaged', 'staged']).isRequired, - discardLines: PropTypes.func.isRequired, - didSurfaceFile: PropTypes.func.isRequired, - quietlySelectItem: PropTypes.func.isRequired, - undoLastDiscard: PropTypes.func.isRequired, - openFiles: PropTypes.func.isRequired, - switchboard: PropTypes.instanceOf(Switchboard), - } - - static defaultProps = { - largeDiffByteThreshold: 32768, - switchboard: new Switchboard(), - } - - static uriPattern = 'atom-github://file-patch/{relpath...}?workdir={workdir}&stagingStatus={stagingStatus}' - - static buildURI(relPath, workdir, stagingStatus) { - return 'atom-github://file-patch/' + - relPath + - `?workdir=${encodeURIComponent(workdir)}` + - `&stagingStatus=${encodeURIComponent(stagingStatus)}`; - } - - static confirmedLargeFilePatches = new Set() - - static resetConfirmedLargeFilePatches() { - this.confirmedLargeFilePatches = new Set(); - } - - constructor(props, context) { - super(props, context); - autobind( - this, - 'onRepoRefresh', 'handleShowDiffClick', 'attemptHunkStageOperation', 'attemptFileStageOperation', - 'attemptModeStageOperation', 'attemptSymlinkStageOperation', 'attemptLineStageOperation', 'didSurfaceFile', - 'diveIntoCorrespondingFilePatch', 'focus', 'openCurrentFile', 'discardLines', 'undoLastDiscard', 'hasUndoHistory', - ); - - this.stagingOperationInProgress = false; - this.emitter = new Emitter(); - - this.state = { - filePatch: null, - stagingStatus: props.initialStagingStatus, - isPartiallyStaged: false, - }; - - this.repositoryObserver = new ModelObserver({ - didUpdate: repo => this.onRepoRefresh(repo), - }); - this.repositoryObserver.setActiveModel(props.getRepositoryForWorkdir(this.props.workingDirectoryPath)); - - this.filePatchLoadedPromise = new Promise(res => { - this.resolveFilePatchLoadedPromise = res; - }); - - this.subscriptions = new CompositeDisposable(); - this.subscriptions.add( - this.props.switchboard.onDidFinishActiveContextUpdate(() => { - this.repositoryObserver.setActiveModel(this.props.getRepositoryForWorkdir(this.props.workingDirectoryPath)); - }), - ); - } - - getFilePatchLoadedPromise() { - return this.filePatchLoadedPromise; - } - - getStagingStatus() { - return this.state.stagingStatus; - } - - getFilePath() { - return this.props.filePath; - } - - getWorkingDirectory() { - return this.props.workingDirectoryPath; - } - - getTitle() { - let title = this.isStaged() ? 'Staged' : 'Unstaged'; - title += ' Changes: '; - title += this.props.filePath; - return title; - } - - serialize() { - return { - deserializer: 'FilePatchControllerStub', - uri: this.getURI(), - }; - } - - onDidDestroy(callback) { - return this.emitter.on('did-destroy', callback); - } - - terminatePendingState() { - if (!this.hasTerminatedPendingState) { - this.emitter.emit('did-terminate-pending-state'); - this.hasTerminatedPendingState = true; - } - } - - onDidTerminatePendingState(callback) { - return this.emitter.on('did-terminate-pending-state', callback); - } - - async onRepoRefresh(repository) { - const staged = this.isStaged(); - let filePatch = await this.getFilePatchForPath(this.props.filePath, staged); - const isPartiallyStaged = await repository.isPartiallyStaged(this.props.filePath); - - const onFinish = () => { - this.props.switchboard.didFinishRepositoryRefresh(); - }; - - if (filePatch) { - this.resolveFilePatchLoadedPromise(); - if (!this.destroyed) { - this.setState({filePatch, isPartiallyStaged}, onFinish); - } else { - onFinish(); - } - } else { - const oldFilePatch = this.state.filePatch; - if (oldFilePatch) { - filePatch = oldFilePatch.clone({ - oldFile: oldFilePatch.oldFile.clone({mode: null, symlink: null}), - newFile: oldFilePatch.newFile.clone({mode: null, symlink: null}), - patch: oldFilePatch.getPatch().clone({hunks: []}), - }); - if (!this.destroyed) { - this.setState({filePatch, isPartiallyStaged}, onFinish); - } else { - onFinish(); - } - } - } - } - - getFilePatchForPath(filePath, staged) { - const repository = this.repositoryObserver.getActiveModel(); - return repository.getFilePatchForPath(filePath, {staged}); - } - - componentDidUpdate(_prevProps, prevState) { - if (prevState.stagingStatus !== this.state.stagingStatus) { - this.emitter.emit('did-change-title'); - } - } - - goToDiffLine(lineNumber) { - this.filePatchView.goToDiffLine(lineNumber); - } - - componentWillUnmount() { - this.destroy(); - } - render() { - const fp = this.state.filePatch; - const hunks = fp ? fp.getHunks() : []; - const executableModeChange = fp && fp.didChangeExecutableMode() ? - {oldMode: fp.getOldMode(), newMode: fp.getNewMode()} : - null; - const symlinkChange = fp && fp.hasSymlink() ? - { - oldSymlink: fp.getOldSymlink(), - newSymlink: fp.getNewSymlink(), - typechange: fp.hasTypechange(), - filePatchStatus: fp.getStatus(), - } : null; - const repository = this.repositoryObserver.getActiveModel(); - if (repository.isUndetermined() || repository.isLoading()) { - return ( -
- -
- ); - } else if (repository.isAbsent()) { - return ( -
- - The repository for {this.props.workingDirectoryPath} is not open in Atom. - -
- ); - } else { - const hasUndoHistory = repository ? this.hasUndoHistory() : false; - return ( -
- { this.filePatchView = c; }} - commandRegistry={this.props.commandRegistry} - tooltips={this.props.tooltips} - displayLargeDiffMessage={!this.shouldDisplayLargeDiff(this.state.filePatch)} - byteCount={this.byteCount} - handleShowDiffClick={this.handleShowDiffClick} - hunks={hunks} - executableModeChange={executableModeChange} - symlinkChange={symlinkChange} - filePath={this.props.filePath} - workingDirectoryPath={this.getWorkingDirectory()} - stagingStatus={this.state.stagingStatus} - isPartiallyStaged={this.state.isPartiallyStaged} - attemptLineStageOperation={this.attemptLineStageOperation} - attemptHunkStageOperation={this.attemptHunkStageOperation} - attemptFileStageOperation={this.attemptFileStageOperation} - attemptModeStageOperation={this.attemptModeStageOperation} - attemptSymlinkStageOperation={this.attemptSymlinkStageOperation} - didSurfaceFile={this.didSurfaceFile} - didDiveIntoCorrespondingFilePatch={this.diveIntoCorrespondingFilePatch} - switchboard={this.props.switchboard} - openCurrentFile={this.openCurrentFile} - discardLines={this.discardLines} - undoLastDiscard={this.undoLastDiscard} - hasUndoHistory={hasUndoHistory} - lineNumber={this.props.lineNumber} - /> -
- ); - } - } - - shouldDisplayLargeDiff(filePatch) { - if (!filePatch) { return true; } - - const fullPath = path.join(this.getWorkingDirectory(), this.props.filePath); - if (FilePatchController.confirmedLargeFilePatches.has(fullPath)) { - return true; - } - - this.byteCount = filePatch.getByteSize(); - return this.byteCount < this.props.largeDiffByteThreshold; - } - - onDidChangeTitle(callback) { - return this.emitter.on('did-change-title', callback); - } - - handleShowDiffClick() { - if (this.repositoryObserver.getActiveModel()) { - const fullPath = path.join(this.getWorkingDirectory(), this.props.filePath); - FilePatchController.confirmedLargeFilePatches.add(fullPath); - this.forceUpdate(); - } - } - - async stageHunk(hunk) { - this.props.switchboard.didBeginStageOperation({stage: true, hunk: true}); - - await this.repositoryObserver.getActiveModel().applyPatchToIndex( - this.state.filePatch.getStagePatchForHunk(hunk), - ); - - this.props.switchboard.didFinishStageOperation({stage: true, hunk: true}); - } - - async unstageHunk(hunk) { - this.props.switchboard.didBeginStageOperation({unstage: true, hunk: true}); - - await this.repositoryObserver.getActiveModel().applyPatchToIndex( - this.state.filePatch.getUnstagePatchForHunk(hunk), - ); - - this.props.switchboard.didFinishStageOperation({unstage: true, hunk: true}); - } - - stageOrUnstageHunk(hunk) { - const stagingStatus = this.state.stagingStatus; - if (stagingStatus === 'unstaged') { - return this.stageHunk(hunk); - } else if (stagingStatus === 'staged') { - return this.unstageHunk(hunk); - } else { - throw new Error(`Unknown stagingStatus: ${stagingStatus}`); - } - } - - async stageFile() { - this.props.switchboard.didBeginStageOperation({stage: true, file: true}); - - await this.repositoryObserver.getActiveModel().stageFiles([this.props.filePath]); - this.props.switchboard.didFinishStageOperation({stage: true, file: true}); - } - - async unstageFile() { - this.props.switchboard.didBeginStageOperation({unstage: true, file: true}); - - await this.repositoryObserver.getActiveModel().unstageFiles([this.props.filePath]); - - this.props.switchboard.didFinishStageOperation({unstage: true, file: true}); - } - - stageOrUnstageFile() { - const stagingStatus = this.state.stagingStatus; - if (stagingStatus === 'unstaged') { - return this.stageFile(); - } else if (stagingStatus === 'staged') { - return this.unstageFile(); - } else { - throw new Error(`Unknown stagingStatus: ${stagingStatus}`); - } - } - - async stageModeChange(mode) { - this.props.switchboard.didBeginStageOperation({stage: true, mode: true}); - - await this.repositoryObserver.getActiveModel().stageFileModeChange( - this.props.filePath, mode, - ); - this.props.switchboard.didFinishStageOperation({stage: true, mode: true}); - } - - async unstageModeChange(mode) { - this.props.switchboard.didBeginStageOperation({unstage: true, mode: true}); - - await this.repositoryObserver.getActiveModel().stageFileModeChange( - this.props.filePath, mode, - ); - this.props.switchboard.didFinishStageOperation({unstage: true, mode: true}); - } - - stageOrUnstageModeChange() { - const stagingStatus = this.state.stagingStatus; - const oldMode = this.state.filePatch.getOldMode(); - const newMode = this.state.filePatch.getNewMode(); - if (stagingStatus === 'unstaged') { - return this.stageModeChange(newMode); - } else if (stagingStatus === 'staged') { - return this.unstageModeChange(oldMode); - } else { - throw new Error(`Unknown stagingStatus: ${stagingStatus}`); - } - } - - async stageSymlinkChange() { - this.props.switchboard.didBeginStageOperation({stage: true, symlink: true}); - - const filePatch = this.state.filePatch; - if (filePatch.hasTypechange() && filePatch.getStatus() === 'added') { - await this.repositoryObserver.getActiveModel().stageFileSymlinkChange(this.props.filePath); - } else { - await this.repositoryObserver.getActiveModel().stageFiles([this.props.filePath]); - } - this.props.switchboard.didFinishStageOperation({stage: true, symlink: true}); - } - - async unstageSymlinkChange() { - this.props.switchboard.didBeginStageOperation({unstage: true, symlink: true}); - - const filePatch = this.state.filePatch; - if (filePatch.hasTypechange() && filePatch.getStatus() === 'deleted') { - await this.repositoryObserver.getActiveModel().stageFileSymlinkChange(this.props.filePath); - } else { - await this.repositoryObserver.getActiveModel().unstageFiles([this.props.filePath]); - } - this.props.switchboard.didFinishStageOperation({unstage: true, symlink: true}); - } - - stageOrUnstageSymlinkChange() { - const stagingStatus = this.state.stagingStatus; - if (stagingStatus === 'unstaged') { - return this.stageSymlinkChange(); - } else if (stagingStatus === 'staged') { - return this.unstageSymlinkChange(); - } else { - throw new Error(`Unknown stagingStatus: ${stagingStatus}`); - } - } - - attemptHunkStageOperation(hunk) { - if (this.stagingOperationInProgress) { - return; - } - - this.stagingOperationInProgress = true; - this.props.switchboard.getChangePatchPromise().then(() => { - this.stagingOperationInProgress = false; - }); - - this.stageOrUnstageHunk(hunk); - } - - attemptFileStageOperation() { - if (this.stagingOperationInProgress) { - return; - } - - this.stagingOperationInProgress = true; - this.props.switchboard.getChangePatchPromise().then(() => { - this.stagingOperationInProgress = false; - }); - - this.stageOrUnstageFile(); - } - - attemptModeStageOperation() { - if (this.stagingOperationInProgress) { - return; - } - - this.stagingOperationInProgress = true; - this.props.switchboard.getChangePatchPromise().then(() => { - this.stagingOperationInProgress = false; - }); - - this.stageOrUnstageModeChange(); - } - - attemptSymlinkStageOperation() { - if (this.stagingOperationInProgress) { - return; - } - - this.stagingOperationInProgress = true; - this.props.switchboard.getChangePatchPromise().then(() => { - this.stagingOperationInProgress = false; - }); - - this.stageOrUnstageSymlinkChange(); - } - - async stageLines(lines) { - this.props.switchboard.didBeginStageOperation({stage: true, line: true}); - - await this.repositoryObserver.getActiveModel().applyPatchToIndex( - this.state.filePatch.getStagePatchForLines(lines), - ); - - this.props.switchboard.didFinishStageOperation({stage: true, line: true}); - } - - async unstageLines(lines) { - this.props.switchboard.didBeginStageOperation({unstage: true, line: true}); - - await this.repositoryObserver.getActiveModel().applyPatchToIndex( - this.state.filePatch.getUnstagePatchForLines(lines), - ); - - this.props.switchboard.didFinishStageOperation({unstage: true, line: true}); - } - - stageOrUnstageLines(lines) { - const stagingStatus = this.state.stagingStatus; - if (stagingStatus === 'unstaged') { - return this.stageLines(lines); - } else if (stagingStatus === 'staged') { - return this.unstageLines(lines); - } else { - throw new Error(`Unknown stagingStatus: ${stagingStatus}`); - } - } - - attemptLineStageOperation(lines) { - if (this.stagingOperationInProgress) { - return; - } - - this.stagingOperationInProgress = true; - this.props.switchboard.getChangePatchPromise().then(() => { - this.stagingOperationInProgress = false; - }); - - this.stageOrUnstageLines(lines); - } - - didSurfaceFile() { - if (this.props.didSurfaceFile) { - this.props.didSurfaceFile(this.props.filePath, this.state.stagingStatus); - } - } - - async diveIntoCorrespondingFilePatch() { - const stagingStatus = this.isStaged() ? 'unstaged' : 'staged'; - const filePatch = await this.getFilePatchForPath(this.props.filePath, stagingStatus === 'staged'); - this.props.quietlySelectItem(this.props.filePath, stagingStatus); - this.setState({filePatch, stagingStatus}); - } - - isStaged() { - return this.state.stagingStatus === 'staged'; - } - - isEmpty() { - return !this.state.filePatch || this.state.filePatch.getHunks().length === 0; - } - - focus() { - if (this.filePatchView) { - this.filePatchView.focus(); - } - } - - wasActivated(isStillActive) { - process.nextTick(() => { - isStillActive() && this.focus(); - }); - } - - async openCurrentFile({lineNumber} = {}) { - const [textEditor] = await this.props.openFiles([this.props.filePath]); - const position = new Point(lineNumber ? lineNumber - 1 : 0, 0); - textEditor.scrollToBufferPosition(position, {center: true}); - textEditor.setCursorBufferPosition(position); - return textEditor; - } - - discardLines(lines) { - return this.props.discardLines(this.state.filePatch, lines, this.repositoryObserver.getActiveModel()); - } - - undoLastDiscard() { - return this.props.undoLastDiscard(this.props.filePath, this.repositoryObserver.getActiveModel()); - } - - hasUndoHistory() { - return this.repositoryObserver.getActiveModel().hasDiscardHistory(this.props.filePath); - } - - destroy() { - this.destroyed = true; - this.subscriptions.dispose(); - this.repositoryObserver.destroy(); - this.emitter.emit('did-destroy'); + return ; } } diff --git a/lib/controllers/file-patch-controller.old.js b/lib/controllers/file-patch-controller.old.js new file mode 100644 index 0000000000..90d6a67df8 --- /dev/null +++ b/lib/controllers/file-patch-controller.old.js @@ -0,0 +1,550 @@ +import path from 'path'; +import React from 'react'; +import PropTypes from 'prop-types'; +import {Point} from 'atom'; +import {Emitter, CompositeDisposable} from 'event-kit'; + +import Switchboard from '../switchboard'; +import FilePatchView from '../views/file-patch-view'; +import ModelObserver from '../models/model-observer'; +import {autobind} from '../helpers'; + +export default class FilePatchController extends React.Component { + static propTypes = { + largeDiffByteThreshold: PropTypes.number, + getRepositoryForWorkdir: PropTypes.func.isRequired, + workingDirectoryPath: PropTypes.string.isRequired, + commandRegistry: PropTypes.object.isRequired, + deserializers: PropTypes.object.isRequired, + tooltips: PropTypes.object.isRequired, + filePath: PropTypes.string.isRequired, + lineNumber: PropTypes.number, + initialStagingStatus: PropTypes.oneOf(['unstaged', 'staged']).isRequired, + discardLines: PropTypes.func.isRequired, + didSurfaceFile: PropTypes.func.isRequired, + quietlySelectItem: PropTypes.func.isRequired, + undoLastDiscard: PropTypes.func.isRequired, + openFiles: PropTypes.func.isRequired, + switchboard: PropTypes.instanceOf(Switchboard), + } + + static defaultProps = { + largeDiffByteThreshold: 32768, + switchboard: new Switchboard(), + } + + static uriPattern = 'atom-github://file-patch/{relpath...}?workdir={workdir}&stagingStatus={stagingStatus}' + + static buildURI(relPath, workdir, stagingStatus) { + return 'atom-github://file-patch/' + + relPath + + `?workdir=${encodeURIComponent(workdir)}` + + `&stagingStatus=${encodeURIComponent(stagingStatus)}`; + } + + static confirmedLargeFilePatches = new Set() + + static resetConfirmedLargeFilePatches() { + this.confirmedLargeFilePatches = new Set(); + } + + constructor(props, context) { + super(props, context); + autobind( + this, + 'onRepoRefresh', 'handleShowDiffClick', 'attemptHunkStageOperation', 'attemptFileStageOperation', + 'attemptModeStageOperation', 'attemptSymlinkStageOperation', 'attemptLineStageOperation', 'didSurfaceFile', + 'diveIntoCorrespondingFilePatch', 'focus', 'openCurrentFile', 'discardLines', 'undoLastDiscard', 'hasUndoHistory', + ); + + this.stagingOperationInProgress = false; + this.emitter = new Emitter(); + + this.state = { + filePatch: null, + stagingStatus: props.initialStagingStatus, + isPartiallyStaged: false, + }; + + this.repositoryObserver = new ModelObserver({ + didUpdate: repo => this.onRepoRefresh(repo), + }); + this.repositoryObserver.setActiveModel(props.getRepositoryForWorkdir(this.props.workingDirectoryPath)); + + this.filePatchLoadedPromise = new Promise(res => { + this.resolveFilePatchLoadedPromise = res; + }); + + this.subscriptions = new CompositeDisposable(); + this.subscriptions.add( + this.props.switchboard.onDidFinishActiveContextUpdate(() => { + this.repositoryObserver.setActiveModel(this.props.getRepositoryForWorkdir(this.props.workingDirectoryPath)); + }), + ); + } + + getFilePatchLoadedPromise() { + return this.filePatchLoadedPromise; + } + + getStagingStatus() { + return this.state.stagingStatus; + } + + getFilePath() { + return this.props.filePath; + } + + getWorkingDirectory() { + return this.props.workingDirectoryPath; + } + + getTitle() { + let title = this.isStaged() ? 'Staged' : 'Unstaged'; + title += ' Changes: '; + title += this.props.filePath; + return title; + } + + serialize() { + return { + deserializer: 'FilePatchControllerStub', + uri: this.getURI(), + }; + } + + onDidDestroy(callback) { + return this.emitter.on('did-destroy', callback); + } + + terminatePendingState() { + if (!this.hasTerminatedPendingState) { + this.emitter.emit('did-terminate-pending-state'); + this.hasTerminatedPendingState = true; + } + } + + onDidTerminatePendingState(callback) { + return this.emitter.on('did-terminate-pending-state', callback); + } + + async onRepoRefresh(repository) { + const staged = this.isStaged(); + let filePatch = await this.getFilePatchForPath(this.props.filePath, staged); + const isPartiallyStaged = await repository.isPartiallyStaged(this.props.filePath); + + const onFinish = () => { + this.props.switchboard.didFinishRepositoryRefresh(); + }; + + if (filePatch) { + this.resolveFilePatchLoadedPromise(); + if (!this.destroyed) { + this.setState({filePatch, isPartiallyStaged}, onFinish); + } else { + onFinish(); + } + } else { + const oldFilePatch = this.state.filePatch; + if (oldFilePatch) { + filePatch = oldFilePatch.clone({ + oldFile: oldFilePatch.oldFile.clone({mode: null, symlink: null}), + newFile: oldFilePatch.newFile.clone({mode: null, symlink: null}), + patch: oldFilePatch.getPatch().clone({hunks: []}), + }); + if (!this.destroyed) { + this.setState({filePatch, isPartiallyStaged}, onFinish); + } else { + onFinish(); + } + } + } + } + + getFilePatchForPath(filePath, staged) { + const repository = this.repositoryObserver.getActiveModel(); + return repository.getFilePatchForPath(filePath, {staged}); + } + + componentDidUpdate(_prevProps, prevState) { + if (prevState.stagingStatus !== this.state.stagingStatus) { + this.emitter.emit('did-change-title'); + } + } + + goToDiffLine(lineNumber) { + this.filePatchView.goToDiffLine(lineNumber); + } + + componentWillUnmount() { + this.destroy(); + } + + render() { + const fp = this.state.filePatch; + const hunks = fp ? fp.getHunks() : []; + const executableModeChange = fp && fp.didChangeExecutableMode() ? + {oldMode: fp.getOldMode(), newMode: fp.getNewMode()} : + null; + const symlinkChange = fp && fp.hasSymlink() ? + { + oldSymlink: fp.getOldSymlink(), + newSymlink: fp.getNewSymlink(), + typechange: fp.hasTypechange(), + filePatchStatus: fp.getStatus(), + } : null; + const repository = this.repositoryObserver.getActiveModel(); + if (repository.isUndetermined() || repository.isLoading()) { + return ( +
+ +
+ ); + } else if (repository.isAbsent()) { + return ( +
+ + The repository for {this.props.workingDirectoryPath} is not open in Atom. + +
+ ); + } else { + const hasUndoHistory = repository ? this.hasUndoHistory() : false; + return ( +
+ { this.filePatchView = c; }} + commandRegistry={this.props.commandRegistry} + tooltips={this.props.tooltips} + displayLargeDiffMessage={!this.shouldDisplayLargeDiff(this.state.filePatch)} + byteCount={this.byteCount} + handleShowDiffClick={this.handleShowDiffClick} + hunks={hunks} + executableModeChange={executableModeChange} + symlinkChange={symlinkChange} + filePath={this.props.filePath} + workingDirectoryPath={this.getWorkingDirectory()} + stagingStatus={this.state.stagingStatus} + isPartiallyStaged={this.state.isPartiallyStaged} + attemptLineStageOperation={this.attemptLineStageOperation} + attemptHunkStageOperation={this.attemptHunkStageOperation} + attemptFileStageOperation={this.attemptFileStageOperation} + attemptModeStageOperation={this.attemptModeStageOperation} + attemptSymlinkStageOperation={this.attemptSymlinkStageOperation} + didSurfaceFile={this.didSurfaceFile} + didDiveIntoCorrespondingFilePatch={this.diveIntoCorrespondingFilePatch} + switchboard={this.props.switchboard} + openCurrentFile={this.openCurrentFile} + discardLines={this.discardLines} + undoLastDiscard={this.undoLastDiscard} + hasUndoHistory={hasUndoHistory} + lineNumber={this.props.lineNumber} + /> +
+ ); + } + } + + shouldDisplayLargeDiff(filePatch) { + if (!filePatch) { return true; } + + const fullPath = path.join(this.getWorkingDirectory(), this.props.filePath); + if (FilePatchController.confirmedLargeFilePatches.has(fullPath)) { + return true; + } + + this.byteCount = filePatch.getByteSize(); + return this.byteCount < this.props.largeDiffByteThreshold; + } + + onDidChangeTitle(callback) { + return this.emitter.on('did-change-title', callback); + } + + handleShowDiffClick() { + if (this.repositoryObserver.getActiveModel()) { + const fullPath = path.join(this.getWorkingDirectory(), this.props.filePath); + FilePatchController.confirmedLargeFilePatches.add(fullPath); + this.forceUpdate(); + } + } + + async stageHunk(hunk) { + this.props.switchboard.didBeginStageOperation({stage: true, hunk: true}); + + await this.repositoryObserver.getActiveModel().applyPatchToIndex( + this.state.filePatch.getStagePatchForHunk(hunk), + ); + + this.props.switchboard.didFinishStageOperation({stage: true, hunk: true}); + } + + async unstageHunk(hunk) { + this.props.switchboard.didBeginStageOperation({unstage: true, hunk: true}); + + await this.repositoryObserver.getActiveModel().applyPatchToIndex( + this.state.filePatch.getUnstagePatchForHunk(hunk), + ); + + this.props.switchboard.didFinishStageOperation({unstage: true, hunk: true}); + } + + stageOrUnstageHunk(hunk) { + const stagingStatus = this.state.stagingStatus; + if (stagingStatus === 'unstaged') { + return this.stageHunk(hunk); + } else if (stagingStatus === 'staged') { + return this.unstageHunk(hunk); + } else { + throw new Error(`Unknown stagingStatus: ${stagingStatus}`); + } + } + + async stageFile() { + this.props.switchboard.didBeginStageOperation({stage: true, file: true}); + + await this.repositoryObserver.getActiveModel().stageFiles([this.props.filePath]); + this.props.switchboard.didFinishStageOperation({stage: true, file: true}); + } + + async unstageFile() { + this.props.switchboard.didBeginStageOperation({unstage: true, file: true}); + + await this.repositoryObserver.getActiveModel().unstageFiles([this.props.filePath]); + + this.props.switchboard.didFinishStageOperation({unstage: true, file: true}); + } + + stageOrUnstageFile() { + const stagingStatus = this.state.stagingStatus; + if (stagingStatus === 'unstaged') { + return this.stageFile(); + } else if (stagingStatus === 'staged') { + return this.unstageFile(); + } else { + throw new Error(`Unknown stagingStatus: ${stagingStatus}`); + } + } + + async stageModeChange(mode) { + this.props.switchboard.didBeginStageOperation({stage: true, mode: true}); + + await this.repositoryObserver.getActiveModel().stageFileModeChange( + this.props.filePath, mode, + ); + this.props.switchboard.didFinishStageOperation({stage: true, mode: true}); + } + + async unstageModeChange(mode) { + this.props.switchboard.didBeginStageOperation({unstage: true, mode: true}); + + await this.repositoryObserver.getActiveModel().stageFileModeChange( + this.props.filePath, mode, + ); + this.props.switchboard.didFinishStageOperation({unstage: true, mode: true}); + } + + stageOrUnstageModeChange() { + const stagingStatus = this.state.stagingStatus; + const oldMode = this.state.filePatch.getOldMode(); + const newMode = this.state.filePatch.getNewMode(); + if (stagingStatus === 'unstaged') { + return this.stageModeChange(newMode); + } else if (stagingStatus === 'staged') { + return this.unstageModeChange(oldMode); + } else { + throw new Error(`Unknown stagingStatus: ${stagingStatus}`); + } + } + + async stageSymlinkChange() { + this.props.switchboard.didBeginStageOperation({stage: true, symlink: true}); + + const filePatch = this.state.filePatch; + if (filePatch.hasTypechange() && filePatch.getStatus() === 'added') { + await this.repositoryObserver.getActiveModel().stageFileSymlinkChange(this.props.filePath); + } else { + await this.repositoryObserver.getActiveModel().stageFiles([this.props.filePath]); + } + this.props.switchboard.didFinishStageOperation({stage: true, symlink: true}); + } + + async unstageSymlinkChange() { + this.props.switchboard.didBeginStageOperation({unstage: true, symlink: true}); + + const filePatch = this.state.filePatch; + if (filePatch.hasTypechange() && filePatch.getStatus() === 'deleted') { + await this.repositoryObserver.getActiveModel().stageFileSymlinkChange(this.props.filePath); + } else { + await this.repositoryObserver.getActiveModel().unstageFiles([this.props.filePath]); + } + this.props.switchboard.didFinishStageOperation({unstage: true, symlink: true}); + } + + stageOrUnstageSymlinkChange() { + const stagingStatus = this.state.stagingStatus; + if (stagingStatus === 'unstaged') { + return this.stageSymlinkChange(); + } else if (stagingStatus === 'staged') { + return this.unstageSymlinkChange(); + } else { + throw new Error(`Unknown stagingStatus: ${stagingStatus}`); + } + } + + attemptHunkStageOperation(hunk) { + if (this.stagingOperationInProgress) { + return; + } + + this.stagingOperationInProgress = true; + this.props.switchboard.getChangePatchPromise().then(() => { + this.stagingOperationInProgress = false; + }); + + this.stageOrUnstageHunk(hunk); + } + + attemptFileStageOperation() { + if (this.stagingOperationInProgress) { + return; + } + + this.stagingOperationInProgress = true; + this.props.switchboard.getChangePatchPromise().then(() => { + this.stagingOperationInProgress = false; + }); + + this.stageOrUnstageFile(); + } + + attemptModeStageOperation() { + if (this.stagingOperationInProgress) { + return; + } + + this.stagingOperationInProgress = true; + this.props.switchboard.getChangePatchPromise().then(() => { + this.stagingOperationInProgress = false; + }); + + this.stageOrUnstageModeChange(); + } + + attemptSymlinkStageOperation() { + if (this.stagingOperationInProgress) { + return; + } + + this.stagingOperationInProgress = true; + this.props.switchboard.getChangePatchPromise().then(() => { + this.stagingOperationInProgress = false; + }); + + this.stageOrUnstageSymlinkChange(); + } + + async stageLines(lines) { + this.props.switchboard.didBeginStageOperation({stage: true, line: true}); + + await this.repositoryObserver.getActiveModel().applyPatchToIndex( + this.state.filePatch.getStagePatchForLines(lines), + ); + + this.props.switchboard.didFinishStageOperation({stage: true, line: true}); + } + + async unstageLines(lines) { + this.props.switchboard.didBeginStageOperation({unstage: true, line: true}); + + await this.repositoryObserver.getActiveModel().applyPatchToIndex( + this.state.filePatch.getUnstagePatchForLines(lines), + ); + + this.props.switchboard.didFinishStageOperation({unstage: true, line: true}); + } + + stageOrUnstageLines(lines) { + const stagingStatus = this.state.stagingStatus; + if (stagingStatus === 'unstaged') { + return this.stageLines(lines); + } else if (stagingStatus === 'staged') { + return this.unstageLines(lines); + } else { + throw new Error(`Unknown stagingStatus: ${stagingStatus}`); + } + } + + attemptLineStageOperation(lines) { + if (this.stagingOperationInProgress) { + return; + } + + this.stagingOperationInProgress = true; + this.props.switchboard.getChangePatchPromise().then(() => { + this.stagingOperationInProgress = false; + }); + + this.stageOrUnstageLines(lines); + } + + didSurfaceFile() { + if (this.props.didSurfaceFile) { + this.props.didSurfaceFile(this.props.filePath, this.state.stagingStatus); + } + } + + async diveIntoCorrespondingFilePatch() { + const stagingStatus = this.isStaged() ? 'unstaged' : 'staged'; + const filePatch = await this.getFilePatchForPath(this.props.filePath, stagingStatus === 'staged'); + this.props.quietlySelectItem(this.props.filePath, stagingStatus); + this.setState({filePatch, stagingStatus}); + } + + isStaged() { + return this.state.stagingStatus === 'staged'; + } + + isEmpty() { + return !this.state.filePatch || this.state.filePatch.getHunks().length === 0; + } + + focus() { + if (this.filePatchView) { + this.filePatchView.focus(); + } + } + + wasActivated(isStillActive) { + process.nextTick(() => { + isStillActive() && this.focus(); + }); + } + + async openCurrentFile({lineNumber} = {}) { + const [textEditor] = await this.props.openFiles([this.props.filePath]); + const position = new Point(lineNumber ? lineNumber - 1 : 0, 0); + textEditor.scrollToBufferPosition(position, {center: true}); + textEditor.setCursorBufferPosition(position); + return textEditor; + } + + discardLines(lines) { + return this.props.discardLines(this.state.filePatch, lines, this.repositoryObserver.getActiveModel()); + } + + undoLastDiscard() { + return this.props.undoLastDiscard(this.props.filePath, this.repositoryObserver.getActiveModel()); + } + + hasUndoHistory() { + return this.repositoryObserver.getActiveModel().hasDiscardHistory(this.props.filePath); + } + + destroy() { + this.destroyed = true; + this.subscriptions.dispose(); + this.repositoryObserver.destroy(); + this.emitter.emit('did-destroy'); + } +} diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index a10a28980f..6dbedb6469 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -16,7 +16,7 @@ import CredentialDialog from '../views/credential-dialog'; import Commands, {Command} from '../atom/commands'; import GitTimingsView from '../views/git-timings-view'; import GithubTabController from './github-tab-controller'; -import FilePatchController from './file-patch-controller'; +import FilePatchItem from '../items/file-patch-item'; import IssueishPaneItem from '../items/issueish-pane-item'; import GitTabItem from '../items/git-tab-item'; import StatusBarTileController from './status-bar-tile-controller'; @@ -318,24 +318,14 @@ export default class RootController extends React.Component { + uriPattern={FilePatchItem.uriPattern}> {({itemHolder, params}) => ( - )} @@ -527,7 +517,7 @@ export default class RootController extends React.Component { } const lineNum = editor.getCursorBufferPosition().row + 1; const filePatchItem = await this.props.workspace.open( - FilePatchController.buildURI(filePath, repoPath, stagingStatus), + FilePatchItem.buildURI(filePath, repoPath, stagingStatus), {pending: true, activatePane: true, activateItem: true}, ); await filePatchItem.getRealItemPromise(); diff --git a/lib/items/file-patch-item.js b/lib/items/file-patch-item.js new file mode 100644 index 0000000000..1c02262dac --- /dev/null +++ b/lib/items/file-patch-item.js @@ -0,0 +1,91 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Emitter} from 'event-kit'; + +import FilePatchContainer from '../containers/file-patch-container'; + +export default class FilePatchItem extends React.Component { + static propTypes = { + repository: PropTypes.object.isRequired, + stagingStatus: PropTypes.oneOf(['staged', 'unstaged']), + relPath: PropTypes.string.isRequired, + + tooltips: PropTypes.object.isRequired, + } + + static uriPattern = 'atom-github://file-patch/{relPath...}?workdir={workdir}&stagingStatus={stagingStatus}' + + static buildURI(relPath, workdir, stagingStatus) { + return 'atom-github://file-patch/' + + relPath + + `?workdir=${encodeURIComponent(workdir)}` + + `&stagingStatus=${encodeURIComponent(stagingStatus)}`; + } + + constructor(props) { + super(props); + + this.emitter = new Emitter(); + this.isDestroyed = false; + this.hasTerminatedPendingState = false; + } + + getTitle() { + let title = this.props.stagingStatus === 'staged' ? 'Staged' : 'Unstaged'; + title += ' Changes: '; + title += this.props.relPath; + return title; + } + + terminatePendingState() { + if (!this.hasTerminatedPendingState) { + this.emitter.emit('did-terminate-pending-state'); + this.hasTerminatedPendingState = true; + } + } + + onDidTerminatePendingState(callback) { + return this.emitter.on('did-terminate-pending-state', callback); + } + + destroy() { + if (!this.isDestroyed) { + this.emitter.emit('did-destroy'); + this.isDestroyed = true; + } + } + + onDidDestroy(callback) { + return this.emitter.on('did-destroy', callback); + } + + render() { + return ( + + ); + } + + serialize() { + return { + deserializer: 'FilePatchControllerStub', + uri: this.getURI(), + }; + } + + getStagingStatus() { + return this.props.stagingStatus; + } + + getFilePath() { + return this.props.relPath; + } + + getWorkingDirectory() { + return this.props.repository.getWorkingDirectoryPath(); + } +} diff --git a/lib/views/file-patch-view.js b/lib/views/file-patch-view.js index e8067025dc..f774c89437 100644 --- a/lib/views/file-patch-view.js +++ b/lib/views/file-patch-view.js @@ -1,716 +1,87 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {CompositeDisposable, Disposable} from 'event-kit'; import cx from 'classnames'; -import bytes from 'bytes'; -import HunkView from './hunk-view'; -import SimpleTooltip from '../atom/simple-tooltip'; -import Commands, {Command} from '../atom/commands'; import FilePatchSelection from '../models/file-patch-selection'; -import Switchboard from '../switchboard'; -import RefHolder from '../models/ref-holder'; -import {autobind} from '../helpers'; - -const executableText = { - 100644: 'non executable 100644', - 100755: 'executable 100755', -}; +import AtomTextEditor from '../atom/atom-text-editor'; +import Marker from '../atom/marker'; +import Decoration from '../atom/decoration'; export default class FilePatchView extends React.Component { static propTypes = { - commandRegistry: PropTypes.object.isRequired, - tooltips: PropTypes.object.isRequired, - filePath: PropTypes.string.isRequired, - hunks: PropTypes.arrayOf(PropTypes.object).isRequired, - executableModeChange: PropTypes.shape({ - oldMode: PropTypes.string.isRequired, - newMode: PropTypes.string.isRequired, - }), - symlinkChange: PropTypes.shape({ - oldSymlink: PropTypes.string, - newSymlink: PropTypes.string, - typechange: PropTypes.bool, - filePatchStatus: PropTypes.string, - }), - stagingStatus: PropTypes.oneOf(['unstaged', 'staged']).isRequired, + stagingStatus: PropTypes.oneOf(['staged', 'unstaged']).isRequired, isPartiallyStaged: PropTypes.bool.isRequired, - hasUndoHistory: PropTypes.bool.isRequired, - attemptLineStageOperation: PropTypes.func.isRequired, - attemptHunkStageOperation: PropTypes.func.isRequired, - attemptFileStageOperation: PropTypes.func.isRequired, - attemptModeStageOperation: PropTypes.func.isRequired, - attemptSymlinkStageOperation: PropTypes.func.isRequired, - discardLines: PropTypes.func.isRequired, - undoLastDiscard: PropTypes.func.isRequired, - openCurrentFile: PropTypes.func.isRequired, - didSurfaceFile: PropTypes.func.isRequired, - didDiveIntoCorrespondingFilePatch: PropTypes.func.isRequired, - switchboard: PropTypes.instanceOf(Switchboard), - displayLargeDiffMessage: PropTypes.bool, - byteCount: PropTypes.number, - handleShowDiffClick: PropTypes.func.isRequired, - } + filePatch: PropTypes.object.isRequired, - static defaultProps = { - switchboard: new Switchboard(), + tooltips: PropTypes.object.isRequired, } - constructor(props, context) { - super(props, context); - autobind( - this, - 'registerCommands', 'renderButtonGroup', 'renderExecutableModeChange', 'renderSymlinkChange', 'contextMenuOnItem', - 'mousedownOnLine', 'mousemoveOnLine', 'mouseup', 'togglePatchSelectionMode', 'selectNext', 'selectNextElement', - 'selectToNext', 'selectPrevious', 'selectPreviousElement', 'selectToPrevious', 'selectFirst', 'selectToFirst', - 'selectLast', 'selectToLast', 'selectAll', 'didConfirm', 'didMoveRight', 'focus', 'openFile', 'stageOrUnstageAll', - 'stageOrUnstageModeChange', 'stageOrUnstageSymlinkChange', 'discardSelection', - ); - - this.mouseSelectionInProgress = false; - this.disposables = new CompositeDisposable(); - - this.refElement = new RefHolder(); + constructor(props) { + super(props); this.state = { - selection: new FilePatchSelection(this.props.hunks), + selection: new FilePatchSelection(this.props.filePatch.getHunks()), }; } - componentDidMount() { - window.addEventListener('mouseup', this.mouseup); - this.disposables.add(new Disposable(() => window.removeEventListener('mouseup', this.mouseup))); - } - - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - const hunksChanged = this.props.hunks.length !== nextProps.hunks.length || - this.props.hunks.some((hunk, index) => hunk !== nextProps.hunks[index]); - - if (hunksChanged) { - this.setState(prevState => { - return { - selection: prevState.selection.updateHunks(nextProps.hunks), - }; - }, () => { - nextProps.switchboard.didChangePatch(); - }); - } - } - - shouldComponentUpdate(nextProps, nextState) { - const deepProps = { - executableModeChange: ['oldMode', 'newMode'], - symlinkChange: ['oldSymlink', 'newSymlink', 'typechange', 'filePatchStatus'], - }; - - for (const propKey in this.constructor.propTypes) { - const subKeys = deepProps[propKey]; - const oldProp = this.props[propKey]; - const newProp = nextProps[propKey]; - - if (subKeys) { - const oldExists = (oldProp !== null && oldProp !== undefined); - const newExists = (newProp !== null && newProp !== undefined); - - if (oldExists !== newExists) { - return true; - } - - if (!oldExists && !newExists) { - continue; - } - - if (subKeys.some(subKey => this.props[propKey][subKey] !== nextProps[propKey][subKey])) { - return true; - } - } else { - if (oldProp !== newProp) { - return true; - } - } - } - - if (this.state.selection !== nextState.selection) { - return true; - } - - return false; - } - - renderEmptyDiffMessage() { - return ( -
- File has no contents -
- ); - } - - renderLargeDiffMessage() { - const human = bytes.format(this.props.byteCount); - - return ( -
-

- This is a large {human} diff. For performance reasons, it is not rendered by default. -

- -
- ); - } - - renderHunks() { - // Render hunks for symlink change only if 'typechange' (which indicates symlink change AND file content change) - const {symlinkChange} = this.props; - if (symlinkChange && !symlinkChange.typechange) { return null; } - - const selectedHunks = this.state.selection.getSelectedHunks(); - const selectedLines = this.state.selection.getSelectedLines(); - const headHunk = this.state.selection.getHeadHunk(); - const headLine = this.state.selection.getHeadLine(); - const hunkSelectionMode = this.state.selection.getMode() === 'hunk'; - - const unstaged = this.props.stagingStatus === 'unstaged'; - const stageButtonLabelPrefix = unstaged ? 'Stage' : 'Unstage'; - - if (this.props.hunks.length === 0) { - return this.renderEmptyDiffMessage(); - } - - return this.props.hunks.map(hunk => { - const isSelected = selectedHunks.has(hunk); - let stageButtonSuffix = (hunkSelectionMode || !isSelected) ? ' Hunk' : ' Selection'; - if (selectedHunks.size > 1 && selectedHunks.has(hunk)) { - stageButtonSuffix += 's'; - } - const stageButtonLabel = stageButtonLabelPrefix + stageButtonSuffix; - const discardButtonLabel = 'Discard' + stageButtonSuffix; - - return ( - this.mousedownOnHeader(e, hunk)} - mousedownOnLine={this.mousedownOnLine} - mousemoveOnLine={this.mousemoveOnLine} - contextMenuOnItem={this.contextMenuOnItem} - didClickStageButton={() => this.didClickStageButtonForHunk(hunk)} - didClickDiscardButton={() => this.didClickDiscardButtonForHunk(hunk)} - /> - ); - }); - - } - render() { - const unstaged = this.props.stagingStatus === 'unstaged'; + const text = this.props.filePatch.getHunks().map(h => h.toString()).join('\n'); + return (
- - {this.registerCommands()} + className={cx('github-FilePatchView', {'is-staged': !this.isUnstaged(), 'is-unstaged': this.isUnstaged()})} + tabIndex="-1"> -
- - {unstaged ? 'Unstaged Changes for ' : 'Staged Changes for '} - {this.props.filePath} - - {this.renderButtonGroup()} -
+ + + + {this.renderFileHeader()} + + + -
- {this.props.executableModeChange && this.renderExecutableModeChange(unstaged)} - {this.props.symlinkChange && this.renderSymlinkChange(unstaged)} - {this.props.displayLargeDiffMessage ? this.renderLargeDiffMessage() : this.renderHunks()} -
); } - registerCommands() { + renderFileHeader() { return ( -
- - - - - - - - - - - - - - - - - this.props.isPartiallyStaged && this.props.didDiveIntoCorrespondingFilePatch()} - /> - - this.props.hasUndoHistory && this.props.undoLastDiscard()} - /> - {this.props.executableModeChange && - } - {this.props.symlinkChange && - } - - - - this.props.hasUndoHistory && this.props.undoLastDiscard()} - /> - - -
+
+ + {this.isUnstaged() ? 'Unstaged Changes for ' : 'Staged Changes for '} + {this.props.filePatch.getPath()} + + {this.renderButtonGroup()} +
); } renderButtonGroup() { - const unstaged = this.props.stagingStatus === 'unstaged'; + const hasHunks = this.props.filePatch.getHunks().length > 0; return ( - {this.props.hasUndoHistory && unstaged ? ( - - ) : null} - {this.props.isPartiallyStaged || !this.props.hunks.length ? ( - - ) : null } ); } - renderExecutableModeChange(unstaged) { - const {executableModeChange} = this.props; - return ( -
-
-
-

Mode change

-
- -
-
-
- File changed mode - - -
-
-
- ); - } - - renderSymlinkChange(unstaged) { - const {symlinkChange} = this.props; - const {oldSymlink, newSymlink} = symlinkChange; - - if (oldSymlink && !newSymlink) { - return ( -
-
-
-

Symlink deleted

-
- -
-
-
- Symlink - - to {oldSymlink} - - deleted. -
-
-
- ); - } else if (!oldSymlink && newSymlink) { - return ( -
-
-
-

Symlink added

-
- -
-
-
- Symlink - - to {newSymlink} - - created. -
-
-
- ); - } else if (oldSymlink && newSymlink) { - return ( -
-
-
-

Symlink changed

-
- -
-
-
- - from {oldSymlink} - - - to {newSymlink} - -
-
-
- ); - } else { - return new Error('Symlink change detected, but missing symlink paths'); - } - } - - componentWillUnmount() { - this.disposables.dispose(); - } - - contextMenuOnItem(event, hunk, line) { - const resend = () => { - const newEvent = new MouseEvent(event.type, event); - setImmediate(() => event.target.parentNode.dispatchEvent(newEvent)); - }; - - const mode = this.state.selection.getMode(); - if (mode === 'hunk' && !this.state.selection.getSelectedHunks().has(hunk)) { - event.stopPropagation(); - - this.setState(prevState => { - return {selection: prevState.selection.selectHunk(hunk, event.shiftKey)}; - }, resend); - } else if (mode === 'line' && !this.state.selection.getSelectedLines().has(line)) { - event.stopPropagation(); - - this.setState(prevState => { - return {selection: prevState.selection.selectLine(line, event.shiftKey)}; - }, resend); - } - } - - mousedownOnHeader(event, hunk) { - if (event.button !== 0) { return; } - const windows = process.platform === 'win32'; - if (event.ctrlKey && !windows) { return; } // simply open context menu - - this.mouseSelectionInProgress = true; - event.persist && event.persist(); - - this.setState(prevState => { - let selection = prevState.selection; - if (event.metaKey || (event.ctrlKey && windows)) { - if (selection.getMode() === 'hunk') { - selection = selection.addOrSubtractHunkSelection(hunk); - } else { - // TODO: optimize - selection = hunk.getLines().reduce( - (current, line) => current.addOrSubtractLineSelection(line).coalesce(), - selection, - ); - } - } else if (event.shiftKey) { - if (selection.getMode() === 'hunk') { - selection = selection.selectHunk(hunk, true); - } else { - const hunkLines = hunk.getLines(); - const tailIndex = selection.getLineSelectionTailIndex(); - const selectedHunkAfterTail = tailIndex < hunkLines[0].diffLineNumber; - if (selectedHunkAfterTail) { - selection = selection.selectLine(hunkLines[hunkLines.length - 1], true); - } else { - selection = selection.selectLine(hunkLines[0], true); - } - } - } else { - selection = selection.selectHunk(hunk, false); - } - - return {selection}; - }); - } - - mousedownOnLine(event, hunk, line) { - if (event.button !== 0) { return; } - const windows = process.platform === 'win32'; - if (event.ctrlKey && !windows) { return; } // simply open context menu - - this.mouseSelectionInProgress = true; - event.persist && event.persist(); - - this.setState(prevState => { - let selection = prevState.selection; - - if (event.metaKey || (event.ctrlKey && windows)) { - if (selection.getMode() === 'hunk') { - selection = selection.addOrSubtractHunkSelection(hunk); - } else { - selection = selection.addOrSubtractLineSelection(line); - } - } else if (event.shiftKey) { - if (selection.getMode() === 'hunk') { - selection = selection.selectHunk(hunk, true); - } else { - selection = selection.selectLine(line, true); - } - } else if (event.detail === 1) { - selection = selection.selectLine(line, false); - } else if (event.detail === 2) { - selection = selection.selectHunk(hunk, false); - } - - return {selection}; - }); - } - - mousemoveOnLine(event, hunk, line) { - if (!this.mouseSelectionInProgress) { return; } - - this.setState(prevState => { - let selection = null; - if (prevState.selection.getMode() === 'hunk') { - selection = prevState.selection.selectHunk(hunk, true); - } else { - selection = prevState.selection.selectLine(line, true); - } - return {selection}; - }); - } - - mouseup() { - this.mouseSelectionInProgress = false; - this.setState(prevState => { - return {selection: prevState.selection.coalesce()}; - }); - } - - togglePatchSelectionMode() { - this.setState(prevState => ({selection: prevState.selection.toggleMode()})); - } - - getPatchSelectionMode() { - return this.state.selection.getMode(); - } - - getSelectedHunks() { - return this.state.selection.getSelectedHunks(); - } - - getSelectedLines() { - return this.state.selection.getSelectedLines(); - } - - selectNext() { - this.setState(prevState => ({selection: prevState.selection.selectNext()})); - } - - selectNextElement() { - if (this.state.selection.isEmpty() && this.props.didSurfaceFile) { - this.props.didSurfaceFile(); - } else { - this.setState(prevState => ({selection: prevState.selection.jumpToNextHunk()})); - } - } - - selectToNext() { - this.setState(prevState => { - return {selection: prevState.selection.selectNext(true).coalesce()}; - }); - } - - selectPrevious() { - this.setState(prevState => ({selection: prevState.selection.selectPrevious()})); - } - - selectPreviousElement() { - if (this.state.selection.isEmpty() && this.props.didSurfaceFile) { - this.props.didSurfaceFile(); - } else { - this.setState(prevState => ({selection: prevState.selection.jumpToPreviousHunk()})); - } - } - - selectToPrevious() { - this.setState(prevState => { - return {selection: prevState.selection.selectPrevious(true).coalesce()}; - }); - } - - selectFirst() { - this.setState(prevState => ({selection: prevState.selection.selectFirst()})); - } - - selectToFirst() { - this.setState(prevState => ({selection: prevState.selection.selectFirst(true)})); - } - - selectLast() { - this.setState(prevState => ({selection: prevState.selection.selectLast()})); - } - - selectToLast() { - this.setState(prevState => ({selection: prevState.selection.selectLast(true)})); - } - - selectAll() { - return new Promise(resolve => { - this.setState(prevState => ({selection: prevState.selection.selectAll()}), resolve); - }); - } - - getNextHunkUpdatePromise() { - return this.state.selection.getNextUpdatePromise(); - } - - didClickStageButtonForHunk(hunk) { - if (this.state.selection.getSelectedHunks().has(hunk)) { - this.props.attemptLineStageOperation(this.state.selection.getSelectedLines()); - } else { - this.setState(prevState => ({selection: prevState.selection.selectHunk(hunk)}), () => { - this.props.attemptHunkStageOperation(hunk); - }); - } - } - - didClickDiscardButtonForHunk(hunk) { - if (this.state.selection.getSelectedHunks().has(hunk)) { - this.discardSelection(); - } else { - this.setState(prevState => ({selection: prevState.selection.selectHunk(hunk)}), () => { - this.discardSelection(); - }); - } - } - - didConfirm() { - return this.didClickStageButtonForHunk([...this.state.selection.getSelectedHunks()][0]); - } - - didMoveRight() { - if (this.props.didSurfaceFile) { - this.props.didSurfaceFile(); - } - } - - focus() { - this.refElement.get().focus(); - } - - openFile() { - let lineNumber = 0; - const firstSelectedLine = Array.from(this.state.selection.getSelectedLines())[0]; - if (firstSelectedLine && firstSelectedLine.newLineNumber > -1) { - lineNumber = firstSelectedLine.newLineNumber; - } else { - const firstSelectedHunk = Array.from(this.state.selection.getSelectedHunks())[0]; - lineNumber = firstSelectedHunk ? firstSelectedHunk.getNewStartRow() : 0; - } - return this.props.openCurrentFile({lineNumber}); - } - - stageOrUnstageAll() { - this.props.attemptFileStageOperation(); - } - - stageOrUnstageModeChange() { - this.props.attemptModeStageOperation(); - } - - stageOrUnstageSymlinkChange() { - this.props.attemptSymlinkStageOperation(); - } - - discardSelection() { - const selectedLines = this.state.selection.getSelectedLines(); - return selectedLines.size ? this.props.discardLines(selectedLines) : null; - } - - goToDiffLine(lineNumber) { - this.setState(prevState => ({selection: prevState.selection.goToDiffLine(lineNumber)})); + isUnstaged() { + return this.props.stagingStatus === 'unstaged'; } } diff --git a/lib/views/file-patch-view.old.js b/lib/views/file-patch-view.old.js new file mode 100644 index 0000000000..e8067025dc --- /dev/null +++ b/lib/views/file-patch-view.old.js @@ -0,0 +1,716 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {CompositeDisposable, Disposable} from 'event-kit'; +import cx from 'classnames'; +import bytes from 'bytes'; + +import HunkView from './hunk-view'; +import SimpleTooltip from '../atom/simple-tooltip'; +import Commands, {Command} from '../atom/commands'; +import FilePatchSelection from '../models/file-patch-selection'; +import Switchboard from '../switchboard'; +import RefHolder from '../models/ref-holder'; +import {autobind} from '../helpers'; + +const executableText = { + 100644: 'non executable 100644', + 100755: 'executable 100755', +}; + +export default class FilePatchView extends React.Component { + static propTypes = { + commandRegistry: PropTypes.object.isRequired, + tooltips: PropTypes.object.isRequired, + filePath: PropTypes.string.isRequired, + hunks: PropTypes.arrayOf(PropTypes.object).isRequired, + executableModeChange: PropTypes.shape({ + oldMode: PropTypes.string.isRequired, + newMode: PropTypes.string.isRequired, + }), + symlinkChange: PropTypes.shape({ + oldSymlink: PropTypes.string, + newSymlink: PropTypes.string, + typechange: PropTypes.bool, + filePatchStatus: PropTypes.string, + }), + stagingStatus: PropTypes.oneOf(['unstaged', 'staged']).isRequired, + isPartiallyStaged: PropTypes.bool.isRequired, + hasUndoHistory: PropTypes.bool.isRequired, + attemptLineStageOperation: PropTypes.func.isRequired, + attemptHunkStageOperation: PropTypes.func.isRequired, + attemptFileStageOperation: PropTypes.func.isRequired, + attemptModeStageOperation: PropTypes.func.isRequired, + attemptSymlinkStageOperation: PropTypes.func.isRequired, + discardLines: PropTypes.func.isRequired, + undoLastDiscard: PropTypes.func.isRequired, + openCurrentFile: PropTypes.func.isRequired, + didSurfaceFile: PropTypes.func.isRequired, + didDiveIntoCorrespondingFilePatch: PropTypes.func.isRequired, + switchboard: PropTypes.instanceOf(Switchboard), + displayLargeDiffMessage: PropTypes.bool, + byteCount: PropTypes.number, + handleShowDiffClick: PropTypes.func.isRequired, + } + + static defaultProps = { + switchboard: new Switchboard(), + } + + constructor(props, context) { + super(props, context); + autobind( + this, + 'registerCommands', 'renderButtonGroup', 'renderExecutableModeChange', 'renderSymlinkChange', 'contextMenuOnItem', + 'mousedownOnLine', 'mousemoveOnLine', 'mouseup', 'togglePatchSelectionMode', 'selectNext', 'selectNextElement', + 'selectToNext', 'selectPrevious', 'selectPreviousElement', 'selectToPrevious', 'selectFirst', 'selectToFirst', + 'selectLast', 'selectToLast', 'selectAll', 'didConfirm', 'didMoveRight', 'focus', 'openFile', 'stageOrUnstageAll', + 'stageOrUnstageModeChange', 'stageOrUnstageSymlinkChange', 'discardSelection', + ); + + this.mouseSelectionInProgress = false; + this.disposables = new CompositeDisposable(); + + this.refElement = new RefHolder(); + + this.state = { + selection: new FilePatchSelection(this.props.hunks), + }; + } + + componentDidMount() { + window.addEventListener('mouseup', this.mouseup); + this.disposables.add(new Disposable(() => window.removeEventListener('mouseup', this.mouseup))); + } + + // eslint-disable-next-line camelcase + UNSAFE_componentWillReceiveProps(nextProps) { + const hunksChanged = this.props.hunks.length !== nextProps.hunks.length || + this.props.hunks.some((hunk, index) => hunk !== nextProps.hunks[index]); + + if (hunksChanged) { + this.setState(prevState => { + return { + selection: prevState.selection.updateHunks(nextProps.hunks), + }; + }, () => { + nextProps.switchboard.didChangePatch(); + }); + } + } + + shouldComponentUpdate(nextProps, nextState) { + const deepProps = { + executableModeChange: ['oldMode', 'newMode'], + symlinkChange: ['oldSymlink', 'newSymlink', 'typechange', 'filePatchStatus'], + }; + + for (const propKey in this.constructor.propTypes) { + const subKeys = deepProps[propKey]; + const oldProp = this.props[propKey]; + const newProp = nextProps[propKey]; + + if (subKeys) { + const oldExists = (oldProp !== null && oldProp !== undefined); + const newExists = (newProp !== null && newProp !== undefined); + + if (oldExists !== newExists) { + return true; + } + + if (!oldExists && !newExists) { + continue; + } + + if (subKeys.some(subKey => this.props[propKey][subKey] !== nextProps[propKey][subKey])) { + return true; + } + } else { + if (oldProp !== newProp) { + return true; + } + } + } + + if (this.state.selection !== nextState.selection) { + return true; + } + + return false; + } + + renderEmptyDiffMessage() { + return ( +
+ File has no contents +
+ ); + } + + renderLargeDiffMessage() { + const human = bytes.format(this.props.byteCount); + + return ( +
+

+ This is a large {human} diff. For performance reasons, it is not rendered by default. +

+ +
+ ); + } + + renderHunks() { + // Render hunks for symlink change only if 'typechange' (which indicates symlink change AND file content change) + const {symlinkChange} = this.props; + if (symlinkChange && !symlinkChange.typechange) { return null; } + + const selectedHunks = this.state.selection.getSelectedHunks(); + const selectedLines = this.state.selection.getSelectedLines(); + const headHunk = this.state.selection.getHeadHunk(); + const headLine = this.state.selection.getHeadLine(); + const hunkSelectionMode = this.state.selection.getMode() === 'hunk'; + + const unstaged = this.props.stagingStatus === 'unstaged'; + const stageButtonLabelPrefix = unstaged ? 'Stage' : 'Unstage'; + + if (this.props.hunks.length === 0) { + return this.renderEmptyDiffMessage(); + } + + return this.props.hunks.map(hunk => { + const isSelected = selectedHunks.has(hunk); + let stageButtonSuffix = (hunkSelectionMode || !isSelected) ? ' Hunk' : ' Selection'; + if (selectedHunks.size > 1 && selectedHunks.has(hunk)) { + stageButtonSuffix += 's'; + } + const stageButtonLabel = stageButtonLabelPrefix + stageButtonSuffix; + const discardButtonLabel = 'Discard' + stageButtonSuffix; + + return ( + this.mousedownOnHeader(e, hunk)} + mousedownOnLine={this.mousedownOnLine} + mousemoveOnLine={this.mousemoveOnLine} + contextMenuOnItem={this.contextMenuOnItem} + didClickStageButton={() => this.didClickStageButtonForHunk(hunk)} + didClickDiscardButton={() => this.didClickDiscardButtonForHunk(hunk)} + /> + ); + }); + + } + + render() { + const unstaged = this.props.stagingStatus === 'unstaged'; + return ( +
+ + {this.registerCommands()} + +
+ + {unstaged ? 'Unstaged Changes for ' : 'Staged Changes for '} + {this.props.filePath} + + {this.renderButtonGroup()} +
+ +
+ {this.props.executableModeChange && this.renderExecutableModeChange(unstaged)} + {this.props.symlinkChange && this.renderSymlinkChange(unstaged)} + {this.props.displayLargeDiffMessage ? this.renderLargeDiffMessage() : this.renderHunks()} +
+
+ ); + } + + registerCommands() { + return ( +
+ + + + + + + + + + + + + + + + + this.props.isPartiallyStaged && this.props.didDiveIntoCorrespondingFilePatch()} + /> + + this.props.hasUndoHistory && this.props.undoLastDiscard()} + /> + {this.props.executableModeChange && + } + {this.props.symlinkChange && + } + + + + this.props.hasUndoHistory && this.props.undoLastDiscard()} + /> + + +
+ ); + } + + renderButtonGroup() { + const unstaged = this.props.stagingStatus === 'unstaged'; + + return ( + + {this.props.hasUndoHistory && unstaged ? ( + + ) : null} + {this.props.isPartiallyStaged || !this.props.hunks.length ? ( + + + ) : null } + + ); + } + + renderExecutableModeChange(unstaged) { + const {executableModeChange} = this.props; + return ( +
+
+
+

Mode change

+
+ +
+
+
+ File changed mode + + +
+
+
+ ); + } + + renderSymlinkChange(unstaged) { + const {symlinkChange} = this.props; + const {oldSymlink, newSymlink} = symlinkChange; + + if (oldSymlink && !newSymlink) { + return ( +
+
+
+

Symlink deleted

+
+ +
+
+
+ Symlink + + to {oldSymlink} + + deleted. +
+
+
+ ); + } else if (!oldSymlink && newSymlink) { + return ( +
+
+
+

Symlink added

+
+ +
+
+
+ Symlink + + to {newSymlink} + + created. +
+
+
+ ); + } else if (oldSymlink && newSymlink) { + return ( +
+
+
+

Symlink changed

+
+ +
+
+
+ + from {oldSymlink} + + + to {newSymlink} + +
+
+
+ ); + } else { + return new Error('Symlink change detected, but missing symlink paths'); + } + } + + componentWillUnmount() { + this.disposables.dispose(); + } + + contextMenuOnItem(event, hunk, line) { + const resend = () => { + const newEvent = new MouseEvent(event.type, event); + setImmediate(() => event.target.parentNode.dispatchEvent(newEvent)); + }; + + const mode = this.state.selection.getMode(); + if (mode === 'hunk' && !this.state.selection.getSelectedHunks().has(hunk)) { + event.stopPropagation(); + + this.setState(prevState => { + return {selection: prevState.selection.selectHunk(hunk, event.shiftKey)}; + }, resend); + } else if (mode === 'line' && !this.state.selection.getSelectedLines().has(line)) { + event.stopPropagation(); + + this.setState(prevState => { + return {selection: prevState.selection.selectLine(line, event.shiftKey)}; + }, resend); + } + } + + mousedownOnHeader(event, hunk) { + if (event.button !== 0) { return; } + const windows = process.platform === 'win32'; + if (event.ctrlKey && !windows) { return; } // simply open context menu + + this.mouseSelectionInProgress = true; + event.persist && event.persist(); + + this.setState(prevState => { + let selection = prevState.selection; + if (event.metaKey || (event.ctrlKey && windows)) { + if (selection.getMode() === 'hunk') { + selection = selection.addOrSubtractHunkSelection(hunk); + } else { + // TODO: optimize + selection = hunk.getLines().reduce( + (current, line) => current.addOrSubtractLineSelection(line).coalesce(), + selection, + ); + } + } else if (event.shiftKey) { + if (selection.getMode() === 'hunk') { + selection = selection.selectHunk(hunk, true); + } else { + const hunkLines = hunk.getLines(); + const tailIndex = selection.getLineSelectionTailIndex(); + const selectedHunkAfterTail = tailIndex < hunkLines[0].diffLineNumber; + if (selectedHunkAfterTail) { + selection = selection.selectLine(hunkLines[hunkLines.length - 1], true); + } else { + selection = selection.selectLine(hunkLines[0], true); + } + } + } else { + selection = selection.selectHunk(hunk, false); + } + + return {selection}; + }); + } + + mousedownOnLine(event, hunk, line) { + if (event.button !== 0) { return; } + const windows = process.platform === 'win32'; + if (event.ctrlKey && !windows) { return; } // simply open context menu + + this.mouseSelectionInProgress = true; + event.persist && event.persist(); + + this.setState(prevState => { + let selection = prevState.selection; + + if (event.metaKey || (event.ctrlKey && windows)) { + if (selection.getMode() === 'hunk') { + selection = selection.addOrSubtractHunkSelection(hunk); + } else { + selection = selection.addOrSubtractLineSelection(line); + } + } else if (event.shiftKey) { + if (selection.getMode() === 'hunk') { + selection = selection.selectHunk(hunk, true); + } else { + selection = selection.selectLine(line, true); + } + } else if (event.detail === 1) { + selection = selection.selectLine(line, false); + } else if (event.detail === 2) { + selection = selection.selectHunk(hunk, false); + } + + return {selection}; + }); + } + + mousemoveOnLine(event, hunk, line) { + if (!this.mouseSelectionInProgress) { return; } + + this.setState(prevState => { + let selection = null; + if (prevState.selection.getMode() === 'hunk') { + selection = prevState.selection.selectHunk(hunk, true); + } else { + selection = prevState.selection.selectLine(line, true); + } + return {selection}; + }); + } + + mouseup() { + this.mouseSelectionInProgress = false; + this.setState(prevState => { + return {selection: prevState.selection.coalesce()}; + }); + } + + togglePatchSelectionMode() { + this.setState(prevState => ({selection: prevState.selection.toggleMode()})); + } + + getPatchSelectionMode() { + return this.state.selection.getMode(); + } + + getSelectedHunks() { + return this.state.selection.getSelectedHunks(); + } + + getSelectedLines() { + return this.state.selection.getSelectedLines(); + } + + selectNext() { + this.setState(prevState => ({selection: prevState.selection.selectNext()})); + } + + selectNextElement() { + if (this.state.selection.isEmpty() && this.props.didSurfaceFile) { + this.props.didSurfaceFile(); + } else { + this.setState(prevState => ({selection: prevState.selection.jumpToNextHunk()})); + } + } + + selectToNext() { + this.setState(prevState => { + return {selection: prevState.selection.selectNext(true).coalesce()}; + }); + } + + selectPrevious() { + this.setState(prevState => ({selection: prevState.selection.selectPrevious()})); + } + + selectPreviousElement() { + if (this.state.selection.isEmpty() && this.props.didSurfaceFile) { + this.props.didSurfaceFile(); + } else { + this.setState(prevState => ({selection: prevState.selection.jumpToPreviousHunk()})); + } + } + + selectToPrevious() { + this.setState(prevState => { + return {selection: prevState.selection.selectPrevious(true).coalesce()}; + }); + } + + selectFirst() { + this.setState(prevState => ({selection: prevState.selection.selectFirst()})); + } + + selectToFirst() { + this.setState(prevState => ({selection: prevState.selection.selectFirst(true)})); + } + + selectLast() { + this.setState(prevState => ({selection: prevState.selection.selectLast()})); + } + + selectToLast() { + this.setState(prevState => ({selection: prevState.selection.selectLast(true)})); + } + + selectAll() { + return new Promise(resolve => { + this.setState(prevState => ({selection: prevState.selection.selectAll()}), resolve); + }); + } + + getNextHunkUpdatePromise() { + return this.state.selection.getNextUpdatePromise(); + } + + didClickStageButtonForHunk(hunk) { + if (this.state.selection.getSelectedHunks().has(hunk)) { + this.props.attemptLineStageOperation(this.state.selection.getSelectedLines()); + } else { + this.setState(prevState => ({selection: prevState.selection.selectHunk(hunk)}), () => { + this.props.attemptHunkStageOperation(hunk); + }); + } + } + + didClickDiscardButtonForHunk(hunk) { + if (this.state.selection.getSelectedHunks().has(hunk)) { + this.discardSelection(); + } else { + this.setState(prevState => ({selection: prevState.selection.selectHunk(hunk)}), () => { + this.discardSelection(); + }); + } + } + + didConfirm() { + return this.didClickStageButtonForHunk([...this.state.selection.getSelectedHunks()][0]); + } + + didMoveRight() { + if (this.props.didSurfaceFile) { + this.props.didSurfaceFile(); + } + } + + focus() { + this.refElement.get().focus(); + } + + openFile() { + let lineNumber = 0; + const firstSelectedLine = Array.from(this.state.selection.getSelectedLines())[0]; + if (firstSelectedLine && firstSelectedLine.newLineNumber > -1) { + lineNumber = firstSelectedLine.newLineNumber; + } else { + const firstSelectedHunk = Array.from(this.state.selection.getSelectedHunks())[0]; + lineNumber = firstSelectedHunk ? firstSelectedHunk.getNewStartRow() : 0; + } + return this.props.openCurrentFile({lineNumber}); + } + + stageOrUnstageAll() { + this.props.attemptFileStageOperation(); + } + + stageOrUnstageModeChange() { + this.props.attemptModeStageOperation(); + } + + stageOrUnstageSymlinkChange() { + this.props.attemptSymlinkStageOperation(); + } + + discardSelection() { + const selectedLines = this.state.selection.getSelectedLines(); + return selectedLines.size ? this.props.discardLines(selectedLines) : null; + } + + goToDiffLine(lineNumber) { + this.setState(prevState => ({selection: prevState.selection.goToDiffLine(lineNumber)})); + } +} From c8d5640c217a4ec71435cb6f6ef212d4b32ee8e8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Jun 2018 13:17:23 -0400 Subject: [PATCH 0126/4847] Convert a FilePatch to a PresentedFilePatch for rendering within a TextEditor --- lib/models/file-patch.js | 5 ++ lib/models/presented-file-patch.js | 59 +++++++++++++++++++++ test/models/file-patch.test.js | 83 ++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 lib/models/presented-file-patch.js diff --git a/lib/models/file-patch.js b/lib/models/file-patch.js index 0e0a91cf0f..41a6976bf8 100644 --- a/lib/models/file-patch.js +++ b/lib/models/file-patch.js @@ -1,5 +1,6 @@ import Hunk from './hunk'; import {toGitPathSep} from '../helpers'; +import PresentedFilePatch from './presented-file-patch'; class File { static empty() { @@ -322,6 +323,10 @@ export default class FilePatch { return hunks; } + present() { + return new PresentedFilePatch(this); + } + toString() { if (this.hasTypechange()) { const left = this.clone({ diff --git a/lib/models/presented-file-patch.js b/lib/models/presented-file-patch.js new file mode 100644 index 0000000000..aef7b69b34 --- /dev/null +++ b/lib/models/presented-file-patch.js @@ -0,0 +1,59 @@ +import {Point} from 'atom'; + +export default class PresentedFilePatch { + constructor(filePatch) { + this.filePatch = filePatch; + + this.hunkStartPositions = []; + this.bufferPositions = { + unchanged: [], + added: [], + deleted: [], + nonewline: [], + }; + + let bufferLine = 0; + this.text = filePatch.getHunks().reduce((str, hunk) => { + this.hunkStartPositions.push(new Point(bufferLine, 0)); + + return hunk.getLines().reduce((hunkStr, line) => { + hunkStr += line.getText() + '\n'; + + this.bufferPositions[line.getStatus()].push( + new Point(bufferLine, 0), + ); + + bufferLine++; + return hunkStr; + }, str); + }, ''); + } + + getFilePatch() { + return this.filePatch; + } + + getText() { + return this.text; + } + + getHunkStartPositions() { + return this.hunkStartPositions; + } + + getUnchangedBufferPositions() { + return this.bufferPositions.unchanged; + } + + getAddedBufferPositions() { + return this.bufferPositions.added; + } + + getDeletedBufferPositions() { + return this.bufferPositions.deleted; + } + + getNoNewlineBufferPositions() { + return this.bufferPositions.nonewline; + } +} diff --git a/test/models/file-patch.test.js b/test/models/file-patch.test.js index e0e7aab8c2..e78e625a73 100644 --- a/test/models/file-patch.test.js +++ b/test/models/file-patch.test.js @@ -387,4 +387,87 @@ describe('FilePatch', function() { assert.strictEqual(filePatch.getByteSize(), 36); }); + + describe('present()', function() { + let presented; + + beforeEach(function() { + const patch = createFilePatch('a.txt', 'a.txt', 'modified', [ + new Hunk(1, 1, 1, 3, '@@ -1,1 +2,2', [ + new HunkLine('line-1', 'added', -1, 1), + new HunkLine('line-2', 'added', -1, 2), + new HunkLine('line-3', 'unchanged', 1, 3), + ]), + new Hunk(5, 7, 5, 4, '@@ -3,3 +4,4', [ + new HunkLine('line-4', 'unchanged', 5, 7), + new HunkLine('line-5', 'deleted', 6, -1), + new HunkLine('line-6', 'deleted', 7, -1), + new HunkLine('line-7', 'added', -1, 8), + new HunkLine('line-8', 'added', -1, 9), + new HunkLine('line-9', 'added', -1, 10), + new HunkLine('line-10', 'deleted', 8, -1), + new HunkLine('line-11', 'deleted', 9, -1), + new HunkLine('line-12', 'unchanged', 5, 7), + ]), + new Hunk(20, 19, 2, 2, '@@ -5,5 +6,6', [ + new HunkLine('line-13', 'deleted', 20, -1), + new HunkLine('line-14', 'added', -1, 19), + new HunkLine('line-15', 'unchanged', 21, 20), + new HunkLine('No newline at end of file', 'nonewline', -1, -1), + ]), + ]); + + presented = patch.present(); + }); + + function assertPositions(actualPositions, expectedPositions) { + assert.lengthOf(actualPositions, expectedPositions.length); + for (let i = 0; i < expectedPositions.length; i++) { + const actual = actualPositions[i]; + const expected = expectedPositions[i]; + + assert.isTrue(actual.isEqual(expected), + `range ${i}: ${actual.toString()} does not equal [${expected.map(e => e.toString()).join(', ')}]`); + } + } + + it('unifies hunks into a continuous, unadorned string of text', function() { + const actualText = presented.getText(); + const expectedText = + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].map(num => `line-${num}\n`).join('') + + 'No newline at end of file\n'; + + assert.strictEqual(actualText, expectedText); + }); + + it("returns the buffer positions corresponding to each hunk's beginning", function() { + assertPositions(presented.getHunkStartPositions(), [ + [0, 0], [3, 0], [12, 0], + ]); + }); + + it('returns the buffer positions corresponding to unchanged lines', function() { + assertPositions(presented.getUnchangedBufferPositions(), [ + [2, 0], [3, 0], [11, 0], [14, 0], + ]); + }); + + it('returns the buffer positions corresponding to added lines', function() { + assertPositions(presented.getAddedBufferPositions(), [ + [0, 0], [1, 0], [6, 0], [7, 0], [8, 0], [13, 0], + ]); + }); + + it('returns the buffer positions corresponding to deleted lines', function() { + assertPositions(presented.getDeletedBufferPositions(), [ + [4, 0], [5, 0], [9, 0], [10, 0], [12, 0], + ]); + }); + + it('returns the buffer position of a "no newline" trailer', function() { + assertPositions(presented.getNoNewlineBufferPositions(), [ + [15, 0], + ]); + }); + }); }); From 462f266fac3736bc23e0b3727e1d4134bf970795 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Jun 2018 13:18:05 -0400 Subject: [PATCH 0127/4847] Change StagingView tests to check for FilePatchItems --- lib/views/staging-view.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/views/staging-view.js b/lib/views/staging-view.js index 0409f73dad..1b563d77d6 100644 --- a/lib/views/staging-view.js +++ b/lib/views/staging-view.js @@ -12,7 +12,7 @@ import ObserveModel from './observe-model'; import MergeConflictListItemView from './merge-conflict-list-item-view'; import CompositeListSelection from '../models/composite-list-selection'; import ResolutionProgress from '../models/conflicts/resolution-progress'; -import FilePatchController from '../controllers/file-patch-controller'; +import FilePatchItem from '../items/file-patch-item'; import Commands, {Command} from '../atom/commands'; import {autobind} from '../helpers'; @@ -541,7 +541,7 @@ export default class StagingView extends React.Component { return; } - const isFilePatchController = realItem instanceof FilePatchController; + const isFilePatchController = realItem instanceof FilePatchItem; const isMatch = realItem.getWorkingDirectory && item.getWorkingDirectory() === this.props.workingDirectoryPath; if (isFilePatchController && isMatch) { @@ -657,7 +657,7 @@ export default class StagingView extends React.Component { const activePane = this.props.workspace.getCenter().getActivePane(); const activePendingItem = activePane.getPendingItem(); const activePaneHasPendingFilePatchItem = activePendingItem && activePendingItem.getRealItem && - activePendingItem.getRealItem() instanceof FilePatchController; + activePendingItem.getRealItem() instanceof FilePatchItem; if (activePaneHasPendingFilePatchItem) { await this.showFilePatchItem(selectedItem.filePath, this.state.selection.getActiveListKey(), { activate: false, @@ -676,7 +676,7 @@ export default class StagingView extends React.Component { const pendingItem = pane.getPendingItem(); if (!pendingItem || !pendingItem.getRealItem) { return false; } const realItem = pendingItem.getRealItem(); - const isDiffViewItem = realItem instanceof FilePatchController; + const isDiffViewItem = realItem instanceof FilePatchItem; // We only want to update pending diff views for currently active repo const isInActiveRepo = realItem.getWorkingDirectory() === this.props.workingDirectoryPath; const isStale = !this.changedFileExists(realItem.getFilePath(), realItem.getStagingStatus()); @@ -691,7 +691,7 @@ export default class StagingView extends React.Component { } async showFilePatchItem(filePath, stagingStatus, {activate, pane} = {activate: false}) { - const uri = FilePatchController.buildURI(filePath, this.props.workingDirectoryPath, stagingStatus); + const uri = FilePatchItem.buildURI(filePath, this.props.workingDirectoryPath, stagingStatus); const filePatchItem = await this.props.workspace.open( uri, {pending: true, activatePane: activate, activateItem: activate, pane}, ); From 0e3e7d39b5768d23a774cfe7193804c08bda3896 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Jun 2018 13:18:24 -0400 Subject: [PATCH 0128/4847] Use a PresentedFilePatch to render --- lib/views/file-patch-view.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/views/file-patch-view.js b/lib/views/file-patch-view.js index f774c89437..f6244e056a 100644 --- a/lib/views/file-patch-view.js +++ b/lib/views/file-patch-view.js @@ -21,18 +21,27 @@ export default class FilePatchView extends React.Component { this.state = { selection: new FilePatchSelection(this.props.filePatch.getHunks()), + presentedFilePatch: this.props.filePatch.present(), }; } - render() { - const text = this.props.filePatch.getHunks().map(h => h.toString()).join('\n'); + static getDerivedStateFromProps(props, state) { + if (props.filePatch !== state.presentedFilePatch.getFilePatch()) { + return { + presentedFilePatch: props.filePatch.present(), + }; + } + + return null; + } + render() { return (
- + {this.renderFileHeader()} From d6189565cd6a618d65a9fb51c2608efa508f146d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Jun 2018 14:53:55 -0400 Subject: [PATCH 0129/4847] FilePatchItem tests --- lib/items/file-patch-item.js | 25 +++---- lib/prop-types.js | 4 ++ test/items/file-patch-item.test.js | 102 +++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 12 deletions(-) create mode 100644 test/items/file-patch-item.test.js diff --git a/lib/items/file-patch-item.js b/lib/items/file-patch-item.js index 1c02262dac..3ab27842fc 100644 --- a/lib/items/file-patch-item.js +++ b/lib/items/file-patch-item.js @@ -2,23 +2,24 @@ import React from 'react'; import PropTypes from 'prop-types'; import {Emitter} from 'event-kit'; +import {WorkdirContextPoolPropType} from '../prop-types'; import FilePatchContainer from '../containers/file-patch-container'; export default class FilePatchItem extends React.Component { static propTypes = { - repository: PropTypes.object.isRequired, - stagingStatus: PropTypes.oneOf(['staged', 'unstaged']), - relPath: PropTypes.string.isRequired, + workdirContextPool: WorkdirContextPoolPropType.isRequired, - tooltips: PropTypes.object.isRequired, + relPath: PropTypes.string.isRequired, + workingDirectory: PropTypes.string.isRequired, + stagingStatus: PropTypes.oneOf(['staged', 'unstaged']), } - static uriPattern = 'atom-github://file-patch/{relPath...}?workdir={workdir}&stagingStatus={stagingStatus}' + static uriPattern = 'atom-github://file-patch/{relPath...}?workdir={workingDirectory}&stagingStatus={stagingStatus}' - static buildURI(relPath, workdir, stagingStatus) { + static buildURI(relPath, workingDirectory, stagingStatus) { return 'atom-github://file-patch/' + relPath + - `?workdir=${encodeURIComponent(workdir)}` + + `?workdir=${encodeURIComponent(workingDirectory)}` + `&stagingStatus=${encodeURIComponent(stagingStatus)}`; } @@ -60,12 +61,12 @@ export default class FilePatchItem extends React.Component { } render() { + const repository = this.props.workdirContextPool.getContext(this.props.workingDirectory).getRepository(); + return ( ); } @@ -86,6 +87,6 @@ export default class FilePatchItem extends React.Component { } getWorkingDirectory() { - return this.props.repository.getWorkingDirectoryPath(); + return this.props.workingDirectory; } } diff --git a/lib/prop-types.js b/lib/prop-types.js index 2d17a1994a..31425b7db5 100644 --- a/lib/prop-types.js +++ b/lib/prop-types.js @@ -10,6 +10,10 @@ export const DOMNodePropType = (props, propName, componentName) => { } }; +export const WorkdirContextPoolPropType = PropTypes.shape({ + getContext: PropTypes.func.isRequired, +}); + export const RemotePropType = PropTypes.shape({ getName: PropTypes.func.isRequired, getUrl: PropTypes.func.isRequired, diff --git a/test/items/file-patch-item.test.js b/test/items/file-patch-item.test.js new file mode 100644 index 0000000000..90a0124db5 --- /dev/null +++ b/test/items/file-patch-item.test.js @@ -0,0 +1,102 @@ +import path from 'path'; +import React from 'react'; +import {mount} from 'enzyme'; + +import PaneItem from '../../lib/atom/pane-item'; +import FilePatchItem from '../../lib/items/file-patch-item'; +import WorkdirContextPool from '../../lib/models/workdir-context-pool'; +import {cloneRepository, buildRepository} from '../helpers'; + +describe('FilePatchItem', function() { + let atomEnv, repository, pool; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + + const workdirPath = await cloneRepository(); + repository = await buildRepository(workdirPath); + + pool = new WorkdirContextPool({ + workspace: atomEnv.workspace, + }); + repository = pool.add(workdirPath).getRepository(); + }); + + afterEach(function() { + atomEnv.destroy(); + pool.clear(); + }); + + function buildPaneApp(overrideProps = {}) { + const props = { + workdirContextPool: pool, + tooltips: atomEnv.tooltips, + ...overrideProps, + }; + + return ( + + {({itemHolder, params}) => { + return ( + + ); + }} + + ); + } + + function open(wrapper, options = {}) { + const opts = { + relPath: 'a.txt', + workingDirectory: repository.getWorkingDirectoryPath(), + stagingStatus: 'unstaged', + ...options, + }; + const uri = FilePatchItem.buildURI(opts.relPath, opts.workingDirectory, opts.stagingStatus); + return atomEnv.workspace.open(uri); + } + + it('locates the repository from the context pool', async function() { + const wrapper = mount(buildPaneApp()); + await open(wrapper); + + assert.strictEqual(wrapper.update().find('FilePatchContainer').prop('repository'), repository); + }); + + it('passes an absent repository if the working directory is unrecognized', async function() { + const wrapper = mount(buildPaneApp()); + await open(wrapper, {workingDirectory: '/nope'}); + + assert.isTrue(wrapper.update().find('FilePatchContainer').prop('repository').isAbsent()); + }); + + it('passes other props to the container', async function() { + const other = Symbol('other'); + const wrapper = mount(buildPaneApp({other})); + await open(wrapper); + + assert.strictEqual(wrapper.update().find('FilePatchContainer').prop('other'), other); + }); + + describe('getTitle()', function() { + it('renders an unstaged title', async function() { + const wrapper = mount(buildPaneApp()); + const item = await open(wrapper, {stagingStatus: 'unstaged'}); + + assert.strictEqual(item.getTitle(), 'Unstaged Changes: a.txt'); + }); + + it('renders a staged title', async function() { + const wrapper = mount(buildPaneApp()); + const item = await open(wrapper, {stagingStatus: 'staged'}); + + assert.strictEqual(item.getTitle(), 'Staged Changes: a.txt'); + }); + }); +}); From 46a67c57d2d7e5cdb08ecc0b6d997208dbb96b4d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Jun 2018 14:54:28 -0400 Subject: [PATCH 0130/4847] Return null for an empty patch for now --- lib/containers/file-patch-container.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/containers/file-patch-container.js b/lib/containers/file-patch-container.js index 9e5d5a4eee..3d7b31d89d 100644 --- a/lib/containers/file-patch-container.js +++ b/lib/containers/file-patch-container.js @@ -41,6 +41,10 @@ export default class FilePatchContainer extends React.Component { return null; } + if (data.filePatch === null) { + return null; + } + return ( Date: Wed, 6 Jun 2018 14:56:42 -0400 Subject: [PATCH 0131/4847] Repository is created from the context pool --- test/items/file-patch-item.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/items/file-patch-item.test.js b/test/items/file-patch-item.test.js index 90a0124db5..d588233824 100644 --- a/test/items/file-patch-item.test.js +++ b/test/items/file-patch-item.test.js @@ -5,7 +5,7 @@ import {mount} from 'enzyme'; import PaneItem from '../../lib/atom/pane-item'; import FilePatchItem from '../../lib/items/file-patch-item'; import WorkdirContextPool from '../../lib/models/workdir-context-pool'; -import {cloneRepository, buildRepository} from '../helpers'; +import {cloneRepository} from '../helpers'; describe('FilePatchItem', function() { let atomEnv, repository, pool; @@ -14,7 +14,6 @@ describe('FilePatchItem', function() { atomEnv = global.buildAtomEnvironment(); const workdirPath = await cloneRepository(); - repository = await buildRepository(workdirPath); pool = new WorkdirContextPool({ workspace: atomEnv.workspace, From b6b92f937424b0ae48771cb33ecd07d826677c60 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Jun 2018 16:05:34 -0400 Subject: [PATCH 0132/4847] FilePatchContainer tests --- lib/containers/file-patch-container.js | 16 +++-- test/containers/file-patch-container.test.js | 65 ++++++++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 test/containers/file-patch-container.test.js diff --git a/lib/containers/file-patch-container.js b/lib/containers/file-patch-container.js index 3d7b31d89d..5375d24f72 100644 --- a/lib/containers/file-patch-container.js +++ b/lib/containers/file-patch-container.js @@ -4,6 +4,7 @@ import yubikiri from 'yubikiri'; import {autobind} from '../helpers'; import ObserveModel from '../views/observe-model'; +import LoadingView from '../views/loading-view'; import FilePatchController from '../controllers/file-patch-controller'; export default class FilePatchContainer extends React.Component { @@ -38,20 +39,27 @@ export default class FilePatchContainer extends React.Component { renderWithData(data) { if (data === null) { - return null; + return ; } if (data.filePatch === null) { - return null; + return this.renderEmptyPatchMessage(); } return ( ); } + + renderEmptyPatchMessage() { + return ( +
+ No changes to display +
+ ); + } } diff --git a/test/containers/file-patch-container.test.js b/test/containers/file-patch-container.test.js new file mode 100644 index 0000000000..2f01eb3772 --- /dev/null +++ b/test/containers/file-patch-container.test.js @@ -0,0 +1,65 @@ +import path from 'path'; +import fs from 'fs-extra'; +import React from 'react'; +import {mount} from 'enzyme'; + +import FilePatchContainer from '../../lib/containers/file-patch-container'; +import {cloneRepository, buildRepository} from '../helpers'; + +describe('FilePatchContainer', function() { + let atomEnv, repository; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + + const workdirPath = await cloneRepository(); + repository = await buildRepository(workdirPath); + sinon.spy(repository, 'getFilePatchForPath'); + sinon.spy(repository, 'isPartiallyStaged'); + + // a.txt: unstaged changes + await fs.writeFile(path.join(workdirPath, 'a.txt'), 'changed\n'); + + // b.txt: staged changes + await fs.writeFile(path.join(workdirPath, 'b.txt'), 'changed\n'); + await repository.stageFiles(['b.txt']); + + // c.txt: untouched + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + function buildApp(overrideProps = {}) { + const props = { + repository, + stagingStatus: 'unstaged', + relPath: 'a.txt', + ...overrideProps, + }; + + return ; + } + + it('renders a loading spinner before file patch data arrives', function() { + const wrapper = mount(buildApp()); + assert.isTrue(wrapper.find('LoadingView').exists()); + }); + + it('renders a message for an empty patch', async function() { + const wrapper = mount(buildApp({relPath: 'c.txt'})); + await assert.async.isTrue(wrapper.update().find('span.icon-info').exists()); + }); + + it('renders a FilePatchView', async function() { + const wrapper = mount(buildApp({relPath: 'a.txt', stagingStatus: 'unstaged'})); + await assert.async.isTrue(wrapper.update().find('FilePatchView').exists()); + }); + + it('passes unrecognized props to the FilePatchView', async function() { + const extra = Symbol('extra'); + const wrapper = mount(buildApp({relPath: 'a.txt', stagingStatus: 'unstaged', extra})); + await assert.async.strictEqual(wrapper.update().find('FilePatchView').prop('extra'), extra); + }); +}); From 3dd99de35a7d7aaf9d480d4b5d0649b6bf644acf Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Jun 2018 16:16:40 -0400 Subject: [PATCH 0133/4847] Stub test for the stub FilePatchController --- .../controllers/file-patch-controller.test.js | 820 +----------------- .../file-patch-controller.test.old.js | 811 +++++++++++++++++ 2 files changed, 838 insertions(+), 793 deletions(-) create mode 100644 test/controllers/file-patch-controller.test.old.js diff --git a/test/controllers/file-patch-controller.test.js b/test/controllers/file-patch-controller.test.js index a7b075e8ec..ad18b3cb4d 100644 --- a/test/controllers/file-patch-controller.test.js +++ b/test/controllers/file-patch-controller.test.js @@ -1,811 +1,45 @@ -import React from 'react'; -import {shallow, mount} from 'enzyme'; -import until from 'test-until'; - -import fs from 'fs'; import path from 'path'; +import fs from 'fs'; +import React from 'react'; +import {mount} from 'enzyme'; -import {cloneRepository, buildRepository} from '../helpers'; -import FilePatch from '../../lib/models/file-patch'; import FilePatchController from '../../lib/controllers/file-patch-controller'; -import Hunk from '../../lib/models/hunk'; -import HunkLine from '../../lib/models/hunk-line'; -import ResolutionProgress from '../../lib/models/conflicts/resolution-progress'; -import Switchboard from '../../lib/switchboard'; - -function createFilePatch(oldFilePath, newFilePath, status, hunks) { - const oldFile = new FilePatch.File({path: oldFilePath}); - const newFile = new FilePatch.File({path: newFilePath}); - const patch = new FilePatch.Patch({status, hunks}); - - return new FilePatch(oldFile, newFile, patch); -} - -let atomEnv, commandRegistry, tooltips, deserializers; -let switchboard, getFilePatchForPath; -let discardLines, didSurfaceFile, didDiveIntoFilePath, quietlySelectItem, undoLastDiscard, openFiles, getRepositoryForWorkdir; -let getSelectedStagingViewItems, resolutionProgress; - -function createComponent(repository, filePath) { - atomEnv = global.buildAtomEnvironment(); - commandRegistry = atomEnv.commands; - deserializers = atomEnv.deserializers; - tooltips = atomEnv.tooltips; - - switchboard = new Switchboard(); - - discardLines = sinon.spy(); - didSurfaceFile = sinon.spy(); - didDiveIntoFilePath = sinon.spy(); - quietlySelectItem = sinon.spy(); - undoLastDiscard = sinon.spy(); - openFiles = sinon.spy(); - getSelectedStagingViewItems = sinon.spy(); +import {cloneRepository, buildRepository} from '../helpers'; - getRepositoryForWorkdir = () => repository; - resolutionProgress = new ResolutionProgress(); +describe('FilePatchController', function() { + let atomEnv, repository, filePatch; - FilePatchController.resetConfirmedLargeFilePatches(); + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); - return ( - - ); -} + const workdirPath = await cloneRepository(); + repository = await buildRepository(workdirPath); -async function refreshRepository(wrapper) { - const workDir = wrapper.prop('workingDirectoryPath'); - const repository = wrapper.prop('getRepositoryForWorkdir')(workDir); + // a.txt: unstaged changes + await fs.writeFile(path.join(workdirPath, 'a.txt'), 'changed\n'); - const promise = wrapper.prop('switchboard').getFinishRepositoryRefreshPromise(); - repository.refresh(); - await promise; - wrapper.update(); -} + filePatch = await repository.getFilePatchForPath('a.txt', {staged: false}); + }); -describe('FilePatchController', function() { afterEach(function() { atomEnv.destroy(); }); - describe('unit tests', function() { - let workdirPath, repository, filePath, component; - beforeEach(async function() { - workdirPath = await cloneRepository('multi-line-file'); - repository = await buildRepository(workdirPath); - filePath = 'sample.js'; - component = createComponent(repository, filePath); - - getFilePatchForPath = sinon.stub(repository, 'getFilePatchForPath'); - }); - - describe('when the FilePatch is too large', function() { - it('renders a confirmation widget', async function() { - const hunk1 = new Hunk(0, 0, 1, 1, '', [ - new HunkLine('line-1', 'added', 1, 1), - new HunkLine('line-2', 'added', 2, 2), - new HunkLine('line-3', 'added', 3, 3), - new HunkLine('line-4', 'added', 4, 4), - new HunkLine('line-5', 'added', 5, 5), - new HunkLine('line-6', 'added', 6, 6), - ]); - const filePatch = createFilePatch(filePath, filePath, 'modified', [hunk1]); - - getFilePatchForPath.returns(filePatch); - - const wrapper = mount(React.cloneElement(component, {largeDiffByteThreshold: 5})); - - await assert.async.match(wrapper.text(), /large .+ diff/); - }); - - it('renders the full diff when the confirmation is clicked', async function() { - const hunk = new Hunk(0, 0, 1, 1, '', [ - new HunkLine('line-1', 'added', 1, 1), - new HunkLine('line-2', 'added', 2, 2), - new HunkLine('line-3', 'added', 3, 3), - new HunkLine('line-4', 'added', 4, 4), - new HunkLine('line-5', 'added', 5, 5), - new HunkLine('line-6', 'added', 6, 6), - ]); - const filePatch = createFilePatch(filePath, filePath, 'modified', [hunk]); - getFilePatchForPath.returns(filePatch); - - const wrapper = mount(React.cloneElement(component, {largeDiffByteThreshold: 5})); - - await assert.async.isTrue(wrapper.update().find('.large-file-patch').exists()); - wrapper.find('.large-file-patch').find('button').simulate('click'); - - assert.isTrue(wrapper.find('HunkView').exists()); - }); - - it('renders the full diff if the file has been confirmed before', async function() { - const hunk = new Hunk(0, 0, 1, 1, '', [ - new HunkLine('line-1', 'added', 1, 1), - new HunkLine('line-2', 'added', 2, 2), - new HunkLine('line-3', 'added', 3, 3), - new HunkLine('line-4', 'added', 4, 4), - new HunkLine('line-5', 'added', 5, 5), - new HunkLine('line-6', 'added', 6, 6), - ]); - const filePatch1 = createFilePatch(filePath, filePath, 'modified', [hunk]); - const filePatch2 = createFilePatch('b.txt', 'b.txt', 'modified', [hunk]); - - getFilePatchForPath.returns(filePatch1); - - const wrapper = mount(React.cloneElement(component, { - filePath: filePatch1.getPath(), largeDiffByteThreshold: 5, - })); - - await assert.async.isTrue(wrapper.update().find('.large-file-patch').exists()); - wrapper.find('.large-file-patch').find('button').simulate('click'); - assert.isTrue(wrapper.find('HunkView').exists()); - - getFilePatchForPath.returns(filePatch2); - wrapper.setProps({filePath: filePatch2.getPath()}); - await assert.async.isTrue(wrapper.update().find('.large-file-patch').exists()); - - getFilePatchForPath.returns(filePatch1); - wrapper.setProps({filePath: filePatch1.getPath()}); - assert.isTrue(wrapper.update().find('HunkView').exists()); - }); - }); - - describe('onRepoRefresh', function() { - it('sets the correct FilePatch as state', async function() { - repository.getFilePatchForPath.restore(); - fs.writeFileSync(path.join(workdirPath, filePath), 'change', 'utf8'); - - const wrapper = mount(component); - - await assert.async.isNotNull(wrapper.state('filePatch')); - - const originalFilePatch = wrapper.state('filePatch'); - assert.equal(wrapper.state('stagingStatus'), 'unstaged'); - - fs.writeFileSync(path.join(workdirPath, 'file.txt'), 'change\nand again!', 'utf8'); - await refreshRepository(wrapper); - - assert.notEqual(originalFilePatch, wrapper.state('filePatch')); - assert.equal(wrapper.state('stagingStatus'), 'unstaged'); - }); - }); - - it('renders FilePatchView only if FilePatch has hunks', async function() { - const emptyFilePatch = createFilePatch(filePath, filePath, 'modified', []); - getFilePatchForPath.returns(emptyFilePatch); - - const wrapper = mount(component); - - assert.isTrue(wrapper.find('FilePatchView').exists()); - assert.isTrue(wrapper.find('FilePatchView').text().includes('File has no contents')); - - const hunk1 = new Hunk(0, 0, 1, 1, '', [new HunkLine('line-1', 'added', 1, 1)]); - const filePatch = createFilePatch(filePath, filePath, 'modified', [hunk1]); - getFilePatchForPath.returns(filePatch); - - wrapper.instance().onRepoRefresh(repository); - - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - assert.isTrue(wrapper.find('HunkView').text().includes('@@ -0,1 +0,1 @@')); - }); - - it('updates the FilePatch after a repo update', async function() { - const hunk1 = new Hunk(5, 5, 2, 1, '', [new HunkLine('line-1', 'added', -1, 5)]); - const hunk2 = new Hunk(8, 8, 1, 1, '', [new HunkLine('line-5', 'deleted', 8, -1)]); - const filePatch0 = createFilePatch(filePath, filePath, 'modified', [hunk1, hunk2]); - getFilePatchForPath.returns(filePatch0); - - const wrapper = shallow(component); - - let view0; - await until(() => { - view0 = wrapper.update().find('FilePatchView').shallow(); - return view0.find({hunk: hunk1}).exists(); - }); - assert.isTrue(view0.find({hunk: hunk2}).exists()); - - const hunk3 = new Hunk(8, 8, 1, 1, '', [new HunkLine('line-10', 'modified', 10, 10)]); - const filePatch1 = createFilePatch(filePath, filePath, 'modified', [hunk1, hunk3]); - getFilePatchForPath.returns(filePatch1); - - wrapper.instance().onRepoRefresh(repository); - let view1; - await until(() => { - view1 = wrapper.update().find('FilePatchView').shallow(); - return view1.find({hunk: hunk3}).exists(); - }); - assert.isTrue(view1.find({hunk: hunk1}).exists()); - assert.isFalse(view1.find({hunk: hunk2}).exists()); - }); - - it('invokes a didSurfaceFile callback with the current file path', async function() { - const filePatch = createFilePatch(filePath, filePath, 'modified', [new Hunk(1, 1, 1, 3, '', [])]); - getFilePatchForPath.returns(filePatch); - - const wrapper = mount(component); - - await assert.async.isTrue(wrapper.update().find('Commands').exists()); - commandRegistry.dispatch(wrapper.find('FilePatchView').getDOMNode(), 'core:move-right'); - assert.isTrue(didSurfaceFile.calledWith(filePath, 'unstaged')); - }); - - describe('openCurrentFile({lineNumber})', () => { - it('sets the cursor on the correct line of the opened text editor', async function() { - const editorSpy = { - relativePath: null, - scrollToBufferPosition: sinon.spy(), - setCursorBufferPosition: sinon.spy(), - }; - - const openFilesStub = relativePaths => { - assert.lengthOf(relativePaths, 1); - editorSpy.relativePath = relativePaths[0]; - return Promise.resolve([editorSpy]); - }; - - const hunk = new Hunk(5, 5, 2, 1, '', [new HunkLine('line-1', 'added', -1, 5)]); - const filePatch = createFilePatch(filePath, filePath, 'modified', [hunk]); - getFilePatchForPath.returns(filePatch); - - const wrapper = mount(React.cloneElement(component, {openFiles: openFilesStub})); - - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - - wrapper.find('LineView').simulate('mousedown', {button: 0, detail: 1}); - window.dispatchEvent(new MouseEvent('mouseup')); - commandRegistry.dispatch(wrapper.find('FilePatchView').getDOMNode(), 'github:open-file'); - wrapper.update(); - - await assert.async.isTrue(editorSpy.setCursorBufferPosition.called); - - assert.isTrue(editorSpy.relativePath === filePath); - - const scrollCall = editorSpy.scrollToBufferPosition.firstCall; - assert.isTrue(scrollCall.args[0].isEqual([4, 0])); - assert.deepEqual(scrollCall.args[1], {center: true}); - - const cursorCall = editorSpy.setCursorBufferPosition.firstCall; - assert.isTrue(cursorCall.args[0].isEqual([4, 0])); - }); - }); - }); - - describe('integration tests', function() { - describe('handling symlink files', function() { - async function indexModeAndOid(repository, filename) { - const output = await repository.git.exec(['ls-files', '-s', '--', filename]); - if (output) { - const parts = output.split(' '); - return {mode: parts[0], oid: parts[1]}; - } else { - return null; - } - } - - it('unstages added lines that don\'t require symlink change', async function() { - const workingDirPath = await cloneRepository('symlinks'); - const repository = await buildRepository(workingDirPath); - - // correctly handle symlinks on Windows - await repository.git.exec(['config', 'core.symlinks', 'true']); - - const deletedSymlinkAddedFilePath = 'symlink.txt'; - fs.unlinkSync(path.join(workingDirPath, deletedSymlinkAddedFilePath)); - fs.writeFileSync(path.join(workingDirPath, deletedSymlinkAddedFilePath), 'qux\nfoo\nbar\nbaz\nzoo\n', 'utf8'); - - // Stage whole file - await repository.stageFiles([deletedSymlinkAddedFilePath]); - - const component = createComponent(repository, deletedSymlinkAddedFilePath); - const wrapper = mount(React.cloneElement(component, {filePath: deletedSymlinkAddedFilePath, initialStagingStatus: 'staged'})); - - // index shows symlink deltion and added lines - assert.autocrlfEqual(await repository.readFileFromIndex(deletedSymlinkAddedFilePath), 'qux\nfoo\nbar\nbaz\nzoo\n'); - assert.equal((await indexModeAndOid(repository, deletedSymlinkAddedFilePath)).mode, '100644'); - - // Unstage a couple added lines, but not all - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - const opPromise0 = switchboard.getFinishStageOperationPromise(); - const hunkView0 = wrapper.find('HunkView').at(0); - hunkView0.find('LineView').at(1).find('.github-HunkView-line').simulate('mousedown', {button: 0, detail: 1}); - hunkView0.find('LineView').at(2).find('.github-HunkView-line').simulate('mousemove', {}); - window.dispatchEvent(new MouseEvent('mouseup')); - hunkView0.find('button.github-HunkView-stageButton').simulate('click'); - await opPromise0; - - await refreshRepository(wrapper); - - // index shows symlink deletions still staged, only a couple of lines have been unstaged - assert.equal((await indexModeAndOid(repository, deletedSymlinkAddedFilePath)).mode, '100644'); - assert.autocrlfEqual(await repository.readFileFromIndex(deletedSymlinkAddedFilePath), 'qux\nbaz\nzoo\n'); - }); - - it('stages deleted lines that don\'t require symlink change', async function() { - const workingDirPath = await cloneRepository('symlinks'); - const repository = await buildRepository(workingDirPath); - - const deletedFileAddedSymlinkPath = 'a.txt'; - fs.unlinkSync(path.join(workingDirPath, deletedFileAddedSymlinkPath)); - fs.symlinkSync(path.join(workingDirPath, 'regular-file.txt'), path.join(workingDirPath, deletedFileAddedSymlinkPath)); - - const component = createComponent(repository, deletedFileAddedSymlinkPath); - const wrapper = mount(React.cloneElement(component, {filePath: deletedFileAddedSymlinkPath, initialStagingStatus: 'unstaged'})); - - // index shows file is not a symlink, no deleted lines - assert.equal((await indexModeAndOid(repository, deletedFileAddedSymlinkPath)).mode, '100644'); - assert.autocrlfEqual(await repository.readFileFromIndex(deletedFileAddedSymlinkPath), 'foo\nbar\nbaz\n\n'); - - // stage a couple of lines, but not all - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - const opPromise0 = switchboard.getFinishStageOperationPromise(); - const hunkView0 = wrapper.find('HunkView').at(0); - hunkView0.find('LineView').at(1).find('.github-HunkView-line').simulate('mousedown', {button: 0, detail: 1}); - hunkView0.find('LineView').at(2).find('.github-HunkView-line').simulate('mousemove', {}); - window.dispatchEvent(new MouseEvent('mouseup')); - hunkView0.find('button.github-HunkView-stageButton').simulate('click'); - await opPromise0; - - await refreshRepository(wrapper); - - // index shows symlink change has not been staged, a couple of lines have been deleted - assert.equal((await indexModeAndOid(repository, deletedFileAddedSymlinkPath)).mode, '100644'); - assert.autocrlfEqual(await repository.readFileFromIndex(deletedFileAddedSymlinkPath), 'foo\n\n'); - }); - - it('stages symlink change when staging added lines that depend on change', async function() { - const workingDirPath = await cloneRepository('symlinks'); - const repository = await buildRepository(workingDirPath); - - // correctly handle symlinks on Windows - await repository.git.exec(['config', 'core.symlinks', 'true']); - - const deletedSymlinkAddedFilePath = 'symlink.txt'; - fs.unlinkSync(path.join(workingDirPath, deletedSymlinkAddedFilePath)); - fs.writeFileSync(path.join(workingDirPath, deletedSymlinkAddedFilePath), 'qux\nfoo\nbar\nbaz\nzoo\n', 'utf8'); - - const component = createComponent(repository, deletedSymlinkAddedFilePath); - const wrapper = mount(React.cloneElement(component, {filePath: deletedSymlinkAddedFilePath})); - - // index shows file is symlink - assert.equal((await indexModeAndOid(repository, deletedSymlinkAddedFilePath)).mode, '120000'); - - // Stage a couple added lines, but not all - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - const opPromise0 = switchboard.getFinishStageOperationPromise(); - const hunkView0 = wrapper.find('HunkView').at(0); - hunkView0.find('LineView').at(1).find('.github-HunkView-line').simulate('mousedown', {button: 0, detail: 1}); - hunkView0.find('LineView').at(2).find('.github-HunkView-line').simulate('mousemove', {}); - window.dispatchEvent(new MouseEvent('mouseup')); - hunkView0.find('button.github-HunkView-stageButton').simulate('click'); - await opPromise0; - - await refreshRepository(wrapper); - - // index no longer shows file is symlink (symlink has been deleted), now a regular file with contents - assert.equal((await indexModeAndOid(repository, deletedSymlinkAddedFilePath)).mode, '100644'); - assert.autocrlfEqual(await repository.readFileFromIndex(deletedSymlinkAddedFilePath), 'foo\nbar\n'); - }); - - it('unstages symlink change when unstaging deleted lines that depend on change', async function() { - const workingDirPath = await cloneRepository('symlinks'); - const repository = await buildRepository(workingDirPath); - - const deletedFileAddedSymlinkPath = 'a.txt'; - fs.unlinkSync(path.join(workingDirPath, deletedFileAddedSymlinkPath)); - fs.symlinkSync(path.join(workingDirPath, 'regular-file.txt'), path.join(workingDirPath, deletedFileAddedSymlinkPath)); - await repository.stageFiles([deletedFileAddedSymlinkPath]); - - const component = createComponent(repository, deletedFileAddedSymlinkPath); - const wrapper = mount(React.cloneElement(component, {filePath: deletedFileAddedSymlinkPath, initialStagingStatus: 'staged'})); - - // index shows file is symlink - assert.equal((await indexModeAndOid(repository, deletedFileAddedSymlinkPath)).mode, '120000'); - - // unstage a couple of lines, but not all - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - const opPromise0 = switchboard.getFinishStageOperationPromise(); - const hunkView0 = wrapper.find('HunkView').at(0); - hunkView0.find('LineView').at(1).find('.github-HunkView-line').simulate('mousedown', {button: 0, detail: 1}); - hunkView0.find('LineView').at(2).find('.github-HunkView-line').simulate('mousemove', {}); - window.dispatchEvent(new MouseEvent('mouseup')); - hunkView0.find('button.github-HunkView-stageButton').simulate('click'); - await opPromise0; - - await refreshRepository(wrapper); - - // index no longer shows file is symlink (symlink creation has been unstaged), shows contents of file that existed prior to symlink - assert.equal((await indexModeAndOid(repository, deletedFileAddedSymlinkPath)).mode, '100644'); - assert.autocrlfEqual(await repository.readFileFromIndex(deletedFileAddedSymlinkPath), 'bar\nbaz\n'); - }); - - it('stages file deletion when all deleted lines are staged', async function() { - const workingDirPath = await cloneRepository('symlinks'); - const repository = await buildRepository(workingDirPath); - await repository.getLoadPromise(); - - const deletedFileAddedSymlinkPath = 'a.txt'; - fs.unlinkSync(path.join(workingDirPath, deletedFileAddedSymlinkPath)); - fs.symlinkSync(path.join(workingDirPath, 'regular-file.txt'), path.join(workingDirPath, deletedFileAddedSymlinkPath)); - - const component = createComponent(repository, deletedFileAddedSymlinkPath); - const wrapper = mount(React.cloneElement(component, {filePath: deletedFileAddedSymlinkPath})); - - assert.equal((await indexModeAndOid(repository, deletedFileAddedSymlinkPath)).mode, '100644'); - - // stage all deleted lines - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - const opPromise0 = switchboard.getFinishStageOperationPromise(); - const hunkView0 = wrapper.find('HunkView').at(0); - hunkView0.find('.github-HunkView-title').simulate('click'); - hunkView0.find('button.github-HunkView-stageButton').simulate('click'); - await opPromise0; - - await refreshRepository(wrapper); - - // File is not on index, file deletion has been staged - assert.isNull(await indexModeAndOid(repository, deletedFileAddedSymlinkPath)); - const {stagedFiles, unstagedFiles} = await repository.getStatusesForChangedFiles(); - assert.equal(unstagedFiles[deletedFileAddedSymlinkPath], 'added'); - assert.equal(stagedFiles[deletedFileAddedSymlinkPath], 'deleted'); - }); - - it('unstages file creation when all added lines are unstaged', async function() { - const workingDirPath = await cloneRepository('symlinks'); - const repository = await buildRepository(workingDirPath); - - await repository.git.exec(['config', 'core.symlinks', 'true']); - - const deletedSymlinkAddedFilePath = 'symlink.txt'; - fs.unlinkSync(path.join(workingDirPath, deletedSymlinkAddedFilePath)); - fs.writeFileSync(path.join(workingDirPath, deletedSymlinkAddedFilePath), 'qux\nfoo\nbar\nbaz\nzoo\n', 'utf8'); - await repository.stageFiles([deletedSymlinkAddedFilePath]); - - const component = createComponent(repository, deletedSymlinkAddedFilePath); - const wrapper = mount(React.cloneElement(component, {filePath: deletedSymlinkAddedFilePath, initialStagingStatus: 'staged'})); - - assert.equal((await indexModeAndOid(repository, deletedSymlinkAddedFilePath)).mode, '100644'); - - // unstage all added lines - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - const opPromise0 = switchboard.getFinishStageOperationPromise(); - const hunkView0 = wrapper.find('HunkView').at(0); - hunkView0.find('.github-HunkView-title').simulate('click'); - hunkView0.find('button.github-HunkView-stageButton').simulate('click'); - await opPromise0; - - await refreshRepository(wrapper); - - // File is not on index, file creation has been unstaged - assert.isNull(await indexModeAndOid(repository, deletedSymlinkAddedFilePath)); - const {stagedFiles, unstagedFiles} = await repository.getStatusesForChangedFiles(); - assert.equal(unstagedFiles[deletedSymlinkAddedFilePath], 'added'); - assert.equal(stagedFiles[deletedSymlinkAddedFilePath], 'deleted'); - }); - }); - - describe('handling non-symlink changes', function() { - let workdirPath, repository, filePath, component; - beforeEach(async function() { - workdirPath = await cloneRepository('multi-line-file'); - repository = await buildRepository(workdirPath); - filePath = 'sample.js'; - component = createComponent(repository, filePath); - }); - - it('stages and unstages hunks when the stage button is clicked on hunk views with no individual lines selected', async function() { - const absFilePath = path.join(workdirPath, filePath); - const originalLines = fs.readFileSync(absFilePath, 'utf8').split('\n'); - const unstagedLines = originalLines.slice(); - unstagedLines.splice(1, 1, - 'this is a modified line', - 'this is a new line', - 'this is another new line', - ); - unstagedLines.splice(11, 2, 'this is a modified line'); - fs.writeFileSync(absFilePath, unstagedLines.join('\n')); - - const wrapper = mount(component); - - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - commandRegistry.dispatch(wrapper.find('FilePatchView').getDOMNode(), 'core:move-down'); - - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - const hunkView0 = wrapper.find('HunkView').at(0); - assert.isFalse(hunkView0.prop('isSelected')); - const opPromise0 = switchboard.getFinishStageOperationPromise(); - hunkView0.find('button.github-HunkView-stageButton').simulate('click'); - await opPromise0; - - const expectedStagedLines = originalLines.slice(); - expectedStagedLines.splice(1, 1, - 'this is a modified line', - 'this is a new line', - 'this is another new line', - ); - assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), expectedStagedLines.join('\n')); - const updatePromise0 = switchboard.getChangePatchPromise(); - const stagedFilePatch = await repository.getFilePatchForPath('sample.js', {staged: true}); - wrapper.setState({ - stagingStatus: 'staged', - filePatch: stagedFilePatch, - }); - await updatePromise0; - const hunkView1 = wrapper.find('HunkView').at(0); - const opPromise1 = switchboard.getFinishStageOperationPromise(); - hunkView1.find('button.github-HunkView-stageButton').simulate('click'); - await opPromise1; - assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), originalLines.join('\n')); - }); - - it('stages and unstages individual lines when the stage button is clicked on a hunk with selected lines', async function() { - const absFilePath = path.join(workdirPath, filePath); - const originalLines = fs.readFileSync(absFilePath, 'utf8').split('\n'); - - // write some unstaged changes - const unstagedLines = originalLines.slice(); - unstagedLines.splice(1, 1, - 'this is a modified line', - 'this is a new line', - 'this is another new line', - ); - unstagedLines.splice(11, 2, 'this is a modified line'); - fs.writeFileSync(absFilePath, unstagedLines.join('\n')); - - // stage a subset of lines from first hunk - const wrapper = mount(component); - - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - const opPromise0 = switchboard.getFinishStageOperationPromise(); - const hunkView0 = wrapper.find('HunkView').at(0); - hunkView0.find('LineView').at(1).find('.github-HunkView-line').simulate('mousedown', {button: 0, detail: 1}); - hunkView0.find('LineView').at(3).find('.github-HunkView-line').simulate('mousemove', {}); - window.dispatchEvent(new MouseEvent('mouseup')); - hunkView0.find('button.github-HunkView-stageButton').simulate('click'); - await opPromise0; - - await refreshRepository(wrapper); - - const expectedLines0 = originalLines.slice(); - expectedLines0.splice(1, 1, - 'this is a modified line', - 'this is a new line', - ); - assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), expectedLines0.join('\n')); - - // stage remaining lines in hunk - const opPromise1 = switchboard.getFinishStageOperationPromise(); - wrapper.find('HunkView').at(0).find('button.github-HunkView-stageButton').simulate('click'); - await opPromise1; - - await refreshRepository(wrapper); - - const expectedLines1 = originalLines.slice(); - expectedLines1.splice(1, 1, - 'this is a modified line', - 'this is a new line', - 'this is another new line', - ); - assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), expectedLines1.join('\n')); - - // unstage a subset of lines from the first hunk - wrapper.setState({stagingStatus: 'staged'}); - await refreshRepository(wrapper); - - const hunkView2 = wrapper.find('HunkView').at(0); - hunkView2.find('LineView').at(1).find('.github-HunkView-line') - .simulate('mousedown', {button: 0, detail: 1}); - window.dispatchEvent(new MouseEvent('mouseup')); - hunkView2.find('LineView').at(2).find('.github-HunkView-line') - .simulate('mousedown', {button: 0, detail: 1, metaKey: true}); - window.dispatchEvent(new MouseEvent('mouseup')); - - const opPromise2 = switchboard.getFinishStageOperationPromise(); - hunkView2.find('button.github-HunkView-stageButton').simulate('click'); - await opPromise2; - - await refreshRepository(wrapper); - - const expectedLines2 = originalLines.slice(); - expectedLines2.splice(2, 0, - 'this is a new line', - 'this is another new line', - ); - assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), expectedLines2.join('\n')); - - // unstage the rest of the hunk - commandRegistry.dispatch(wrapper.find('FilePatchView').getDOMNode(), 'github:toggle-patch-selection-mode'); - - const opPromise3 = switchboard.getFinishStageOperationPromise(); - wrapper.find('HunkView').at(0).find('button.github-HunkView-stageButton').simulate('click'); - await opPromise3; - - assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), originalLines.join('\n')); - }); - - // https://github.com/atom/github/issues/417 - describe('when unstaging the last lines/hunks from a file', function() { - it('removes added files from index when last hunk is unstaged', async function() { - const absFilePath = path.join(workdirPath, 'new-file.txt'); - - fs.writeFileSync(absFilePath, 'foo\n'); - await repository.stageFiles(['new-file.txt']); - - const wrapper = mount(React.cloneElement(component, { - filePath: 'new-file.txt', - initialStagingStatus: 'staged', - })); - - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - - const opPromise = switchboard.getFinishStageOperationPromise(); - wrapper.find('HunkView').at(0).find('button.github-HunkView-stageButton').simulate('click'); - await opPromise; - - const stagedChanges = await repository.getStagedChanges(); - assert.equal(stagedChanges.length, 0); - }); - - it('removes added files from index when last lines are unstaged', async function() { - const absFilePath = path.join(workdirPath, 'new-file.txt'); - - fs.writeFileSync(absFilePath, 'foo\n'); - await repository.stageFiles(['new-file.txt']); - - const wrapper = mount(React.cloneElement(component, { - filePath: 'new-file.txt', - initialStagingStatus: 'staged', - })); - - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - - const viewNode = wrapper.find('FilePatchView').getDOMNode(); - commandRegistry.dispatch(viewNode, 'github:toggle-patch-selection-mode'); - commandRegistry.dispatch(viewNode, 'core:select-all'); - - const opPromise = switchboard.getFinishStageOperationPromise(); - wrapper.find('HunkView').at(0).find('button.github-HunkView-stageButton').simulate('click'); - await opPromise; - - const stagedChanges = await repository.getStagedChanges(); - assert.lengthOf(stagedChanges, 0); - }); - }); - - // https://github.com/atom/github/issues/341 - describe('when duplicate staging occurs', function() { - it('avoids patch conflicts with pending line staging operations', async function() { - const absFilePath = path.join(workdirPath, filePath); - const originalLines = fs.readFileSync(absFilePath, 'utf8').split('\n'); - - // write some unstaged changes - const unstagedLines = originalLines.slice(); - unstagedLines.splice(1, 0, - 'this is a modified line', - 'this is a new line', - 'this is another new line', - ); - unstagedLines.splice(11, 2, 'this is a modified line'); - fs.writeFileSync(absFilePath, unstagedLines.join('\n')); - - const wrapper = mount(component); - - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - const hunkView0 = wrapper.find('HunkView').at(0); - hunkView0.find('LineView').at(1).find('.github-HunkView-line') - .simulate('mousedown', {button: 0, detail: 1}); - window.dispatchEvent(new MouseEvent('mouseup')); - - // stage lines in rapid succession - // second stage action is a no-op since the first staging operation is in flight - const line1StagingPromise = switchboard.getFinishStageOperationPromise(); - hunkView0.find('.github-HunkView-stageButton').simulate('click'); - hunkView0.find('.github-HunkView-stageButton').simulate('click'); - await line1StagingPromise; - - const changePatchPromise = switchboard.getChangePatchPromise(); - - // assert that only line 1 has been staged - await refreshRepository(wrapper); // clear the cached file patches - let expectedLines = originalLines.slice(); - expectedLines.splice(1, 0, - 'this is a modified line', - ); - let actualLines = await repository.readFileFromIndex(filePath); - assert.autocrlfEqual(actualLines, expectedLines.join('\n')); - await changePatchPromise; - wrapper.update(); - - const hunkView1 = wrapper.find('HunkView').at(0); - hunkView1.find('LineView').at(2).find('.github-HunkView-line') - .simulate('mousedown', {button: 0, detail: 1}); - window.dispatchEvent(new MouseEvent('mouseup')); - const line2StagingPromise = switchboard.getFinishStageOperationPromise(); - hunkView1.find('.github-HunkView-stageButton').simulate('click'); - await line2StagingPromise; - - // assert that line 2 has now been staged - expectedLines = originalLines.slice(); - expectedLines.splice(1, 0, - 'this is a modified line', - 'this is a new line', - ); - actualLines = await repository.readFileFromIndex(filePath); - assert.autocrlfEqual(actualLines, expectedLines.join('\n')); - }); - - it('avoids patch conflicts with pending hunk staging operations', async function() { - const absFilePath = path.join(workdirPath, filePath); - const originalLines = fs.readFileSync(absFilePath, 'utf8').split('\n'); - - // write some unstaged changes - const unstagedLines = originalLines.slice(); - unstagedLines.splice(1, 0, - 'this is a modified line', - 'this is a new line', - 'this is another new line', - ); - unstagedLines.splice(11, 2, 'this is a modified line'); - fs.writeFileSync(absFilePath, unstagedLines.join('\n')); - - const wrapper = mount(component); - - await assert.async.isTrue(wrapper.update().find('HunkView').exists()); - - // ensure staging the same hunk twice does not cause issues - // second stage action is a no-op since the first staging operation is in flight - const hunk1StagingPromise = switchboard.getFinishStageOperationPromise(); - wrapper.find('HunkView').at(0).find('.github-HunkView-stageButton').simulate('click'); - wrapper.find('HunkView').at(0).find('.github-HunkView-stageButton').simulate('click'); - await hunk1StagingPromise; - - const patchPromise0 = switchboard.getChangePatchPromise(); - await refreshRepository(wrapper); // clear the cached file patches - const modifiedFilePatch = await repository.getFilePatchForPath(filePath); - wrapper.setState({filePatch: modifiedFilePatch}); - await patchPromise0; + function buildApp(overrideProps = {}) { + const props = { + stagingStatus: 'unstaged', + isPartiallyStaged: false, + filePatch, + ...overrideProps, + }; - let expectedLines = originalLines.slice(); - expectedLines.splice(1, 0, - 'this is a modified line', - 'this is a new line', - 'this is another new line', - ); - let actualLines = await repository.readFileFromIndex(filePath); - assert.autocrlfEqual(actualLines, expectedLines.join('\n')); + return ; + } - const hunk2StagingPromise = switchboard.getFinishStageOperationPromise(); - wrapper.find('HunkView').at(0).find('.github-HunkView-stageButton').simulate('click'); - await hunk2StagingPromise; + it('passes extra props to the FilePatchView', function() { + const extra = Symbol('extra'); + const wrapper = mount(buildApp({extra})); - expectedLines = originalLines.slice(); - expectedLines.splice(1, 0, - 'this is a modified line', - 'this is a new line', - 'this is another new line', - ); - expectedLines.splice(11, 2, 'this is a modified line'); - actualLines = await repository.readFileFromIndex(filePath); - assert.autocrlfEqual(actualLines, expectedLines.join('\n')); - }); - }); - }); + assert.strictEqual(wrapper.find('FilePatchView').prop('extra'), extra); }); }); diff --git a/test/controllers/file-patch-controller.test.old.js b/test/controllers/file-patch-controller.test.old.js new file mode 100644 index 0000000000..a7b075e8ec --- /dev/null +++ b/test/controllers/file-patch-controller.test.old.js @@ -0,0 +1,811 @@ +import React from 'react'; +import {shallow, mount} from 'enzyme'; +import until from 'test-until'; + +import fs from 'fs'; +import path from 'path'; + +import {cloneRepository, buildRepository} from '../helpers'; +import FilePatch from '../../lib/models/file-patch'; +import FilePatchController from '../../lib/controllers/file-patch-controller'; +import Hunk from '../../lib/models/hunk'; +import HunkLine from '../../lib/models/hunk-line'; +import ResolutionProgress from '../../lib/models/conflicts/resolution-progress'; +import Switchboard from '../../lib/switchboard'; + +function createFilePatch(oldFilePath, newFilePath, status, hunks) { + const oldFile = new FilePatch.File({path: oldFilePath}); + const newFile = new FilePatch.File({path: newFilePath}); + const patch = new FilePatch.Patch({status, hunks}); + + return new FilePatch(oldFile, newFile, patch); +} + +let atomEnv, commandRegistry, tooltips, deserializers; +let switchboard, getFilePatchForPath; +let discardLines, didSurfaceFile, didDiveIntoFilePath, quietlySelectItem, undoLastDiscard, openFiles, getRepositoryForWorkdir; +let getSelectedStagingViewItems, resolutionProgress; + +function createComponent(repository, filePath) { + atomEnv = global.buildAtomEnvironment(); + commandRegistry = atomEnv.commands; + deserializers = atomEnv.deserializers; + tooltips = atomEnv.tooltips; + + switchboard = new Switchboard(); + + discardLines = sinon.spy(); + didSurfaceFile = sinon.spy(); + didDiveIntoFilePath = sinon.spy(); + quietlySelectItem = sinon.spy(); + undoLastDiscard = sinon.spy(); + openFiles = sinon.spy(); + getSelectedStagingViewItems = sinon.spy(); + + getRepositoryForWorkdir = () => repository; + resolutionProgress = new ResolutionProgress(); + + FilePatchController.resetConfirmedLargeFilePatches(); + + return ( + + ); +} + +async function refreshRepository(wrapper) { + const workDir = wrapper.prop('workingDirectoryPath'); + const repository = wrapper.prop('getRepositoryForWorkdir')(workDir); + + const promise = wrapper.prop('switchboard').getFinishRepositoryRefreshPromise(); + repository.refresh(); + await promise; + wrapper.update(); +} + +describe('FilePatchController', function() { + afterEach(function() { + atomEnv.destroy(); + }); + + describe('unit tests', function() { + let workdirPath, repository, filePath, component; + beforeEach(async function() { + workdirPath = await cloneRepository('multi-line-file'); + repository = await buildRepository(workdirPath); + filePath = 'sample.js'; + component = createComponent(repository, filePath); + + getFilePatchForPath = sinon.stub(repository, 'getFilePatchForPath'); + }); + + describe('when the FilePatch is too large', function() { + it('renders a confirmation widget', async function() { + const hunk1 = new Hunk(0, 0, 1, 1, '', [ + new HunkLine('line-1', 'added', 1, 1), + new HunkLine('line-2', 'added', 2, 2), + new HunkLine('line-3', 'added', 3, 3), + new HunkLine('line-4', 'added', 4, 4), + new HunkLine('line-5', 'added', 5, 5), + new HunkLine('line-6', 'added', 6, 6), + ]); + const filePatch = createFilePatch(filePath, filePath, 'modified', [hunk1]); + + getFilePatchForPath.returns(filePatch); + + const wrapper = mount(React.cloneElement(component, {largeDiffByteThreshold: 5})); + + await assert.async.match(wrapper.text(), /large .+ diff/); + }); + + it('renders the full diff when the confirmation is clicked', async function() { + const hunk = new Hunk(0, 0, 1, 1, '', [ + new HunkLine('line-1', 'added', 1, 1), + new HunkLine('line-2', 'added', 2, 2), + new HunkLine('line-3', 'added', 3, 3), + new HunkLine('line-4', 'added', 4, 4), + new HunkLine('line-5', 'added', 5, 5), + new HunkLine('line-6', 'added', 6, 6), + ]); + const filePatch = createFilePatch(filePath, filePath, 'modified', [hunk]); + getFilePatchForPath.returns(filePatch); + + const wrapper = mount(React.cloneElement(component, {largeDiffByteThreshold: 5})); + + await assert.async.isTrue(wrapper.update().find('.large-file-patch').exists()); + wrapper.find('.large-file-patch').find('button').simulate('click'); + + assert.isTrue(wrapper.find('HunkView').exists()); + }); + + it('renders the full diff if the file has been confirmed before', async function() { + const hunk = new Hunk(0, 0, 1, 1, '', [ + new HunkLine('line-1', 'added', 1, 1), + new HunkLine('line-2', 'added', 2, 2), + new HunkLine('line-3', 'added', 3, 3), + new HunkLine('line-4', 'added', 4, 4), + new HunkLine('line-5', 'added', 5, 5), + new HunkLine('line-6', 'added', 6, 6), + ]); + const filePatch1 = createFilePatch(filePath, filePath, 'modified', [hunk]); + const filePatch2 = createFilePatch('b.txt', 'b.txt', 'modified', [hunk]); + + getFilePatchForPath.returns(filePatch1); + + const wrapper = mount(React.cloneElement(component, { + filePath: filePatch1.getPath(), largeDiffByteThreshold: 5, + })); + + await assert.async.isTrue(wrapper.update().find('.large-file-patch').exists()); + wrapper.find('.large-file-patch').find('button').simulate('click'); + assert.isTrue(wrapper.find('HunkView').exists()); + + getFilePatchForPath.returns(filePatch2); + wrapper.setProps({filePath: filePatch2.getPath()}); + await assert.async.isTrue(wrapper.update().find('.large-file-patch').exists()); + + getFilePatchForPath.returns(filePatch1); + wrapper.setProps({filePath: filePatch1.getPath()}); + assert.isTrue(wrapper.update().find('HunkView').exists()); + }); + }); + + describe('onRepoRefresh', function() { + it('sets the correct FilePatch as state', async function() { + repository.getFilePatchForPath.restore(); + fs.writeFileSync(path.join(workdirPath, filePath), 'change', 'utf8'); + + const wrapper = mount(component); + + await assert.async.isNotNull(wrapper.state('filePatch')); + + const originalFilePatch = wrapper.state('filePatch'); + assert.equal(wrapper.state('stagingStatus'), 'unstaged'); + + fs.writeFileSync(path.join(workdirPath, 'file.txt'), 'change\nand again!', 'utf8'); + await refreshRepository(wrapper); + + assert.notEqual(originalFilePatch, wrapper.state('filePatch')); + assert.equal(wrapper.state('stagingStatus'), 'unstaged'); + }); + }); + + it('renders FilePatchView only if FilePatch has hunks', async function() { + const emptyFilePatch = createFilePatch(filePath, filePath, 'modified', []); + getFilePatchForPath.returns(emptyFilePatch); + + const wrapper = mount(component); + + assert.isTrue(wrapper.find('FilePatchView').exists()); + assert.isTrue(wrapper.find('FilePatchView').text().includes('File has no contents')); + + const hunk1 = new Hunk(0, 0, 1, 1, '', [new HunkLine('line-1', 'added', 1, 1)]); + const filePatch = createFilePatch(filePath, filePath, 'modified', [hunk1]); + getFilePatchForPath.returns(filePatch); + + wrapper.instance().onRepoRefresh(repository); + + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + assert.isTrue(wrapper.find('HunkView').text().includes('@@ -0,1 +0,1 @@')); + }); + + it('updates the FilePatch after a repo update', async function() { + const hunk1 = new Hunk(5, 5, 2, 1, '', [new HunkLine('line-1', 'added', -1, 5)]); + const hunk2 = new Hunk(8, 8, 1, 1, '', [new HunkLine('line-5', 'deleted', 8, -1)]); + const filePatch0 = createFilePatch(filePath, filePath, 'modified', [hunk1, hunk2]); + getFilePatchForPath.returns(filePatch0); + + const wrapper = shallow(component); + + let view0; + await until(() => { + view0 = wrapper.update().find('FilePatchView').shallow(); + return view0.find({hunk: hunk1}).exists(); + }); + assert.isTrue(view0.find({hunk: hunk2}).exists()); + + const hunk3 = new Hunk(8, 8, 1, 1, '', [new HunkLine('line-10', 'modified', 10, 10)]); + const filePatch1 = createFilePatch(filePath, filePath, 'modified', [hunk1, hunk3]); + getFilePatchForPath.returns(filePatch1); + + wrapper.instance().onRepoRefresh(repository); + let view1; + await until(() => { + view1 = wrapper.update().find('FilePatchView').shallow(); + return view1.find({hunk: hunk3}).exists(); + }); + assert.isTrue(view1.find({hunk: hunk1}).exists()); + assert.isFalse(view1.find({hunk: hunk2}).exists()); + }); + + it('invokes a didSurfaceFile callback with the current file path', async function() { + const filePatch = createFilePatch(filePath, filePath, 'modified', [new Hunk(1, 1, 1, 3, '', [])]); + getFilePatchForPath.returns(filePatch); + + const wrapper = mount(component); + + await assert.async.isTrue(wrapper.update().find('Commands').exists()); + commandRegistry.dispatch(wrapper.find('FilePatchView').getDOMNode(), 'core:move-right'); + assert.isTrue(didSurfaceFile.calledWith(filePath, 'unstaged')); + }); + + describe('openCurrentFile({lineNumber})', () => { + it('sets the cursor on the correct line of the opened text editor', async function() { + const editorSpy = { + relativePath: null, + scrollToBufferPosition: sinon.spy(), + setCursorBufferPosition: sinon.spy(), + }; + + const openFilesStub = relativePaths => { + assert.lengthOf(relativePaths, 1); + editorSpy.relativePath = relativePaths[0]; + return Promise.resolve([editorSpy]); + }; + + const hunk = new Hunk(5, 5, 2, 1, '', [new HunkLine('line-1', 'added', -1, 5)]); + const filePatch = createFilePatch(filePath, filePath, 'modified', [hunk]); + getFilePatchForPath.returns(filePatch); + + const wrapper = mount(React.cloneElement(component, {openFiles: openFilesStub})); + + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + + wrapper.find('LineView').simulate('mousedown', {button: 0, detail: 1}); + window.dispatchEvent(new MouseEvent('mouseup')); + commandRegistry.dispatch(wrapper.find('FilePatchView').getDOMNode(), 'github:open-file'); + wrapper.update(); + + await assert.async.isTrue(editorSpy.setCursorBufferPosition.called); + + assert.isTrue(editorSpy.relativePath === filePath); + + const scrollCall = editorSpy.scrollToBufferPosition.firstCall; + assert.isTrue(scrollCall.args[0].isEqual([4, 0])); + assert.deepEqual(scrollCall.args[1], {center: true}); + + const cursorCall = editorSpy.setCursorBufferPosition.firstCall; + assert.isTrue(cursorCall.args[0].isEqual([4, 0])); + }); + }); + }); + + describe('integration tests', function() { + describe('handling symlink files', function() { + async function indexModeAndOid(repository, filename) { + const output = await repository.git.exec(['ls-files', '-s', '--', filename]); + if (output) { + const parts = output.split(' '); + return {mode: parts[0], oid: parts[1]}; + } else { + return null; + } + } + + it('unstages added lines that don\'t require symlink change', async function() { + const workingDirPath = await cloneRepository('symlinks'); + const repository = await buildRepository(workingDirPath); + + // correctly handle symlinks on Windows + await repository.git.exec(['config', 'core.symlinks', 'true']); + + const deletedSymlinkAddedFilePath = 'symlink.txt'; + fs.unlinkSync(path.join(workingDirPath, deletedSymlinkAddedFilePath)); + fs.writeFileSync(path.join(workingDirPath, deletedSymlinkAddedFilePath), 'qux\nfoo\nbar\nbaz\nzoo\n', 'utf8'); + + // Stage whole file + await repository.stageFiles([deletedSymlinkAddedFilePath]); + + const component = createComponent(repository, deletedSymlinkAddedFilePath); + const wrapper = mount(React.cloneElement(component, {filePath: deletedSymlinkAddedFilePath, initialStagingStatus: 'staged'})); + + // index shows symlink deltion and added lines + assert.autocrlfEqual(await repository.readFileFromIndex(deletedSymlinkAddedFilePath), 'qux\nfoo\nbar\nbaz\nzoo\n'); + assert.equal((await indexModeAndOid(repository, deletedSymlinkAddedFilePath)).mode, '100644'); + + // Unstage a couple added lines, but not all + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + const opPromise0 = switchboard.getFinishStageOperationPromise(); + const hunkView0 = wrapper.find('HunkView').at(0); + hunkView0.find('LineView').at(1).find('.github-HunkView-line').simulate('mousedown', {button: 0, detail: 1}); + hunkView0.find('LineView').at(2).find('.github-HunkView-line').simulate('mousemove', {}); + window.dispatchEvent(new MouseEvent('mouseup')); + hunkView0.find('button.github-HunkView-stageButton').simulate('click'); + await opPromise0; + + await refreshRepository(wrapper); + + // index shows symlink deletions still staged, only a couple of lines have been unstaged + assert.equal((await indexModeAndOid(repository, deletedSymlinkAddedFilePath)).mode, '100644'); + assert.autocrlfEqual(await repository.readFileFromIndex(deletedSymlinkAddedFilePath), 'qux\nbaz\nzoo\n'); + }); + + it('stages deleted lines that don\'t require symlink change', async function() { + const workingDirPath = await cloneRepository('symlinks'); + const repository = await buildRepository(workingDirPath); + + const deletedFileAddedSymlinkPath = 'a.txt'; + fs.unlinkSync(path.join(workingDirPath, deletedFileAddedSymlinkPath)); + fs.symlinkSync(path.join(workingDirPath, 'regular-file.txt'), path.join(workingDirPath, deletedFileAddedSymlinkPath)); + + const component = createComponent(repository, deletedFileAddedSymlinkPath); + const wrapper = mount(React.cloneElement(component, {filePath: deletedFileAddedSymlinkPath, initialStagingStatus: 'unstaged'})); + + // index shows file is not a symlink, no deleted lines + assert.equal((await indexModeAndOid(repository, deletedFileAddedSymlinkPath)).mode, '100644'); + assert.autocrlfEqual(await repository.readFileFromIndex(deletedFileAddedSymlinkPath), 'foo\nbar\nbaz\n\n'); + + // stage a couple of lines, but not all + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + const opPromise0 = switchboard.getFinishStageOperationPromise(); + const hunkView0 = wrapper.find('HunkView').at(0); + hunkView0.find('LineView').at(1).find('.github-HunkView-line').simulate('mousedown', {button: 0, detail: 1}); + hunkView0.find('LineView').at(2).find('.github-HunkView-line').simulate('mousemove', {}); + window.dispatchEvent(new MouseEvent('mouseup')); + hunkView0.find('button.github-HunkView-stageButton').simulate('click'); + await opPromise0; + + await refreshRepository(wrapper); + + // index shows symlink change has not been staged, a couple of lines have been deleted + assert.equal((await indexModeAndOid(repository, deletedFileAddedSymlinkPath)).mode, '100644'); + assert.autocrlfEqual(await repository.readFileFromIndex(deletedFileAddedSymlinkPath), 'foo\n\n'); + }); + + it('stages symlink change when staging added lines that depend on change', async function() { + const workingDirPath = await cloneRepository('symlinks'); + const repository = await buildRepository(workingDirPath); + + // correctly handle symlinks on Windows + await repository.git.exec(['config', 'core.symlinks', 'true']); + + const deletedSymlinkAddedFilePath = 'symlink.txt'; + fs.unlinkSync(path.join(workingDirPath, deletedSymlinkAddedFilePath)); + fs.writeFileSync(path.join(workingDirPath, deletedSymlinkAddedFilePath), 'qux\nfoo\nbar\nbaz\nzoo\n', 'utf8'); + + const component = createComponent(repository, deletedSymlinkAddedFilePath); + const wrapper = mount(React.cloneElement(component, {filePath: deletedSymlinkAddedFilePath})); + + // index shows file is symlink + assert.equal((await indexModeAndOid(repository, deletedSymlinkAddedFilePath)).mode, '120000'); + + // Stage a couple added lines, but not all + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + const opPromise0 = switchboard.getFinishStageOperationPromise(); + const hunkView0 = wrapper.find('HunkView').at(0); + hunkView0.find('LineView').at(1).find('.github-HunkView-line').simulate('mousedown', {button: 0, detail: 1}); + hunkView0.find('LineView').at(2).find('.github-HunkView-line').simulate('mousemove', {}); + window.dispatchEvent(new MouseEvent('mouseup')); + hunkView0.find('button.github-HunkView-stageButton').simulate('click'); + await opPromise0; + + await refreshRepository(wrapper); + + // index no longer shows file is symlink (symlink has been deleted), now a regular file with contents + assert.equal((await indexModeAndOid(repository, deletedSymlinkAddedFilePath)).mode, '100644'); + assert.autocrlfEqual(await repository.readFileFromIndex(deletedSymlinkAddedFilePath), 'foo\nbar\n'); + }); + + it('unstages symlink change when unstaging deleted lines that depend on change', async function() { + const workingDirPath = await cloneRepository('symlinks'); + const repository = await buildRepository(workingDirPath); + + const deletedFileAddedSymlinkPath = 'a.txt'; + fs.unlinkSync(path.join(workingDirPath, deletedFileAddedSymlinkPath)); + fs.symlinkSync(path.join(workingDirPath, 'regular-file.txt'), path.join(workingDirPath, deletedFileAddedSymlinkPath)); + await repository.stageFiles([deletedFileAddedSymlinkPath]); + + const component = createComponent(repository, deletedFileAddedSymlinkPath); + const wrapper = mount(React.cloneElement(component, {filePath: deletedFileAddedSymlinkPath, initialStagingStatus: 'staged'})); + + // index shows file is symlink + assert.equal((await indexModeAndOid(repository, deletedFileAddedSymlinkPath)).mode, '120000'); + + // unstage a couple of lines, but not all + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + const opPromise0 = switchboard.getFinishStageOperationPromise(); + const hunkView0 = wrapper.find('HunkView').at(0); + hunkView0.find('LineView').at(1).find('.github-HunkView-line').simulate('mousedown', {button: 0, detail: 1}); + hunkView0.find('LineView').at(2).find('.github-HunkView-line').simulate('mousemove', {}); + window.dispatchEvent(new MouseEvent('mouseup')); + hunkView0.find('button.github-HunkView-stageButton').simulate('click'); + await opPromise0; + + await refreshRepository(wrapper); + + // index no longer shows file is symlink (symlink creation has been unstaged), shows contents of file that existed prior to symlink + assert.equal((await indexModeAndOid(repository, deletedFileAddedSymlinkPath)).mode, '100644'); + assert.autocrlfEqual(await repository.readFileFromIndex(deletedFileAddedSymlinkPath), 'bar\nbaz\n'); + }); + + it('stages file deletion when all deleted lines are staged', async function() { + const workingDirPath = await cloneRepository('symlinks'); + const repository = await buildRepository(workingDirPath); + await repository.getLoadPromise(); + + const deletedFileAddedSymlinkPath = 'a.txt'; + fs.unlinkSync(path.join(workingDirPath, deletedFileAddedSymlinkPath)); + fs.symlinkSync(path.join(workingDirPath, 'regular-file.txt'), path.join(workingDirPath, deletedFileAddedSymlinkPath)); + + const component = createComponent(repository, deletedFileAddedSymlinkPath); + const wrapper = mount(React.cloneElement(component, {filePath: deletedFileAddedSymlinkPath})); + + assert.equal((await indexModeAndOid(repository, deletedFileAddedSymlinkPath)).mode, '100644'); + + // stage all deleted lines + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + const opPromise0 = switchboard.getFinishStageOperationPromise(); + const hunkView0 = wrapper.find('HunkView').at(0); + hunkView0.find('.github-HunkView-title').simulate('click'); + hunkView0.find('button.github-HunkView-stageButton').simulate('click'); + await opPromise0; + + await refreshRepository(wrapper); + + // File is not on index, file deletion has been staged + assert.isNull(await indexModeAndOid(repository, deletedFileAddedSymlinkPath)); + const {stagedFiles, unstagedFiles} = await repository.getStatusesForChangedFiles(); + assert.equal(unstagedFiles[deletedFileAddedSymlinkPath], 'added'); + assert.equal(stagedFiles[deletedFileAddedSymlinkPath], 'deleted'); + }); + + it('unstages file creation when all added lines are unstaged', async function() { + const workingDirPath = await cloneRepository('symlinks'); + const repository = await buildRepository(workingDirPath); + + await repository.git.exec(['config', 'core.symlinks', 'true']); + + const deletedSymlinkAddedFilePath = 'symlink.txt'; + fs.unlinkSync(path.join(workingDirPath, deletedSymlinkAddedFilePath)); + fs.writeFileSync(path.join(workingDirPath, deletedSymlinkAddedFilePath), 'qux\nfoo\nbar\nbaz\nzoo\n', 'utf8'); + await repository.stageFiles([deletedSymlinkAddedFilePath]); + + const component = createComponent(repository, deletedSymlinkAddedFilePath); + const wrapper = mount(React.cloneElement(component, {filePath: deletedSymlinkAddedFilePath, initialStagingStatus: 'staged'})); + + assert.equal((await indexModeAndOid(repository, deletedSymlinkAddedFilePath)).mode, '100644'); + + // unstage all added lines + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + const opPromise0 = switchboard.getFinishStageOperationPromise(); + const hunkView0 = wrapper.find('HunkView').at(0); + hunkView0.find('.github-HunkView-title').simulate('click'); + hunkView0.find('button.github-HunkView-stageButton').simulate('click'); + await opPromise0; + + await refreshRepository(wrapper); + + // File is not on index, file creation has been unstaged + assert.isNull(await indexModeAndOid(repository, deletedSymlinkAddedFilePath)); + const {stagedFiles, unstagedFiles} = await repository.getStatusesForChangedFiles(); + assert.equal(unstagedFiles[deletedSymlinkAddedFilePath], 'added'); + assert.equal(stagedFiles[deletedSymlinkAddedFilePath], 'deleted'); + }); + }); + + describe('handling non-symlink changes', function() { + let workdirPath, repository, filePath, component; + beforeEach(async function() { + workdirPath = await cloneRepository('multi-line-file'); + repository = await buildRepository(workdirPath); + filePath = 'sample.js'; + component = createComponent(repository, filePath); + }); + + it('stages and unstages hunks when the stage button is clicked on hunk views with no individual lines selected', async function() { + const absFilePath = path.join(workdirPath, filePath); + const originalLines = fs.readFileSync(absFilePath, 'utf8').split('\n'); + const unstagedLines = originalLines.slice(); + unstagedLines.splice(1, 1, + 'this is a modified line', + 'this is a new line', + 'this is another new line', + ); + unstagedLines.splice(11, 2, 'this is a modified line'); + fs.writeFileSync(absFilePath, unstagedLines.join('\n')); + + const wrapper = mount(component); + + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + commandRegistry.dispatch(wrapper.find('FilePatchView').getDOMNode(), 'core:move-down'); + + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + const hunkView0 = wrapper.find('HunkView').at(0); + assert.isFalse(hunkView0.prop('isSelected')); + const opPromise0 = switchboard.getFinishStageOperationPromise(); + hunkView0.find('button.github-HunkView-stageButton').simulate('click'); + await opPromise0; + + const expectedStagedLines = originalLines.slice(); + expectedStagedLines.splice(1, 1, + 'this is a modified line', + 'this is a new line', + 'this is another new line', + ); + assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), expectedStagedLines.join('\n')); + const updatePromise0 = switchboard.getChangePatchPromise(); + const stagedFilePatch = await repository.getFilePatchForPath('sample.js', {staged: true}); + wrapper.setState({ + stagingStatus: 'staged', + filePatch: stagedFilePatch, + }); + await updatePromise0; + const hunkView1 = wrapper.find('HunkView').at(0); + const opPromise1 = switchboard.getFinishStageOperationPromise(); + hunkView1.find('button.github-HunkView-stageButton').simulate('click'); + await opPromise1; + assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), originalLines.join('\n')); + }); + + it('stages and unstages individual lines when the stage button is clicked on a hunk with selected lines', async function() { + const absFilePath = path.join(workdirPath, filePath); + const originalLines = fs.readFileSync(absFilePath, 'utf8').split('\n'); + + // write some unstaged changes + const unstagedLines = originalLines.slice(); + unstagedLines.splice(1, 1, + 'this is a modified line', + 'this is a new line', + 'this is another new line', + ); + unstagedLines.splice(11, 2, 'this is a modified line'); + fs.writeFileSync(absFilePath, unstagedLines.join('\n')); + + // stage a subset of lines from first hunk + const wrapper = mount(component); + + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + const opPromise0 = switchboard.getFinishStageOperationPromise(); + const hunkView0 = wrapper.find('HunkView').at(0); + hunkView0.find('LineView').at(1).find('.github-HunkView-line').simulate('mousedown', {button: 0, detail: 1}); + hunkView0.find('LineView').at(3).find('.github-HunkView-line').simulate('mousemove', {}); + window.dispatchEvent(new MouseEvent('mouseup')); + hunkView0.find('button.github-HunkView-stageButton').simulate('click'); + await opPromise0; + + await refreshRepository(wrapper); + + const expectedLines0 = originalLines.slice(); + expectedLines0.splice(1, 1, + 'this is a modified line', + 'this is a new line', + ); + assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), expectedLines0.join('\n')); + + // stage remaining lines in hunk + const opPromise1 = switchboard.getFinishStageOperationPromise(); + wrapper.find('HunkView').at(0).find('button.github-HunkView-stageButton').simulate('click'); + await opPromise1; + + await refreshRepository(wrapper); + + const expectedLines1 = originalLines.slice(); + expectedLines1.splice(1, 1, + 'this is a modified line', + 'this is a new line', + 'this is another new line', + ); + assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), expectedLines1.join('\n')); + + // unstage a subset of lines from the first hunk + wrapper.setState({stagingStatus: 'staged'}); + await refreshRepository(wrapper); + + const hunkView2 = wrapper.find('HunkView').at(0); + hunkView2.find('LineView').at(1).find('.github-HunkView-line') + .simulate('mousedown', {button: 0, detail: 1}); + window.dispatchEvent(new MouseEvent('mouseup')); + hunkView2.find('LineView').at(2).find('.github-HunkView-line') + .simulate('mousedown', {button: 0, detail: 1, metaKey: true}); + window.dispatchEvent(new MouseEvent('mouseup')); + + const opPromise2 = switchboard.getFinishStageOperationPromise(); + hunkView2.find('button.github-HunkView-stageButton').simulate('click'); + await opPromise2; + + await refreshRepository(wrapper); + + const expectedLines2 = originalLines.slice(); + expectedLines2.splice(2, 0, + 'this is a new line', + 'this is another new line', + ); + assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), expectedLines2.join('\n')); + + // unstage the rest of the hunk + commandRegistry.dispatch(wrapper.find('FilePatchView').getDOMNode(), 'github:toggle-patch-selection-mode'); + + const opPromise3 = switchboard.getFinishStageOperationPromise(); + wrapper.find('HunkView').at(0).find('button.github-HunkView-stageButton').simulate('click'); + await opPromise3; + + assert.autocrlfEqual(await repository.readFileFromIndex('sample.js'), originalLines.join('\n')); + }); + + // https://github.com/atom/github/issues/417 + describe('when unstaging the last lines/hunks from a file', function() { + it('removes added files from index when last hunk is unstaged', async function() { + const absFilePath = path.join(workdirPath, 'new-file.txt'); + + fs.writeFileSync(absFilePath, 'foo\n'); + await repository.stageFiles(['new-file.txt']); + + const wrapper = mount(React.cloneElement(component, { + filePath: 'new-file.txt', + initialStagingStatus: 'staged', + })); + + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + + const opPromise = switchboard.getFinishStageOperationPromise(); + wrapper.find('HunkView').at(0).find('button.github-HunkView-stageButton').simulate('click'); + await opPromise; + + const stagedChanges = await repository.getStagedChanges(); + assert.equal(stagedChanges.length, 0); + }); + + it('removes added files from index when last lines are unstaged', async function() { + const absFilePath = path.join(workdirPath, 'new-file.txt'); + + fs.writeFileSync(absFilePath, 'foo\n'); + await repository.stageFiles(['new-file.txt']); + + const wrapper = mount(React.cloneElement(component, { + filePath: 'new-file.txt', + initialStagingStatus: 'staged', + })); + + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + + const viewNode = wrapper.find('FilePatchView').getDOMNode(); + commandRegistry.dispatch(viewNode, 'github:toggle-patch-selection-mode'); + commandRegistry.dispatch(viewNode, 'core:select-all'); + + const opPromise = switchboard.getFinishStageOperationPromise(); + wrapper.find('HunkView').at(0).find('button.github-HunkView-stageButton').simulate('click'); + await opPromise; + + const stagedChanges = await repository.getStagedChanges(); + assert.lengthOf(stagedChanges, 0); + }); + }); + + // https://github.com/atom/github/issues/341 + describe('when duplicate staging occurs', function() { + it('avoids patch conflicts with pending line staging operations', async function() { + const absFilePath = path.join(workdirPath, filePath); + const originalLines = fs.readFileSync(absFilePath, 'utf8').split('\n'); + + // write some unstaged changes + const unstagedLines = originalLines.slice(); + unstagedLines.splice(1, 0, + 'this is a modified line', + 'this is a new line', + 'this is another new line', + ); + unstagedLines.splice(11, 2, 'this is a modified line'); + fs.writeFileSync(absFilePath, unstagedLines.join('\n')); + + const wrapper = mount(component); + + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + const hunkView0 = wrapper.find('HunkView').at(0); + hunkView0.find('LineView').at(1).find('.github-HunkView-line') + .simulate('mousedown', {button: 0, detail: 1}); + window.dispatchEvent(new MouseEvent('mouseup')); + + // stage lines in rapid succession + // second stage action is a no-op since the first staging operation is in flight + const line1StagingPromise = switchboard.getFinishStageOperationPromise(); + hunkView0.find('.github-HunkView-stageButton').simulate('click'); + hunkView0.find('.github-HunkView-stageButton').simulate('click'); + await line1StagingPromise; + + const changePatchPromise = switchboard.getChangePatchPromise(); + + // assert that only line 1 has been staged + await refreshRepository(wrapper); // clear the cached file patches + let expectedLines = originalLines.slice(); + expectedLines.splice(1, 0, + 'this is a modified line', + ); + let actualLines = await repository.readFileFromIndex(filePath); + assert.autocrlfEqual(actualLines, expectedLines.join('\n')); + await changePatchPromise; + wrapper.update(); + + const hunkView1 = wrapper.find('HunkView').at(0); + hunkView1.find('LineView').at(2).find('.github-HunkView-line') + .simulate('mousedown', {button: 0, detail: 1}); + window.dispatchEvent(new MouseEvent('mouseup')); + const line2StagingPromise = switchboard.getFinishStageOperationPromise(); + hunkView1.find('.github-HunkView-stageButton').simulate('click'); + await line2StagingPromise; + + // assert that line 2 has now been staged + expectedLines = originalLines.slice(); + expectedLines.splice(1, 0, + 'this is a modified line', + 'this is a new line', + ); + actualLines = await repository.readFileFromIndex(filePath); + assert.autocrlfEqual(actualLines, expectedLines.join('\n')); + }); + + it('avoids patch conflicts with pending hunk staging operations', async function() { + const absFilePath = path.join(workdirPath, filePath); + const originalLines = fs.readFileSync(absFilePath, 'utf8').split('\n'); + + // write some unstaged changes + const unstagedLines = originalLines.slice(); + unstagedLines.splice(1, 0, + 'this is a modified line', + 'this is a new line', + 'this is another new line', + ); + unstagedLines.splice(11, 2, 'this is a modified line'); + fs.writeFileSync(absFilePath, unstagedLines.join('\n')); + + const wrapper = mount(component); + + await assert.async.isTrue(wrapper.update().find('HunkView').exists()); + + // ensure staging the same hunk twice does not cause issues + // second stage action is a no-op since the first staging operation is in flight + const hunk1StagingPromise = switchboard.getFinishStageOperationPromise(); + wrapper.find('HunkView').at(0).find('.github-HunkView-stageButton').simulate('click'); + wrapper.find('HunkView').at(0).find('.github-HunkView-stageButton').simulate('click'); + await hunk1StagingPromise; + + const patchPromise0 = switchboard.getChangePatchPromise(); + await refreshRepository(wrapper); // clear the cached file patches + const modifiedFilePatch = await repository.getFilePatchForPath(filePath); + wrapper.setState({filePatch: modifiedFilePatch}); + await patchPromise0; + + let expectedLines = originalLines.slice(); + expectedLines.splice(1, 0, + 'this is a modified line', + 'this is a new line', + 'this is another new line', + ); + let actualLines = await repository.readFileFromIndex(filePath); + assert.autocrlfEqual(actualLines, expectedLines.join('\n')); + + const hunk2StagingPromise = switchboard.getFinishStageOperationPromise(); + wrapper.find('HunkView').at(0).find('.github-HunkView-stageButton').simulate('click'); + await hunk2StagingPromise; + + expectedLines = originalLines.slice(); + expectedLines.splice(1, 0, + 'this is a modified line', + 'this is a new line', + 'this is another new line', + ); + expectedLines.splice(11, 2, 'this is a modified line'); + actualLines = await repository.readFileFromIndex(filePath); + assert.autocrlfEqual(actualLines, expectedLines.join('\n')); + }); + }); + }); + }); +}); From 52e36e127a96ae556c91beec1513f56c96c09d3a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Jun 2018 16:16:50 -0400 Subject: [PATCH 0134/4847] :fire: unused spies --- test/containers/file-patch-container.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/containers/file-patch-container.test.js b/test/containers/file-patch-container.test.js index 2f01eb3772..02fdd93eed 100644 --- a/test/containers/file-patch-container.test.js +++ b/test/containers/file-patch-container.test.js @@ -14,8 +14,6 @@ describe('FilePatchContainer', function() { const workdirPath = await cloneRepository(); repository = await buildRepository(workdirPath); - sinon.spy(repository, 'getFilePatchForPath'); - sinon.spy(repository, 'isPartiallyStaged'); // a.txt: unstaged changes await fs.writeFile(path.join(workdirPath, 'a.txt'), 'changed\n'); From f872f576c9b7bde450110643ed78744e5b725ad4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Jun 2018 16:17:47 -0400 Subject: [PATCH 0135/4847] Out of the way, old FilePatchView tests --- .../{file-patch-view.test.js => file-patch-view.test.old.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/views/{file-patch-view.test.js => file-patch-view.test.old.js} (100%) diff --git a/test/views/file-patch-view.test.js b/test/views/file-patch-view.test.old.js similarity index 100% rename from test/views/file-patch-view.test.js rename to test/views/file-patch-view.test.old.js From 8ab776124213040943cfbefa8d82f68f61b2d88f Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 7 Jun 2018 20:39:09 +0900 Subject: [PATCH 0136/4847] Remove comments And keep the timeline center pane. --- docs/rfcs/004-issueish-list.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index fe19cf55e9..1bd096fbd8 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -30,7 +30,7 @@ Each list has a "collapse arrow" in its header. Clicking the collapse arrow togg If either list exceeds 20 items, truncate the list and render a "More" link after its final item. Clicking "more" opens the corresponding search on GitHub. -![Lists](https://user-images.githubusercontent.com/378023/40964722-ceb9d95a-68e6-11e8-90b3-1c155cdc2c00.png) +![list](https://user-images.githubusercontent.com/378023/41097007-7a32992e-6a91-11e8-9c4b-2417cf94dce9.png) Each list item renders a tile containing a compact set of information about that pull request: @@ -48,26 +48,25 @@ Clicking on a list item opens an issueish pane item for the chosen issueish in t For a pull request, the issueish pane shows: +* PR status badge. -> `Open`. +* Link to .com. -> [atom/github#1503](https://github.com/atom/github/pull/1503) * Author avatar * Title -* Link to .com. -> [atom/github#1503](https://github.com/atom/github/pull/1503) -* PR status badge. -> `Open`. * Branches -> `master` < `aw/rfc-pr-list` -* `Commits` with count, links to .com (for now) +* "Checkout" button to fetch (if necessary) and check out the pull request. Only enabled if the current pull request is not the current one. +* `Commits` with count, links to .com (for now), optional with avatars * `Checks` with count, links to .com (for now) -* `Files changed` with count, links to .com (for now) - * Plus a "Checkout" button to fetch (if necessary) and check out the pull request. Only enabled if the current pull request is not the current one. -* `Conversation` with comment count. - * Reaction emoji and counts. - * Full description as rendered markdown. - * Comments as rendered markdown. +* `Files changed` with count, links to .com (for now), optional with "+-" bar * Controls for actions: * Mergability status -> `Able to merge`, links to the [Merging controls at the bottom](https://github.com/atom/github/pull/1503#partial-pull-merging) * "Merge PR" to merge the pull request on GitHub if it is open. * "Close" to close the pull request, unmerged, if it is open. * "Re-open PR" to re-open a pull request if it is closed. +* `Conversation` with comment count, opens the current PR timeline in a center pane. + * Reaction emoji and counts. + * Description (PR body) as rendered markdown. -![pane](https://user-images.githubusercontent.com/378023/41033008-0900b4ec-69c0-11e8-9def-68e6f5b40901.png) +![detail](https://user-images.githubusercontent.com/378023/41097077-ba228d00-6a91-11e8-9445-a9557c03e6b6.png) ## Drawbacks From 9f7323c0607973f6af9888cb3120119d11ce55ed Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 7 Jun 2018 22:05:24 +0900 Subject: [PATCH 0137/4847] Add new PR option --- docs/rfcs/004-issueish-list.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index 1bd096fbd8..ea8f7e92ac 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -68,9 +68,17 @@ For a pull request, the issueish pane shows: ![detail](https://user-images.githubusercontent.com/378023/41097077-ba228d00-6a91-11e8-9445-a9557c03e6b6.png) +## New PR + +If no current PR can be found, an "open new pull request" button is shown. If needed it also offers to "Publish" or "Push". + +![new pr](https://user-images.githubusercontent.com/378023/41100932-9a3cd7be-6a9d-11e8-85c4-c995b71548c7.png) + +When the current branch is the default branch, e.g. `master`, a message is shown that suggests to "Create a new branch". + ## Drawbacks -This does not offer a mechanism to create _new_ pull requests, which we have now. We also lose timeline events on the pull request. +None! ## Rationale and alternatives @@ -90,7 +98,6 @@ With that said, the choices for the specific lists we show are a bit arbitrary. ### Before RFC merge: -- [ ] How can we still offer "push/publish+new pull request"? - [ ] What else from the existing issueish pane should we keep? Comments, timeline events? - [ ] Are there other pull request actions it would be useful to support? From d64d8b30c5931c0989d33b4c186a9ef7c7ba79fe Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 7 Jun 2018 09:28:33 -0400 Subject: [PATCH 0138/4847] (Failing) tests for FilePatchView --- test/views/file-patch-view.test.js | 60 ++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 test/views/file-patch-view.test.js diff --git a/test/views/file-patch-view.test.js b/test/views/file-patch-view.test.js new file mode 100644 index 0000000000..c5225a1564 --- /dev/null +++ b/test/views/file-patch-view.test.js @@ -0,0 +1,60 @@ +import path from 'path'; +import fs from 'fs-extra'; +import React from 'react'; +import {mount} from 'enzyme'; + +import {cloneRepository, buildRepository} from '../helpers'; +import FilePatchView from '../../lib/views/file-patch-view'; + +describe('FilePatchView', function() { + let atomEnv, filePatch; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + + const workdirPath = await cloneRepository(); + const repository = await buildRepository(workdirPath); + + // a.txt: unstaged changes + await fs.writeFile(path.join(workdirPath, 'a.txt'), 'changed\n'); + filePatch = await repository.getFilePatchForPath('a.txt', {staged: false}); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + function buildApp(overrideProps = {}) { + const props = { + stagingStatus: 'unstaged', + isPartiallyStaged: false, + filePatch, + tooltips: atomEnv.tooltips, + ...overrideProps, + }; + + return ; + } + + it('renders the file header', function() { + const wrapper = mount(buildApp()); + assert.isTrue(wrapper.find('FilePatchHeader').exists()); + }); + + it('renders the file patch within an editor', function() { + const wrapper = mount(buildApp()); + + const editor = wrapper.find('AtomTextEditor'); + assert.strictEqual(editor.instance().getModel().getText(), filePatch.present().getText()); + }); + + it('renders a header for each hunk'); + + describe('hunk lines', function() { + it('decorates added lines'); + + it('decorates deleted lines'); + + it('decorates the nonewlines line'); + }); +}); From b1e1fd8e97dcd1b573825ef72e1d45bfa054da77 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 7 Jun 2018 10:57:10 -0400 Subject: [PATCH 0139/4847] Write and test a FilePatchHeaderView component --- lib/views/file-patch-header-view.js | 135 +++++++++++++++++++ test/views/file-patch-header-view.test.js | 154 ++++++++++++++++++++++ 2 files changed, 289 insertions(+) create mode 100644 lib/views/file-patch-header-view.js create mode 100644 test/views/file-patch-header-view.test.js diff --git a/lib/views/file-patch-header-view.js b/lib/views/file-patch-header-view.js new file mode 100644 index 0000000000..3514460e6b --- /dev/null +++ b/lib/views/file-patch-header-view.js @@ -0,0 +1,135 @@ +import React, {Fragment} from 'react'; +import PropTypes from 'prop-types'; +import cx from 'classnames'; + +import RefHolder from '../models/ref-holder'; +import Tooltip from '../atom/tooltip'; + +export default class FilePatchHeaderView extends React.Component { + static propTypes = { + relPath: PropTypes.string.isRequired, + stagingStatus: PropTypes.oneOf(['staged', 'unstaged']).isRequired, + isPartiallyStaged: PropTypes.bool.isRequired, + hasHunks: PropTypes.bool.isRequired, + hasUndoHistory: PropTypes.bool.isRequired, + + tooltips: PropTypes.object.isRequired, + + undoLastDiscard: PropTypes.func.isRequired, + diveIntoMirrorPatch: PropTypes.func.isRequired, + openFile: PropTypes.func.isRequired, + toggleFile: PropTypes.func.isRequired, + }; + + constructor(props) { + super(props); + + this.refMirrorButton = new RefHolder(); + this.refOpenFileButton = new RefHolder(); + } + + render() { + return ( +
+ + {this.renderTitle()} + + {this.renderButtonGroup()} +
+ ); + } + + renderTitle() { + const status = this.props.stagingStatus; + return `${status[0].toUpperCase()}${status.slice(1)} Changes for ${this.props.relPath}`; + } + + renderButtonGroup() { + return ( + + {this.renderUndoDiscardButton()} + {this.renderMirrorPatchButton()} + {this.renderOpenFileButton()} + {this.renderToggleFileButton()} + + ); + } + + renderUndoDiscardButton() { + if (!this.props.hasUndoHistory || this.props.stagingStatus !== 'unstaged') { + return null; + } + + return ( + + ); + } + + renderMirrorPatchButton() { + if (!this.props.isPartiallyStaged && this.props.hasHunks) { + return null; + } + + const attrs = this.props.stagingStatus === 'unstaged' + ? { + iconClass: 'icon-tasklist', + tooltipText: 'View staged changes', + } + : { + iconClass: 'icon-list-unordered', + tooltipText: 'View unstaged changes', + }; + + return ( + + + ); + } +} diff --git a/test/views/file-patch-header-view.test.js b/test/views/file-patch-header-view.test.js new file mode 100644 index 0000000000..d56eb3605b --- /dev/null +++ b/test/views/file-patch-header-view.test.js @@ -0,0 +1,154 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import FilePatchHeaderView from '../../lib/views/file-patch-header-view'; + +describe('FilePatchHeaderView', function() { + let atomEnv; + + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + function buildApp(overrideProps = {}) { + return ( + {}} + diveIntoMirrorPatch={() => {}} + openFile={() => {}} + toggleFile={() => {}} + + {...overrideProps} + /> + ); + } + + describe('the title', function() { + it('renders for an unstaged patch', function() { + const wrapper = shallow(buildApp({stagingStatus: 'unstaged'})); + assert.strictEqual(wrapper.find('.github-FilePatchView-title').text(), 'Unstaged Changes for dir/a.txt'); + }); + + it('renders for a staged patch', function() { + const wrapper = shallow(buildApp({stagingStatus: 'staged'})); + assert.strictEqual(wrapper.find('.github-FilePatchView-title').text(), 'Staged Changes for dir/a.txt'); + }); + }); + + describe('the button group', function() { + it('includes undo discard if undo history is available and the patch is unstaged', function() { + const undoLastDiscard = sinon.stub(); + const wrapper = shallow(buildApp({hasUndoHistory: true, stagingStatus: 'unstaged', undoLastDiscard})); + assert.isTrue(wrapper.find('button.icon-history').exists()); + + wrapper.find('button.icon-history').simulate('click'); + assert.isTrue(undoLastDiscard.called); + + wrapper.setProps({hasUndoHistory: false, stagingStatus: 'unstaged'}); + assert.isFalse(wrapper.find('button.icon-history').exists()); + + wrapper.setProps({hasUndoHistory: true, stagingStatus: 'staged'}); + assert.isFalse(wrapper.find('button.icon-history').exists()); + }); + + function createPatchToggleTest({overrideProps, stagingStatus, buttonClass, oppositeButtonClass, tooltip}) { + return function() { + const diveIntoMirrorPatch = sinon.stub(); + const wrapper = shallow(buildApp({stagingStatus, diveIntoMirrorPatch, ...overrideProps})); + + assert.isTrue(wrapper.find(`button.${buttonClass}`).exists(), + `${buttonClass} expected, but not found`); + assert.isFalse(wrapper.find(`button.${oppositeButtonClass}`).exists(), + `${oppositeButtonClass} not expected, but found`); + + wrapper.find(`button.${buttonClass}`).simulate('click'); + assert.isTrue(diveIntoMirrorPatch.called, `${buttonClass} click did nothing`); + + assert.isTrue(wrapper.find('Tooltip').someWhere(n => n.prop('title') === tooltip)); + }; + } + + function createUnstagedPatchToggleTest(overrideProps) { + return createPatchToggleTest({ + overrideProps, + stagingStatus: 'unstaged', + buttonClass: 'icon-tasklist', + oppositeButtonClass: 'icon-list-unordered', + tooltip: 'View staged changes', + }); + } + + function createStagedPatchToggleTest(overrideProps) { + return createPatchToggleTest({ + overrideProps, + stagingStatus: 'staged', + buttonClass: 'icon-list-unordered', + oppositeButtonClass: 'icon-tasklist', + tooltip: 'View unstaged changes', + }); + } + + describe('when the patch is partially staged', function() { + const props = {isPartiallyStaged: true}; + + it('includes a toggle to staged button when unstaged', createUnstagedPatchToggleTest(props)); + + it('includes a toggle to unstaged button when staged', createStagedPatchToggleTest(props)); + }); + + describe('when the patch contains no hunks', function() { + const props = {hasHunks: false}; + + it('includes a toggle to staged button when unstaged', createUnstagedPatchToggleTest(props)); + + it('includes a toggle to unstaged button when staged', createStagedPatchToggleTest(props)); + }); + + it('includes an open file button', function() { + const openFile = sinon.stub(); + const wrapper = shallow(buildApp({openFile})); + + wrapper.find('button.icon-code').simulate('click'); + assert.isTrue(openFile.called); + }); + + function createToggleFileTest({stagingStatus, buttonClass, oppositeButtonClass}) { + return function() { + const toggleFile = sinon.stub(); + const wrapper = shallow(buildApp({toggleFile, stagingStatus})); + + assert.isTrue(wrapper.find(`button.${buttonClass}`).exists(), + `${buttonClass} expected, but not found`); + assert.isFalse(wrapper.find(`button.${oppositeButtonClass}`).exists(), + `${oppositeButtonClass} not expected, but found`); + + wrapper.find(`button.${buttonClass}`).simulate('click'); + assert.isTrue(toggleFile.called, `${buttonClass} click did nothing`); + }; + } + + it('includes a stage file button when unstaged', createToggleFileTest({ + stagingStatus: 'unstaged', + buttonClass: 'icon-move-down', + oppositeButtonClass: 'icon-move-up', + })); + + it('includes an unstage file button when staged', createToggleFileTest({ + stagingStatus: 'staged', + buttonClass: 'icon-move-up', + oppositeButtonClass: 'icon-move-down', + })); + }); +}); From 7cdfaf223725eb862befea373b8e3f412a51aa3d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 7 Jun 2018 11:11:04 -0400 Subject: [PATCH 0140/4847] Render the FilePatchHeaderView within the FilePatchView --- lib/views/file-patch-view.js | 77 ++++++++++++------------------ test/views/file-patch-view.test.js | 14 ++++-- 2 files changed, 41 insertions(+), 50 deletions(-) diff --git a/lib/views/file-patch-view.js b/lib/views/file-patch-view.js index f6244e056a..538ba31bf2 100644 --- a/lib/views/file-patch-view.js +++ b/lib/views/file-patch-view.js @@ -6,14 +6,22 @@ import FilePatchSelection from '../models/file-patch-selection'; import AtomTextEditor from '../atom/atom-text-editor'; import Marker from '../atom/marker'; import Decoration from '../atom/decoration'; +import FilePatchHeaderView from './file-patch-header-view'; export default class FilePatchView extends React.Component { static propTypes = { + relPath: PropTypes.string.isRequired, stagingStatus: PropTypes.oneOf(['staged', 'unstaged']).isRequired, isPartiallyStaged: PropTypes.bool.isRequired, filePatch: PropTypes.object.isRequired, + repository: PropTypes.object.isRequired, tooltips: PropTypes.object.isRequired, + + undoLastDiscard: PropTypes.func.isRequired, + diveIntoMirrorPatch: PropTypes.func.isRequired, + openFile: PropTypes.func.isRequired, + toggleFile: PropTypes.func.isRequired, } constructor(props) { @@ -38,59 +46,34 @@ export default class FilePatchView extends React.Component { render() { return (
- - - - {this.renderFileHeader()} - - - + 0} + hasUndoHistory={this.props.repository.hasDiscardHistory(this.props.relPath)} -
- ); - } + tooltips={this.props.tooltips} - renderFileHeader() { - return ( -
- - {this.isUnstaged() ? 'Unstaged Changes for ' : 'Staged Changes for '} - {this.props.filePatch.getPath()} - - {this.renderButtonGroup()} -
- ); - } + undoLastDiscard={this.props.undoLastDiscard} + diveIntoMirrorPatch={this.props.diveIntoMirrorPatch} + openFile={this.props.openFile} + toggleFile={this.props.toggleFile} + /> - renderButtonGroup() { - const hasHunks = this.props.filePatch.getHunks().length > 0; +
+ + + + + + +
- return ( - - {this.props.isPartiallyStaged || !hasHunks ? ( - - ) : null } - +
); } - - isUnstaged() { - return this.props.stagingStatus === 'unstaged'; - } } diff --git a/test/views/file-patch-view.test.js b/test/views/file-patch-view.test.js index c5225a1564..2d4b8095dc 100644 --- a/test/views/file-patch-view.test.js +++ b/test/views/file-patch-view.test.js @@ -7,13 +7,13 @@ import {cloneRepository, buildRepository} from '../helpers'; import FilePatchView from '../../lib/views/file-patch-view'; describe('FilePatchView', function() { - let atomEnv, filePatch; + let atomEnv, repository, filePatch; beforeEach(async function() { atomEnv = global.buildAtomEnvironment(); const workdirPath = await cloneRepository(); - const repository = await buildRepository(workdirPath); + repository = await buildRepository(workdirPath); // a.txt: unstaged changes await fs.writeFile(path.join(workdirPath, 'a.txt'), 'changed\n'); @@ -26,10 +26,18 @@ describe('FilePatchView', function() { function buildApp(overrideProps = {}) { const props = { + relPath: 'a.txt', stagingStatus: 'unstaged', isPartiallyStaged: false, filePatch, + repository, tooltips: atomEnv.tooltips, + + undoLastDiscard: () => {}, + diveIntoMirrorPatch: () => {}, + openFile: () => {}, + toggleFile: () => {}, + ...overrideProps, }; @@ -38,7 +46,7 @@ describe('FilePatchView', function() { it('renders the file header', function() { const wrapper = mount(buildApp()); - assert.isTrue(wrapper.find('FilePatchHeader').exists()); + assert.isTrue(wrapper.find('FilePatchHeaderView').exists()); }); it('renders the file patch within an editor', function() { From 36523deafec0ec228bda09be97c1af6a0cfa4e57 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 7 Jun 2018 14:15:29 -0400 Subject: [PATCH 0141/4847] Render FilePatchMetaViews for symlink and file mode changes --- lib/views/file-patch-meta-view.js | 37 +++++++ lib/views/file-patch-view.js | 130 +++++++++++++++++++++++- test/views/file-patch-meta-view.test.js | 53 ++++++++++ test/views/file-patch-view.test.js | 114 ++++++++++++++++++++- 4 files changed, 331 insertions(+), 3 deletions(-) create mode 100644 lib/views/file-patch-meta-view.js create mode 100644 test/views/file-patch-meta-view.test.js diff --git a/lib/views/file-patch-meta-view.js b/lib/views/file-patch-meta-view.js new file mode 100644 index 0000000000..4edbb69417 --- /dev/null +++ b/lib/views/file-patch-meta-view.js @@ -0,0 +1,37 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import cx from 'classnames'; + +export default class FilePatchMetaView extends React.Component { + static propTypes = { + title: PropTypes.string.isRequired, + actionIcon: PropTypes.string.isRequired, + actionText: PropTypes.string.isRequired, + + action: PropTypes.func.isRequired, + + children: PropTypes.element.isRequired, + }; + + render() { + return ( +
+
+
+

{this.props.title}

+
+ +
+
+
+ {this.props.children} +
+
+
+ ); + } +} diff --git a/lib/views/file-patch-view.js b/lib/views/file-patch-view.js index 538ba31bf2..056573a260 100644 --- a/lib/views/file-patch-view.js +++ b/lib/views/file-patch-view.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {Fragment} from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; @@ -7,6 +7,12 @@ import AtomTextEditor from '../atom/atom-text-editor'; import Marker from '../atom/marker'; import Decoration from '../atom/decoration'; import FilePatchHeaderView from './file-patch-header-view'; +import FilePatchMetaView from './file-patch-meta-view'; + +const executableText = { + 100644: 'non executable', + 100755: 'executable', +}; export default class FilePatchView extends React.Component { static propTypes = { @@ -22,6 +28,8 @@ export default class FilePatchView extends React.Component { diveIntoMirrorPatch: PropTypes.func.isRequired, openFile: PropTypes.func.isRequired, toggleFile: PropTypes.func.isRequired, + toggleModeChange: PropTypes.func.isRequired, + toggleSymlinkChange: PropTypes.func.isRequired, } constructor(props) { @@ -68,6 +76,10 @@ export default class FilePatchView extends React.Component { + + {this.renderExecutableModeChangeMeta()} + {this.renderSymlinkChangeMeta()} + @@ -76,4 +88,120 @@ export default class FilePatchView extends React.Component {
); } + + renderExecutableModeChangeMeta() { + if (!this.props.filePatch.didChangeExecutableMode()) { + return null; + } + + const oldMode = this.props.filePatch.getOldMode(); + const newMode = this.props.filePatch.getNewMode(); + + const attrs = this.props.stagingStatus === 'unstaged' + ? { + actionIcon: 'icon-move-down', + actionText: 'Stage Mode Change', + } + : { + actionIcon: 'icon-move-up', + actionText: 'Unstage Mode Change', + }; + + return ( + + + File changed mode + + from {executableText[oldMode]} {oldMode} + + + to {executableText[newMode]} {newMode} + + + + ); + } + + renderSymlinkChangeMeta() { + if (!this.props.filePatch.hasSymlink()) { + return null; + } + + let detail =
; + let title = ''; + const oldSymlink = this.props.filePatch.getOldSymlink(); + const newSymlink = this.props.filePatch.getNewSymlink(); + if (oldSymlink && newSymlink) { + detail = ( + + Symlink changed + + from {oldSymlink} + + + to {newSymlink} + . + + ); + title = 'Symlink changed'; + } else if (oldSymlink && !newSymlink) { + detail = ( + + Symlink + + to {oldSymlink} + + deleted. + + ); + title = 'Symlink deleted'; + } else if (!oldSymlink && newSymlink) { + detail = ( + + Symlink + + to {newSymlink} + + created. + + ); + title = 'Symlink created'; + } else { + return null; + } + + const attrs = this.props.stagingStatus === 'unstaged' + ? { + actionIcon: 'icon-move-down', + actionText: 'Stage Symlink Change', + } + : { + actionIcon: 'icon-move-up', + actionText: 'Unstage Symlink Change', + }; + + return ( + + + {detail} + + + ); + } } diff --git a/test/views/file-patch-meta-view.test.js b/test/views/file-patch-meta-view.test.js new file mode 100644 index 0000000000..8602e9a9f5 --- /dev/null +++ b/test/views/file-patch-meta-view.test.js @@ -0,0 +1,53 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import FilePatchMetaView from '../../lib/views/file-patch-meta-view'; + +describe('FilePatchMetaView', function() { + let atomEnv; + + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + function buildApp(overrideProps = {}, children =
) { + return ( + {}} + + {...overrideProps}> + {children} + + ); + } + + it('renders the title', function() { + const wrapper = shallow(buildApp({title: 'Yes'})); + assert.strictEqual(wrapper.find('.github-FilePatchView-metaTitle').text(), 'Yes'); + }); + + it('renders a control button with the correct text and callback', function() { + const action = sinon.stub(); + const wrapper = shallow(buildApp({action, actionText: 'do the thing', actionIcon: 'icon-move-down'})); + + const button = wrapper.find('button.icon-move-down'); + + assert.strictEqual(button.text(), 'do the thing'); + + button.simulate('click'); + assert.isTrue(action.called); + }); + + it('renders child elements as details', function() { + const wrapper = shallow(buildApp({},
)); + assert.isTrue(wrapper.find('.github-FilePatchView-metaDetails .child').exists()); + }); +}); diff --git a/test/views/file-patch-view.test.js b/test/views/file-patch-view.test.js index 2d4b8095dc..e5d477cc96 100644 --- a/test/views/file-patch-view.test.js +++ b/test/views/file-patch-view.test.js @@ -1,7 +1,7 @@ import path from 'path'; import fs from 'fs-extra'; import React from 'react'; -import {mount} from 'enzyme'; +import {shallow, mount} from 'enzyme'; import {cloneRepository, buildRepository} from '../helpers'; import FilePatchView from '../../lib/views/file-patch-view'; @@ -37,6 +37,8 @@ describe('FilePatchView', function() { diveIntoMirrorPatch: () => {}, openFile: () => {}, toggleFile: () => {}, + toggleModeChange: () => {}, + toggleSymlinkChange: () => {}, ...overrideProps, }; @@ -45,7 +47,7 @@ describe('FilePatchView', function() { } it('renders the file header', function() { - const wrapper = mount(buildApp()); + const wrapper = shallow(buildApp()); assert.isTrue(wrapper.find('FilePatchHeaderView').exists()); }); @@ -56,6 +58,114 @@ describe('FilePatchView', function() { assert.strictEqual(editor.instance().getModel().getText(), filePatch.present().getText()); }); + describe('executable mode changes', function() { + it('does not render if the mode has not changed', function() { + sinon.stub(filePatch, 'getOldMode').returns('100644'); + sinon.stub(filePatch, 'getNewMode').returns('100644'); + + const wrapper = shallow(buildApp()); + assert.isFalse(wrapper.find('FilePatchMetaView[title="Mode change"]').exists()); + }); + + it('renders change details within a meta container', function() { + sinon.stub(filePatch, 'getOldMode').returns('100644'); + sinon.stub(filePatch, 'getNewMode').returns('100755'); + + const wrapper = mount(buildApp({stagingStatus: 'unstaged'})); + + const meta = wrapper.find('FilePatchMetaView[title="Mode change"]'); + assert.isTrue(meta.exists()); + assert.strictEqual(meta.prop('actionIcon'), 'icon-move-down'); + assert.strictEqual(meta.prop('actionText'), 'Stage Mode Change'); + + const details = meta.find('.github-FilePatchView-metaDetails'); + assert.strictEqual(details.text(), 'File changed modefrom non executable 100644to executable 100755'); + }); + + it("stages or unstages the mode change when the meta container's action is triggered", function() { + sinon.stub(filePatch, 'getOldMode').returns('100644'); + sinon.stub(filePatch, 'getNewMode').returns('100755'); + + const toggleModeChange = sinon.stub(); + const wrapper = shallow(buildApp({stagingStatus: 'staged', toggleModeChange})); + + const meta = wrapper.find('FilePatchMetaView[title="Mode change"]'); + assert.isTrue(meta.exists()); + assert.strictEqual(meta.prop('actionIcon'), 'icon-move-up'); + assert.strictEqual(meta.prop('actionText'), 'Unstage Mode Change'); + + meta.prop('action')(); + assert.isTrue(toggleModeChange.called); + }); + }); + + describe('symlink changes', function() { + it('does not render if the symlink status is unchanged', function() { + const wrapper = mount(buildApp()); + assert.lengthOf(wrapper.find('FilePatchMetaView').filterWhere(v => v.prop('title').startsWith('Symlink')), 0); + }); + + it('renders symlink change information within a meta container', function() { + sinon.stub(filePatch, 'hasSymlink').returns(true); + sinon.stub(filePatch, 'getOldSymlink').returns('/old.txt'); + sinon.stub(filePatch, 'getNewSymlink').returns('/new.txt'); + + const wrapper = mount(buildApp({stagingStatus: 'unstaged'})); + const meta = wrapper.find('FilePatchMetaView[title="Symlink changed"]'); + assert.isTrue(meta.exists()); + assert.strictEqual(meta.prop('actionIcon'), 'icon-move-down'); + assert.strictEqual(meta.prop('actionText'), 'Stage Symlink Change'); + assert.strictEqual( + meta.find('.github-FilePatchView-metaDetails').text(), + 'Symlink changedfrom /old.txtto /new.txt.', + ); + }); + + it('stages or unstages the symlink change', function() { + const toggleSymlinkChange = sinon.stub(); + sinon.stub(filePatch, 'hasSymlink').returns(true); + sinon.stub(filePatch, 'getOldSymlink').returns('/old.txt'); + sinon.stub(filePatch, 'getNewSymlink').returns('/new.txt'); + + const wrapper = mount(buildApp({stagingStatus: 'staged', toggleSymlinkChange})); + const meta = wrapper.find('FilePatchMetaView[title="Symlink changed"]'); + assert.isTrue(meta.exists()); + assert.strictEqual(meta.prop('actionIcon'), 'icon-move-up'); + assert.strictEqual(meta.prop('actionText'), 'Unstage Symlink Change'); + + meta.find('button.icon-move-up').simulate('click'); + assert.isTrue(toggleSymlinkChange.called); + }); + + it('renders details for a symlink deletion', function() { + sinon.stub(filePatch, 'hasSymlink').returns(true); + sinon.stub(filePatch, 'getOldSymlink').returns('/old.txt'); + sinon.stub(filePatch, 'getNewSymlink').returns(null); + + const wrapper = mount(buildApp()); + const meta = wrapper.find('FilePatchMetaView[title="Symlink deleted"]'); + assert.isTrue(meta.exists()); + assert.strictEqual( + meta.find('.github-FilePatchView-metaDetails').text(), + 'Symlinkto /old.txtdeleted.', + ); + }); + + it('renders details for a symlink creation', function() { + sinon.stub(filePatch, 'hasSymlink').returns(true); + sinon.stub(filePatch, 'getOldSymlink').returns(null); + sinon.stub(filePatch, 'getNewSymlink').returns('/new.txt'); + + const wrapper = mount(buildApp()); + const meta = wrapper.find('FilePatchMetaView[title="Symlink created"]'); + assert.isTrue(meta.exists()); + assert.strictEqual( + meta.find('.github-FilePatchView-metaDetails').text(), + 'Symlinkto /new.txtcreated.', + ); + }); + }); + it('renders a header for each hunk'); describe('hunk lines', function() { From 55de6f9769e335140c1780e4ce8b43deebdca711 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 8 Jun 2018 11:30:12 +0900 Subject: [PATCH 0142/4847] :memo: Fix typo --- docs/rfcs/004-issueish-list.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index ea8f7e92ac..2c16fc1ba9 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -72,7 +72,7 @@ For a pull request, the issueish pane shows: If no current PR can be found, an "open new pull request" button is shown. If needed it also offers to "Publish" or "Push". -![new pr](https://user-images.githubusercontent.com/378023/41100932-9a3cd7be-6a9d-11e8-85c4-c995b71548c7.png) +![new pr](https://user-images.githubusercontent.com/378023/41136021-33249004-6b0f-11e8-9cf0-08bf4a9a2767.png) When the current branch is the default branch, e.g. `master`, a message is shown that suggests to "Create a new branch". From 20ed5c68a8d324f02db20a66ce08e1788b6aad92 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 8 Jun 2018 11:52:31 +0900 Subject: [PATCH 0143/4847] Add PR number to list item Some teams use these numbers a lot when talking about PRs. --- docs/rfcs/004-issueish-list.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index 2c16fc1ba9..81b59d3b7e 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -30,17 +30,17 @@ Each list has a "collapse arrow" in its header. Clicking the collapse arrow togg If either list exceeds 20 items, truncate the list and render a "More" link after its final item. Clicking "more" opens the corresponding search on GitHub. -![list](https://user-images.githubusercontent.com/378023/41097007-7a32992e-6a91-11e8-9c4b-2417cf94dce9.png) +![list](https://user-images.githubusercontent.com/378023/41136538-ad5c461c-6b11-11e8-9e1d-e4a674f628cd.png) Each list item renders a tile containing a compact set of information about that pull request: * Mini author avatar * Title, truncated if necessary -* Terse relative timestamp (1d, 2h, 30m) -* Pull request state: open, closed, merged +* PR number (`#1503`) * Status check summary +* Terse relative timestamp (1d, 2h, 30m) -![List item](https://user-images.githubusercontent.com/378023/40964791-f4b28fbc-68e6-11e8-907b-c7d436d0d315.png) +![list item](https://user-images.githubusercontent.com/378023/41136622-1102db54-6b12-11e8-8b9b-49ecc45ac98f.png) Clicking on a list item opens an issueish pane item for the chosen issueish in the same pane container as the parent component (by default, the right dock). If the issuish pane item is already open, it is activated instead. @@ -72,7 +72,7 @@ For a pull request, the issueish pane shows: If no current PR can be found, an "open new pull request" button is shown. If needed it also offers to "Publish" or "Push". -![new pr](https://user-images.githubusercontent.com/378023/41136021-33249004-6b0f-11e8-9cf0-08bf4a9a2767.png) +![new pr](https://user-images.githubusercontent.com/378023/41136463-5d8dd3da-6b11-11e8-8e28-72275a691430.png) When the current branch is the default branch, e.g. `master`, a message is shown that suggests to "Create a new branch". From c5e174e13237fb5092e6d3e143e5d3ca7400e711 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 8 Jun 2018 14:31:38 +0900 Subject: [PATCH 0144/4847] Add CI status to PR pane --- docs/rfcs/004-issueish-list.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index 81b59d3b7e..fca6440922 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -56,9 +56,9 @@ For a pull request, the issueish pane shows: * "Checkout" button to fetch (if necessary) and check out the pull request. Only enabled if the current pull request is not the current one. * `Commits` with count, links to .com (for now), optional with avatars * `Checks` with count, links to .com (for now) + * CI status, each item links to the detail page * `Files changed` with count, links to .com (for now), optional with "+-" bar -* Controls for actions: - * Mergability status -> `Able to merge`, links to the [Merging controls at the bottom](https://github.com/atom/github/pull/1503#partial-pull-merging) +* Mergability status -> `Able to merge`, links to the [Merging controls at the bottom](https://github.com/atom/github/pull/1503#partial-pull-merging) * "Merge PR" to merge the pull request on GitHub if it is open. * "Close" to close the pull request, unmerged, if it is open. * "Re-open PR" to re-open a pull request if it is closed. @@ -66,7 +66,7 @@ For a pull request, the issueish pane shows: * Reaction emoji and counts. * Description (PR body) as rendered markdown. -![detail](https://user-images.githubusercontent.com/378023/41097077-ba228d00-6a91-11e8-9445-a9557c03e6b6.png) +![detail](https://user-images.githubusercontent.com/378023/41140383-368c45d4-6b28-11e8-87c2-d4bc0b47fbe1.png) ## New PR From a5ec7c12c49291f868be26be402967de1d25e9c7 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Fri, 8 Jun 2018 09:15:33 +0000 Subject: [PATCH 0145/4847] fix(package): update classnames to version 2.2.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 39bda68bd6..9ff02bd63f 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "babel-plugin-transform-object-rest-spread": "6.26.0", "babel-preset-react": "6.24.1", "bytes": "^3.0.0", - "classnames": "2.2.5", + "classnames": "2.2.6", "compare-sets": "1.0.1", "dugite": "^1.66.0", "event-kit": "2.5.0", From e59cc5c31235d37750a0440b4ff21489c54a600c Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Fri, 8 Jun 2018 20:04:43 +0000 Subject: [PATCH 0146/4847] chore(package): update sinon to version 5.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ff02bd63f..1d33457f4a 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "mocha-stress": "1.0.0", "node-fetch": "2.1.2", "relay-compiler": "1.6.0", - "sinon": "5.1.0", + "sinon": "5.1.1", "test-until": "1.1.1" }, "consumedServices": { From 33595a847fe7294d975ef2994288640e43bc51de Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Sat, 9 Jun 2018 20:38:52 -0400 Subject: [PATCH 0147/4847] HunkHeaderView --- lib/views/hunk-header-view.js | 60 ++++++++++++++++++++++ test/views/hunk-header-view.test.js | 78 +++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 lib/views/hunk-header-view.js create mode 100644 test/views/hunk-header-view.test.js diff --git a/lib/views/hunk-header-view.js b/lib/views/hunk-header-view.js new file mode 100644 index 0000000000..e0ba9f9b46 --- /dev/null +++ b/lib/views/hunk-header-view.js @@ -0,0 +1,60 @@ +import React, {Fragment} from 'react'; +import PropTypes from 'prop-types'; +import cx from 'classnames'; + +import RefHolder from '../models/ref-holder'; +import Tooltip from '../atom/tooltip'; + +export default class HunkHeaderView extends React.Component { + static propTypes = { + hunk: PropTypes.object.isRequired, + isSelected: PropTypes.bool.isRequired, + stagingStatus: PropTypes.oneOf(['unstaged', 'staged']).isRequired, + selectionMode: PropTypes.oneOf(['hunk', 'line']).isRequired, + toggleSelectionLabel: PropTypes.string.isRequired, + discardSelectionLabel: PropTypes.string.isRequired, + + tooltips: PropTypes.object.isRequired, + + toggleSelection: PropTypes.func.isRequired, + discardSelection: PropTypes.func.isRequired, + }; + + constructor(props) { + super(props); + + this.refDiscardButton = new RefHolder(); + } + + render() { + const conditional = { + 'is-selected': this.props.isSelected, + 'is-hunkMode': this.props.selectionMode === 'hunk', + }; + + return ( +
+ + {this.props.hunk.getHeader().trim()} {this.props.hunk.getSectionHeading().trim()} + + + {this.props.stagingStatus === 'unstaged' && ( + +
+ ); + } +} diff --git a/test/views/hunk-header-view.test.js b/test/views/hunk-header-view.test.js new file mode 100644 index 0000000000..525aa9a10c --- /dev/null +++ b/test/views/hunk-header-view.test.js @@ -0,0 +1,78 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import HunkHeaderView from '../../lib/views/hunk-header-view'; +import Hunk from '../../lib/models/hunk'; + +describe('HunkHeaderView', function() { + let atomEnv, hunk; + + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + hunk = new Hunk(0, 1, 10, 11, 'section heading', []); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + function buildApp(overrideProps = {}) { + return ( + {}} + discardSelection={() => {}} + + {...overrideProps} + /> + ); + } + + it('applies a CSS class when selected', function() { + const wrapper = shallow(buildApp({isSelected: true})); + assert.isTrue(wrapper.find('.github-HunkHeaderView').hasClass('is-selected')); + + wrapper.setProps({isSelected: false}); + assert.isFalse(wrapper.find('.github-HunkHeaderView').hasClass('is-selected')); + }); + + it('applies a CSS class in hunk selection mode', function() { + const wrapper = shallow(buildApp({selectionMode: 'hunk'})); + assert.isTrue(wrapper.find('.github-HunkHeaderView').hasClass('is-hunkMode')); + + wrapper.setProps({selectionMode: 'line'}); + assert.isFalse(wrapper.find('.github-HunkHeaderView').hasClass('is-hunkMode')); + }); + + it('renders the hunk header title', function() { + const wrapper = shallow(buildApp()); + assert.strictEqual(wrapper.find('.github-HunkHeaderView-title').text(), '@@ -0,10 +1,11 @@ section heading'); + }); + + it('renders a button to toggle the selection', function() { + const toggleSelection = sinon.stub(); + const wrapper = shallow(buildApp({toggleSelectionLabel: 'Do the thing', toggleSelection})); + const button = wrapper.find('button.github-HunkHeaderView-stageButton'); + assert.strictEqual(button.text(), 'Do the thing'); + button.simulate('click'); + assert.isTrue(toggleSelection.called); + }); + + it('renders a button to discard an unstaged selection', function() { + const discardSelection = sinon.stub(); + const wrapper = shallow(buildApp({stagingStatus: 'unstaged', discardSelectionLabel: 'Nope', discardSelection})); + const button = wrapper.find('button.github-HunkHeaderView-discardButton'); + assert.isTrue(button.exists()); + assert.isTrue(wrapper.find('Tooltip[title="Nope"]').exists()); + button.simulate('click'); + assert.isTrue(discardSelection.called); + }); +}); From 1c743386e80848fdc94b4d137c20e9ecb3519302 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Mon, 11 Jun 2018 06:12:19 +0000 Subject: [PATCH 0148/4847] chore(package): update sinon to version 6.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1d33457f4a..38542b4160 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "mocha-stress": "1.0.0", "node-fetch": "2.1.2", "relay-compiler": "1.6.0", - "sinon": "5.1.1", + "sinon": "6.0.0", "test-until": "1.1.1" }, "consumedServices": { From 381ff5b6a183a179942ac9938b3a6b7982bf1b6d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 11:15:49 -0400 Subject: [PATCH 0149/4847] Use PropTypes.node instead of PropTypes.element --- lib/atom/atom-text-editor.js | 2 +- lib/atom/decoration.js | 2 +- lib/atom/marker-layer.js | 2 +- lib/atom/marker.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/atom/atom-text-editor.js b/lib/atom/atom-text-editor.js index ab7eedf561..b2b77c276e 100644 --- a/lib/atom/atom-text-editor.js +++ b/lib/atom/atom-text-editor.js @@ -43,7 +43,7 @@ export default class AtomTextEditor extends React.PureComponent { text: PropTypes.string, didChange: PropTypes.func, didChangeCursorPosition: PropTypes.func, - children: PropTypes.element, + children: PropTypes.node, } static defaultProps = { diff --git a/lib/atom/decoration.js b/lib/atom/decoration.js index 121f9c46ed..1da7256eac 100644 --- a/lib/atom/decoration.js +++ b/lib/atom/decoration.js @@ -16,7 +16,7 @@ class WrappedDecoration extends React.Component { type: PropTypes.oneOf(['line', 'line-number', 'highlight', 'overlay', 'gutter', 'block']).isRequired, position: PropTypes.oneOf(['head', 'tail', 'before', 'after']), className: PropTypes.string, - children: PropTypes.element, + children: PropTypes.node, itemHolder: RefHolderPropType, options: PropTypes.object, } diff --git a/lib/atom/marker-layer.js b/lib/atom/marker-layer.js index 0ff781c1e2..5bf1e2f9cb 100644 --- a/lib/atom/marker-layer.js +++ b/lib/atom/marker-layer.js @@ -17,7 +17,7 @@ class WrappedMarkerLayer extends React.Component { static propTypes = { ...markerLayerProps, editor: PropTypes.object, - children: PropTypes.element, + children: PropTypes.node, handleID: PropTypes.func, }; diff --git a/lib/atom/marker.js b/lib/atom/marker.js index 34ed5db4f4..72db45c203 100644 --- a/lib/atom/marker.js +++ b/lib/atom/marker.js @@ -41,7 +41,7 @@ class WrappedMarker extends React.Component { screenRange: RangePropType, screenPosition: PointPropType, markableHolder: RefHolderPropType, - children: PropTypes.element, + children: PropTypes.node, handleID: PropTypes.func, } From d876ddc9db2956c1e9bece43542a2d5637f73122 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 11:52:24 -0400 Subject: [PATCH 0150/4847] Decorate a parent Marker or MarkerLayer --- lib/atom/decoration.js | 19 +++++++++++++------ lib/atom/marker-layer.js | 10 +++++++++- lib/atom/marker.js | 11 ++++++++++- test/atom/decoration.test.js | 12 ++++++++++++ 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/lib/atom/decoration.js b/lib/atom/decoration.js index 1da7256eac..08ec2b901a 100644 --- a/lib/atom/decoration.js +++ b/lib/atom/decoration.js @@ -6,13 +6,14 @@ import {Disposable} from 'event-kit'; import {createItem, autobind} from '../helpers'; import {RefHolderPropType} from '../prop-types'; import {TextEditorContext} from './atom-text-editor'; -import {MarkerContext} from './marker'; +import {DecorableContext} from './marker'; import RefHolder from '../models/ref-holder'; class WrappedDecoration extends React.Component { static propTypes = { editorHolder: RefHolderPropType.isRequired, markerHolder: RefHolderPropType.isRequired, + decorateMethod: PropTypes.oneOf(['decorateMarker', 'decorateMarkerLayer']), type: PropTypes.oneOf(['line', 'line-number', 'highlight', 'overlay', 'gutter', 'block']).isRequired, position: PropTypes.oneOf(['head', 'tail', 'before', 'after']), className: PropTypes.string, @@ -22,6 +23,7 @@ class WrappedDecoration extends React.Component { } static defaultProps = { + decorateMethod: 'decorateMarker', options: {}, position: 'head', } @@ -102,7 +104,7 @@ class WrappedDecoration extends React.Component { const marker = this.props.markerHolder.get(); this.decorationHolder.setter( - editor.decorateMarker(marker, options), + editor[this.props.decorateMethod](marker, options), ); } @@ -160,11 +162,16 @@ export default class Decoration extends React.Component { return ( {editorHolder => ( - - {markerHolder => ( - + + {({holder, decorateMethod}) => ( + )} - + )} ); diff --git a/lib/atom/marker-layer.js b/lib/atom/marker-layer.js index 5bf1e2f9cb..8793c3ee50 100644 --- a/lib/atom/marker-layer.js +++ b/lib/atom/marker-layer.js @@ -5,6 +5,7 @@ import {Disposable} from 'event-kit'; import {autobind, extractProps} from '../helpers'; import RefHolder from '../models/ref-holder'; import {TextEditorContext} from './atom-text-editor'; +import {DecorableContext} from './marker'; const markerLayerProps = { maintainHistory: PropTypes.bool, @@ -35,6 +36,11 @@ class WrappedMarkerLayer extends React.Component { this.state = { editorHolder: RefHolder.on(this.props.editor), }; + + this.decorable = { + holder: this.layerHolder, + decorateMethod: 'decorateMarkerLayer', + }; } static getDerivedStateFromProps(props, state) { @@ -54,7 +60,9 @@ class WrappedMarkerLayer extends React.Component { render() { return ( - {this.props.children} + + {this.props.children} + ); } diff --git a/lib/atom/marker.js b/lib/atom/marker.js index 72db45c203..22e620f166 100644 --- a/lib/atom/marker.js +++ b/lib/atom/marker.js @@ -33,6 +33,8 @@ const markerProps = { export const MarkerContext = React.createContext(); +export const DecorableContext = React.createContext(); + class WrappedMarker extends React.Component { static propTypes = { ...markerProps, @@ -56,6 +58,11 @@ class WrappedMarker extends React.Component { this.sub = new Disposable(); this.markerHolder = new RefHolder(); + + this.decorable = { + holder: this.markerHolder, + decorateMethod: 'decorateMarker', + }; } componentDidMount() { @@ -65,7 +72,9 @@ class WrappedMarker extends React.Component { render() { return ( - {this.props.children} + + {this.props.children} + ); } diff --git a/test/atom/decoration.test.js b/test/atom/decoration.test.js index 45feeaee37..441c5da836 100644 --- a/test/atom/decoration.test.js +++ b/test/atom/decoration.test.js @@ -5,6 +5,7 @@ import {mount} from 'enzyme'; import Decoration from '../../lib/atom/decoration'; import AtomTextEditor from '../../lib/atom/atom-text-editor'; import Marker from '../../lib/atom/marker'; +import MarkerLayer from '../../lib/atom/marker-layer'; describe('Decoration', function() { let atomEnv, editor, marker; @@ -126,4 +127,15 @@ describe('Decoration', function() { assert.lengthOf(theEditor.getLineDecorations({position: 'head', class: 'whatever'}), 1); }); + + it('decorates a parent MarkerLayer', function() { + mount( + + + + + + , + ); + }); }); From d82f5649920fa88e0b72d7e57b5e73007f50cc68 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 11:55:50 -0400 Subject: [PATCH 0151/4847] Render a HunkHeaderView for each hunk header --- lib/views/file-patch-view.js | 41 ++++++++++++++++++++++++++++++ test/views/file-patch-view.test.js | 12 ++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/lib/views/file-patch-view.js b/lib/views/file-patch-view.js index 056573a260..429b468215 100644 --- a/lib/views/file-patch-view.js +++ b/lib/views/file-patch-view.js @@ -8,6 +8,7 @@ import Marker from '../atom/marker'; import Decoration from '../atom/decoration'; import FilePatchHeaderView from './file-patch-header-view'; import FilePatchMetaView from './file-patch-meta-view'; +import HunkHeaderView from './hunk-header-view'; const executableText = { 100644: 'non executable', @@ -74,6 +75,7 @@ export default class FilePatchView extends React.Component {
+ @@ -82,6 +84,8 @@ export default class FilePatchView extends React.Component { + + {this.renderHunkHeaders()}
@@ -204,4 +208,41 @@ export default class FilePatchView extends React.Component { ); } + + renderHunkHeaders() { + const selectedHunks = this.state.selection.getSelectedHunks(); + const isHunkSelectionMode = this.state.selection.getMode() === 'hunk'; + const toggleVerb = this.props.stagingStatus === 'unstaged' ? 'Stage' : 'Unstage'; + + return this.props.filePatch.getHunks().map((hunk, index) => { + const isSelected = selectedHunks.has(hunk); + let buttonSuffix = (isHunkSelectionMode || !isSelected) ? ' Hunk' : ' Selection'; + if (isSelected && selectedHunks.size > 1) { + buttonSuffix += 's'; + } + const toggleSelectionLabel = `${toggleVerb}${buttonSuffix}`; + const discardSelectionLabel = `Discard${buttonSuffix}`; + const bufferPosition = this.state.presentedFilePatch.getHunkStartPositions()[index]; + + return ( + + + {}} + discardSelection={() => {}} + /> + + + ); + }); + } } diff --git a/test/views/file-patch-view.test.js b/test/views/file-patch-view.test.js index e5d477cc96..244972580c 100644 --- a/test/views/file-patch-view.test.js +++ b/test/views/file-patch-view.test.js @@ -166,7 +166,17 @@ describe('FilePatchView', function() { }); }); - it('renders a header for each hunk'); + it('renders a header for each hunk', function() { + const hunks = [ + new Hunk(0, 0, 5, 5, 'hunk 0', []), + new Hunk(10, 10, 15, 15, 'hunk 1', []), + ]; + sinon.stub(filePatch, 'getHunks').returns(hunks); + + const wrapper = mount(buildApp()); + assert.isTrue(wrapper.find('HunkHeaderView').someWhere(h => h.prop('hunk') === hunks[0])); + assert.isTrue(wrapper.find('HunkHeaderView').someWhere(h => h.prop('hunk') === hunks[1])); + }); describe('hunk lines', function() { it('decorates added lines'); From 0850afe1f92485448cd1a4396e7cee6dcff3d6a3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 11:56:04 -0400 Subject: [PATCH 0152/4847] Decorate lines --- lib/views/file-patch-view.js | 27 ++++++++++++++ test/views/file-patch-view.test.js | 57 ++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/lib/views/file-patch-view.js b/lib/views/file-patch-view.js index 429b468215..b1ecb833e4 100644 --- a/lib/views/file-patch-view.js +++ b/lib/views/file-patch-view.js @@ -5,6 +5,7 @@ import cx from 'classnames'; import FilePatchSelection from '../models/file-patch-selection'; import AtomTextEditor from '../atom/atom-text-editor'; import Marker from '../atom/marker'; +import MarkerLayer from '../atom/marker-layer'; import Decoration from '../atom/decoration'; import FilePatchHeaderView from './file-patch-header-view'; import FilePatchMetaView from './file-patch-meta-view'; @@ -86,6 +87,20 @@ export default class FilePatchView extends React.Component { {this.renderHunkHeaders()} + + {this.renderLineDecorations( + this.state.presentedFilePatch.getAddedBufferPositions(), + 'github-FilePatchView-line--added', + )} + {this.renderLineDecorations( + this.state.presentedFilePatch.getDeletedBufferPositions(), + 'github-FilePatchView-line--deleted', + )} + {this.renderLineDecorations( + this.state.presentedFilePatch.getNoNewlineBufferPositions(), + 'github-FilePatchView-line--nonewline', + )} + @@ -245,4 +260,16 @@ export default class FilePatchView extends React.Component { ); }); } + + renderLineDecorations(positions, lineClass) { + return ( + + {positions.map((position, index) => { + return ; + })} + + + + ); + } } diff --git a/test/views/file-patch-view.test.js b/test/views/file-patch-view.test.js index 244972580c..2209313379 100644 --- a/test/views/file-patch-view.test.js +++ b/test/views/file-patch-view.test.js @@ -4,6 +4,8 @@ import React from 'react'; import {shallow, mount} from 'enzyme'; import {cloneRepository, buildRepository} from '../helpers'; +import Hunk from '../../lib/models/hunk'; +import HunkLine from '../../lib/models/hunk-line'; import FilePatchView from '../../lib/views/file-patch-view'; describe('FilePatchView', function() { @@ -179,10 +181,59 @@ describe('FilePatchView', function() { }); describe('hunk lines', function() { - it('decorates added lines'); + it('decorates added lines', function() { + const hunks = [ + new Hunk(0, 0, 1, 1, 'hunk 0', [ + new HunkLine('line 0', 'added', 0, 1, 0), + new HunkLine('line 1', 'deleted', 0, 1, 0), + ]), + ]; + sinon.stub(filePatch, 'getHunks').returns(hunks); - it('decorates deleted lines'); + const wrapper = mount(buildApp()); + assert.lengthOf( + wrapper.find('Decoration').filterWhere(h => { + return h.prop('type') === 'line' && h.prop('className') === 'github-FilePatchView-line--added'; + }), + 1, + ); + }); + + it('decorates deleted lines', function() { + const hunks = [ + new Hunk(0, 0, 1, 1, 'hunk 0', [ + new HunkLine('line 0', 'added', 0, 1, 0), + new HunkLine('line 1', 'deleted', 0, 1, 0), + ]), + ]; + sinon.stub(filePatch, 'getHunks').returns(hunks); + + const wrapper = mount(buildApp()); + assert.lengthOf( + wrapper.find('Decoration').filterWhere(h => { + return h.prop('type') === 'line' && h.prop('className') === 'github-FilePatchView-line--deleted'; + }), + 1, + ); + }); + + it('decorates the nonewline line', function() { + const hunks = [ + new Hunk(0, 0, 1, 1, 'hunk 0', [ + new HunkLine('line 0', 'added', 0, 1, 0), + new HunkLine('line 1', 'deleted', 0, 1, 0), + new HunkLine('no newline', 'nonewline', 0, 1, 0), + ]), + ]; + sinon.stub(filePatch, 'getHunks').returns(hunks); - it('decorates the nonewlines line'); + const wrapper = mount(buildApp()); + assert.lengthOf( + wrapper.find('Decoration').filterWhere(h => { + return h.prop('type') === 'line' && h.prop('className') === 'github-FilePatchView-line--nonewline'; + }), + 1, + ); + }); }); }); From 0b3faa3eef8eb27c368084f14035f982924b520c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 13:38:57 -0400 Subject: [PATCH 0153/4847] Pass the WorkdirContextPool into the React component tree --- lib/controllers/root-controller.js | 9 +++++++-- lib/github-package.js | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 6dbedb6469..77ff3107bb 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -26,6 +26,7 @@ import GitCacheView from '../views/git-cache-view'; import Conflict from '../models/conflicts/conflict'; import RefHolder from '../models/ref-holder'; import Switchboard from '../switchboard'; +import {WorkdirContextPoolPropType} from '../prop-types'; import {destroyFilePatchPaneItems, destroyEmptyFilePatchPaneItems, autobind} from '../helpers'; import {GitError} from '../git-shell-out-strategy'; @@ -53,6 +54,7 @@ export default class RootController extends React.Component { destroyGitTabItem: PropTypes.func.isRequired, destroyGithubTabItem: PropTypes.func.isRequired, pipelineManager: PropTypes.object, + workdirContextPool: WorkdirContextPoolPropType.isRequired, } static defaultProps = { @@ -322,10 +324,13 @@ export default class RootController extends React.Component { {({itemHolder, params}) => ( )} diff --git a/lib/github-package.js b/lib/github-package.js index 1223b648ae..f5e6c4d9fc 100644 --- a/lib/github-package.js +++ b/lib/github-package.js @@ -288,7 +288,7 @@ export default class GithubPackage { destroyGitTabItem={this.destroyGitTabItem} destroyGithubTabItem={this.destroyGithubTabItem} removeFilePatchItem={this.removeFilePatchItem} - getRepositoryForWorkdir={this.getRepositoryForWorkdir} + workdirContextPool={this.contextPool} />, this.element, callback, ); } From 0017501d0c5cbc368562889a255e5ac8a31a6540 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 13:39:07 -0400 Subject: [PATCH 0154/4847] Start shifting CSS around --- styles/file-patch-view.less | 20 +++ styles/hunk-header-view.less | 162 ++++++++++++++++++ styles/{hunk-view.less => hunk-view.old.less} | 0 3 files changed, 182 insertions(+) create mode 100644 styles/hunk-header-view.less rename styles/{hunk-view.less => hunk-view.old.less} (100%) diff --git a/styles/file-patch-view.less b/styles/file-patch-view.less index 224f1bb133..0c0dd50899 100644 --- a/styles/file-patch-view.less +++ b/styles/file-patch-view.less @@ -1,5 +1,8 @@ @import "variables"; +@hunk-fg-color: @text-color-subtle; +@hunk-bg-color: @pane-item-background-color; + .github-FilePatchView { display: flex; flex-direction: column; @@ -136,4 +139,21 @@ } } + // Line decorations + + &-line { + // mixin + .hunk-line-mixin(@fg; @bg) { + color: saturate( mix(@fg, @text-color-highlight, 20%), 20%); + background-color: saturate( mix(@bg, @hunk-bg-color, 15%), 20%); + } + + &--deleted { + .hunk-line-mixin(@text-color-error, @background-color-error); + } + + &--added { + .hunk-line-mixin(@text-color-success, @background-color-success); + } + } } diff --git a/styles/hunk-header-view.less b/styles/hunk-header-view.less new file mode 100644 index 0000000000..a1e1e19449 --- /dev/null +++ b/styles/hunk-header-view.less @@ -0,0 +1,162 @@ +@import "ui-variables"; + +@hunk-fg-color: @text-color-subtle; +@hunk-bg-color: @pane-item-background-color; + +.github-HunkHeaderView { + font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; + + display: flex; + align-items: stretch; + font-size: .9em; + background-color: @panel-heading-background-color; + border-bottom: 1px solid @panel-heading-border-color; + + &-title { + flex: 1; + line-height: 2.4; + padding: 0 @component-padding; + color: @text-color-subtle; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + -webkit-font-smoothing: antialiased; + } + + &-stageButton, + &-discardButton { + line-height: 1; + padding-left: @component-padding; + padding-right: @component-padding; + font-family: @font-family; + border: none; + border-left: 1px solid @panel-heading-border-color; + background-color: transparent; + cursor: default; + &:hover { background-color: @button-background-color-hover; } + &:active { background-color: @panel-heading-border-color; } + } + + // pixel fit the icon + &-discardButton:before { + text-align: left; + width: auto; + } + + &-line { + display: table-row; + line-height: 1.5em; + color: @hunk-fg-color; + &.is-unchanged { + -webkit-font-smoothing: antialiased; + } + } + + &-lineNumber { + display: table-cell; + min-width: 3.5em; // min 4 chars + overflow: hidden; + padding: 0 .5em; + text-align: right; + border-right: 1px solid @base-border-color; + -webkit-font-smoothing: antialiased; + } + + &-plusMinus { + margin-right: 1ch; + color: fade(@text-color, 50%); + vertical-align: top; + } + + &-lineContent { + display: table-cell; + padding: 0 .5em 0 3ch; // indent 3 characters + text-indent: -2ch; // remove indentation for the +/- + white-space: pre-wrap; + word-break: break-word; + width: 100%; + vertical-align: top; + } + + &-lineText { + display: inline-block; + text-indent: 0; + } +} + + +// +// States +// ------------------------------- + +.github-HunkView.is-selected.is-hunkMode .github-HunkView-header { + background-color: @background-color-selected; + .github-HunkView-title { + color: @text-color; + } + .github-HunkView-stageButton, .github-HunkView-discardButton { + border-color: mix(@text-color, @background-color-selected, 25%); + } +} + +.github-HunkView-title:hover { + color: @text-color-highlight; +} + +.github-HunkView-line { + + // mixin + .hunk-line-mixin(@fg; @bg) { + &:hover { + background-color: @background-color-highlight; + } + &.is-selected { + color: @text-color; + background-color: @background-color-selected; + } + .github-HunkView-lineContent { + color: saturate( mix(@fg, @text-color-highlight, 20%), 20%); + background-color: saturate( mix(@bg, @hunk-bg-color, 15%), 20%); + } + // hightlight when focused + selected + .github-FilePatchView:focus &.is-selected .github-HunkView-lineContent { + color: saturate( mix(@fg, @text-color-highlight, 10%), 10%); + background-color: saturate( mix(@bg, @hunk-bg-color, 25%), 10%); + } + } + + &.is-deleted { + .hunk-line-mixin(@text-color-error, @background-color-error); + } + + &.is-added { + .hunk-line-mixin(@text-color-success, @background-color-success); + } + + // divider line between added and deleted lines + &.is-deleted + .is-added .github-HunkView-lineContent { + box-shadow: 0 -1px 0 hsla(0,0%,50%,.1); + } + +} + +// focus colors +.github-FilePatchView:focus { + .github-HunkView.is-selected.is-hunkMode .github-HunkView-title, + .github-HunkView.is-selected.is-hunkMode .github-HunkView-header, + .github-HunkView-line.is-selected .github-HunkView-lineNumber { + color: contrast(@button-background-color-selected); + background: @button-background-color-selected; + } + .github-HunkView-line.is-selected .github-HunkView-lineNumber { + border-color: mix(@button-border-color, @button-background-color-selected, 25%); + } + .github-HunkView.is-selected.is-hunkMode .github-HunkView { + &-stageButton, + &-discardButton { + border-color: mix(@hunk-bg-color, @button-background-color-selected, 30%); + &:hover { background-color: mix(@hunk-bg-color, @button-background-color-selected, 10%); } + &:active { background-color: @button-background-color-selected; } + } + } +} diff --git a/styles/hunk-view.less b/styles/hunk-view.old.less similarity index 100% rename from styles/hunk-view.less rename to styles/hunk-view.old.less From 80704060542da4ad289c00e671ca9c4cef831827 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 14:00:23 -0400 Subject: [PATCH 0155/4847] Specify what constitutes the "current" PR --- docs/rfcs/004-issueish-list.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index fca6440922..62daf7b591 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -22,7 +22,7 @@ As an initial building block toward a pull request review workflow. Within the GitHub panel, render a vertical stack of two collapsible lists of _issueish_ (pull request or issue) items: -_First list: current pull request_. If the active branch is associated with one or more open pull requests on the GitHub repository, render an item for each. +_First list: current pull request_. If the active branch is associated with one or more open pull requests on a GitHub repository, render an item for each. "Associated with" means that the pull request's head ref and head repository matches the upstream remote ref for the current branch in the active git repository. _Second list: all open pull requests_. List all open pull requests on the GitHub repository. From be873aa436d047699801455570409533947364c5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 14:00:32 -0400 Subject: [PATCH 0156/4847] Specify the PR list order --- docs/rfcs/004-issueish-list.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index 62daf7b591..796cd1e62b 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -24,7 +24,7 @@ Within the GitHub panel, render a vertical stack of two collapsible lists of _is _First list: current pull request_. If the active branch is associated with one or more open pull requests on a GitHub repository, render an item for each. "Associated with" means that the pull request's head ref and head repository matches the upstream remote ref for the current branch in the active git repository. -_Second list: all open pull requests_. List all open pull requests on the GitHub repository. +_Second list: all open pull requests_. List all open pull requests on the GitHub repository, ordered by decreasing creation date. Each list has a "collapse arrow" in its header. Clicking the collapse arrow toggles the visibility of that list's items, accordion-style. From 766c5fd6e15889ab3aba3042ca73907ac8767f54 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 14:00:59 -0400 Subject: [PATCH 0157/4847] We're starting with a regular pane item for issueishes --- docs/rfcs/004-issueish-list.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index 796cd1e62b..5a74a332da 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -42,7 +42,7 @@ Each list item renders a tile containing a compact set of information about that ![list item](https://user-images.githubusercontent.com/378023/41136622-1102db54-6b12-11e8-8b9b-49ecc45ac98f.png) -Clicking on a list item opens an issueish pane item for the chosen issueish in the same pane container as the parent component (by default, the right dock). If the issuish pane item is already open, it is activated instead. +Clicking on a list item opens an issueish pane item for the chosen issueish. If the issueish pane item is already open, it is activated instead. ### Issueish Pane Item: Pull Request From 77e63ba56a2e366d659af1f3c8d290212c74b089 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 14:01:07 -0400 Subject: [PATCH 0158/4847] Some drawbacks --- docs/rfcs/004-issueish-list.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index 5a74a332da..db2569a20a 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -78,7 +78,8 @@ When the current branch is the default branch, e.g. `master`, a message is shown ## Drawbacks -None! +* "All pull requests" could easily be overwhelming on moderate to high traffic repositories. Stay tuned for more refinements on this front. +* Opening a pane item for each pull request click is heavyweight from a navigational standpoint. We may explore showing a popup as an intermediate state. ## Rationale and alternatives From df128ddd308a7a801657ec1f7fc88f429066d585 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 14:01:17 -0400 Subject: [PATCH 0159/4847] Questions are answered, yay --- docs/rfcs/004-issueish-list.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index db2569a20a..0db3dd7b99 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -99,8 +99,8 @@ With that said, the choices for the specific lists we show are a bit arbitrary. ### Before RFC merge: -- [ ] What else from the existing issueish pane should we keep? Comments, timeline events? -- [ ] Are there other pull request actions it would be useful to support? +- [x] What else from the existing issueish pane should we keep? Comments, timeline events? +- [x] Are there other pull request actions it would be useful to support? ### Out of scope: From 728ac17cc6b1d74dcba99d8017b088ca2b185a78 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 14:01:31 -0400 Subject: [PATCH 0160/4847] Move "merge"/"close"/"re-open" actions out of scope --- docs/rfcs/004-issueish-list.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/004-issueish-list.md index 0db3dd7b99..4a09559ba6 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/004-issueish-list.md @@ -106,6 +106,7 @@ With that said, the choices for the specific lists we show are a bit arbitrary. - [ ] How can we allow a user to customize the lists? - [ ] How can we notify a user about updated activity on a visible PR? +- [ ] Where should you be able to merge, close, or re-open pull requests? ## Implementation phases From f971b7dfc7f92521acf9ef49edae074e94c17180 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 14:02:00 -0400 Subject: [PATCH 0161/4847] Accept the RFC as 002 --- docs/rfcs/{004-issueish-list.md => 002-issueish-list.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename docs/rfcs/{004-issueish-list.md => 002-issueish-list.md} (99%) diff --git a/docs/rfcs/004-issueish-list.md b/docs/rfcs/002-issueish-list.md similarity index 99% rename from docs/rfcs/004-issueish-list.md rename to docs/rfcs/002-issueish-list.md index 4a09559ba6..a1be89d236 100644 --- a/docs/rfcs/004-issueish-list.md +++ b/docs/rfcs/002-issueish-list.md @@ -2,7 +2,7 @@ ## Status -Proposed +Accepted ## Summary From 88b35dbc2c8ad36a925af7b4391c33e8f42e7ddc Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Jun 2018 14:32:14 -0400 Subject: [PATCH 0162/4847] :fire: some dead code --- lib/multi-list-collection.js | 165 ---------- lib/multi-list.js | 314 ------------------ test/multi-list-collection.test.js | 154 --------- test/multi-list.test.js | 509 ----------------------------- 4 files changed, 1142 deletions(-) delete mode 100644 lib/multi-list-collection.js delete mode 100644 lib/multi-list.js delete mode 100644 test/multi-list-collection.test.js delete mode 100644 test/multi-list.test.js diff --git a/lib/multi-list-collection.js b/lib/multi-list-collection.js deleted file mode 100644 index 0b062eb65c..0000000000 --- a/lib/multi-list-collection.js +++ /dev/null @@ -1,165 +0,0 @@ -import MultiList from './multi-list'; - -export default class MultiListCollection { - constructor(lists, didChangeSelection) { - this.list = new MultiList(lists, (item, key) => { - didChangeSelection && didChangeSelection(item, key); - }); - const selectedKey = this.list.getActiveListKey(); - const selectedItem = this.list.getActiveItem(); - this.selectedKeys = new Set(selectedKey ? [selectedKey] : []); - this.selectedItems = new Set(selectedItem ? [selectedItem] : []); - } - - updateLists(lists, {suppressCallback} = {}) { - const listKeys = this.list.getListKeys(); - - let oldActiveListIndex, oldActiveListItemIndex; - for (let i = 0; i < listKeys.length; i++) { - const key = listKeys[i]; - if (this.selectedKeys.has(key)) { - oldActiveListIndex = i; - const items = this.getItemsForKey(key); - for (let j = 0; j < items.length; j++) { - const item = items[j]; - if (this.selectedItems.has(item)) { - oldActiveListItemIndex = j; - break; - } - } - break; - } - } - - this.list.updateLists(lists, {suppressCallback, oldActiveListIndex, oldActiveListItemIndex}); - this.updateSelections(); - } - - clearSelectedItems() { - this.selectedItems = new Set(); - } - - clearSelectedKeys() { - this.selectedKeys = new Set(); - } - - getSelectedItems() { - return this.selectedItems; - } - - getSelectedKeys() { - return this.selectedKeys; - } - - getItemsForKey(key) { - return this.list.getItemsForKey(key); - } - - getActiveListKey() { - return this.list.getActiveListKey(); - } - - getActiveItem() { - return this.list.getActiveItem(); - } - - selectNextList({wrap, addToExisting} = {}) { - this.list.activateNextList({wrap}); - this.updateSelections({addToExisting}); - } - - selectPreviousList({wrap, addToExisting} = {}) { - this.list.activatePreviousList({wrap}); - this.updateSelections({addToExisting}); - } - - selectNextItem({addToExisting, stopAtBounds} = {}) { - this.list.activateNextItem({stopAtBounds}); - this.updateSelections({addToExisting}); - } - - selectPreviousItem({addToExisting, stopAtBounds} = {}) { - this.list.activatePreviousItem({stopAtBounds}); - this.updateSelections({addToExisting}); - } - - updateSelections({addToExisting} = {}) { - const selectedKey = this.list.getActiveListKey(); - const selectedItem = this.list.getActiveItem(); - this.selectItems(selectedItem ? [selectedItem] : [], {addToExisting, suppressCallback: true}); - this.selectKeys(selectedKey ? [selectedKey] : [], {addToExisting, suppressCallback: true}); - } - - selectItems(items, {addToExisting, suppressCallback} = {}) { - if (!addToExisting) { this.clearSelectedItems(); } - items.forEach(item => this.selectedItems.add(item)); - this.list.activateItem(items[0], {suppressCallback}); - } - - selectKeys(keys, {addToExisting, suppressCallback} = {}) { - if (!addToExisting) { this.clearSelectedKeys(); } - keys.forEach(key => this.selectedKeys.add(key)); - this.list.activateListForKey(keys[0], {suppressCallback}); - } - - selectAllItemsForKey(key, addToExisting) { - this.selectKeys([key], {addToExisting}); - this.selectItems(this.list.getItemsForKey(key), {addToExisting}); - } - - selectFirstItemForKey(key, {addToExisting} = {}) { - this.selectKeys([key], {addToExisting}); - this.selectItems([this.list.getItemsForKey(key)[0]], {addToExisting}); - } - - selectItemsAndKeysInRange(endPoint1, endPoint2, addToExisting) { - if (!addToExisting) { - this.clearSelectedItems(); - this.clearSelectedKeys(); - } - const listKeys = this.list.getListKeys(); - const index1 = listKeys.indexOf(endPoint1.key); - const index2 = listKeys.indexOf(endPoint2.key); - - if (index1 < 0) { throw new Error(`key "${endPoint1.key}" not found`); } - if (index2 < 0) { throw new Error(`key "${endPoint2.key}" not found`); } - let startPoint, endPoint, startKeyIndex, endKeyIndex; - if (index1 < index2) { - startPoint = endPoint1; - endPoint = endPoint2; - startKeyIndex = index1; - endKeyIndex = index2; - } else { - startPoint = endPoint2; - endPoint = endPoint1; - startKeyIndex = index2; - endKeyIndex = index1; - } - const startItemIndex = this.list.getItemIndexForKey(startPoint.key, startPoint.item); - const endItemIndex = this.list.getItemIndexForKey(endPoint.key, endPoint.item); - if (startItemIndex < 0) { throw new Error(`item "${startPoint.item}" not found`); } - if (endItemIndex < 0) { throw new Error(`item "${endPoint.item}" not found`); } - - if (startKeyIndex === endKeyIndex) { - const items = this.list.getItemsForKey(listKeys[startKeyIndex]); - const indexes = [startItemIndex, endItemIndex].sort((a, b) => a - b); - this.selectKeys([startPoint.key], {addToExisting: true, suppressCallback: true}); - this.selectItems(items.slice(indexes[0], indexes[1] + 1), {addToExisting: true}); - return; - } - - for (let i = startKeyIndex; i <= endKeyIndex; i++) { - const key = listKeys[i]; - const items = this.list.getItemsForKey(key); - if (i === startKeyIndex) { - this.selectItems(items.slice(startItemIndex), {addToExisting: true}); - } else if (i === endKeyIndex) { - this.selectItems(items.slice(0, endItemIndex + 1), {addToExisting: true}); - } else { - this.selectItems(items, {addToExisting: true}); - } - } - const keys = listKeys.slice(startKeyIndex, endKeyIndex - startKeyIndex + 1); - this.selectKeys(keys, {addToExisting: true, suppressCallback: true}); - } -} diff --git a/lib/multi-list.js b/lib/multi-list.js deleted file mode 100644 index 967b6765b4..0000000000 --- a/lib/multi-list.js +++ /dev/null @@ -1,314 +0,0 @@ -import compareSets from 'compare-sets'; - -export default class MultiList { - constructor(lists, didChangeActiveItem) { - this.listInfoByKey = new Map(); - this.listOrderByKey = lists.map(list => { - this.listInfoByKey.set(list.key, { - items: list.items, - activeItem: list.items[0], - activeIndex: 0, - }); - return list.key; - }); - this.didChangeActiveItem = didChangeActiveItem; - this.activateListForKey(lists[0].key, {suppressCallback: true}); - } - - getListKeys() { - return this.listOrderByKey; - } - - getActiveListKey() { - return this.activeListKey; - } - - getItemsForKey(key) { - return this.listInfoByKey.get(key).items; - } - - getItemsInActiveList() { - return this.getItemsForKey(this.getActiveListKey()); - } - - getItemIndexForKey(key, item) { - const items = this.getItemsForKey(key); - return items.indexOf(item); - } - - getActiveItemForKey(key) { - if (key === undefined) { throw new RangeError(); } - return this.listInfoByKey.get(key).activeItem; - } - - getActiveItem() { - return this.listInfoByKey.get(this.getActiveListKey()).activeItem; - } - - activateListForKey(key, {suppressCallback} = {}) { - this.activeListKey = key; - - if (this.didChangeActiveItem && !suppressCallback) { - this.didChangeActiveItem(this.getActiveItem(), this.getActiveListKey()); - } - } - - activateItemAtIndexForKey(key, index, {suppressCallback} = {}) { - this.activateListForKey(key, {suppressCallback: true}); - const listInfo = this.listInfoByKey.get(key); - listInfo.activeIndex = index; - listInfo.activeItem = listInfo.items[index]; - - if (this.didChangeActiveItem && !suppressCallback) { - this.didChangeActiveItem(this.getActiveItem(), this.getActiveListKey()); - } - } - - activateItem(activeItem, {suppressCallback} = {}) { - for (const [key, listInfo] of this.listInfoByKey) { - for (let index = 0; index < listInfo.items.length; index++) { - const item = listInfo.items[index]; - if (activeItem === item) { - return this.activateItemAtIndexForKey(key, index, {suppressCallback}); - } - } - } - return null; - } - - activateNextList({wrap, activateFirst, suppressCallback} = {}) { - const listCount = this.listOrderByKey.length; - let index = this.listOrderByKey.indexOf(this.getActiveListKey()) + 1; - if (wrap && index >= listCount) { index = 0; } - let listsLeft = listCount - 1; - while (index < listCount && listsLeft && this.getItemsForKey(this.listOrderByKey[index]).length === 0) { - index++; - if (wrap && index >= listCount) { index = 0; } - listsLeft--; - } - if (index < listCount) { - const key = this.listOrderByKey[index]; - activateFirst ? - this.activateItemAtIndexForKey(key, 0, {suppressCallback}) : - this.activateListForKey(key, {suppressCallback}); - } - } - - activatePreviousList({wrap, activateLast, suppressCallback} = {}) { - const listCount = this.listOrderByKey.length; - let index = this.listOrderByKey.indexOf(this.getActiveListKey()) - 1; - if (wrap && index < 0) { index = listCount - 1; } - let listsLeft = index; - while (index >= 0 && listsLeft && this.getItemsForKey(this.listOrderByKey[index]).length === 0) { - index--; - if (wrap && index < 0) { index = listCount - 1; } - listsLeft--; - } - if (index >= 0) { - const key = this.listOrderByKey[index]; - if (activateLast) { - const lastItemIndex = this.getItemsForKey(this.listOrderByKey[index]).length - 1; - this.activateItemAtIndexForKey(key, lastItemIndex, {suppressCallback}); - } else { - this.activateListForKey(key, {suppressCallback}); - } - } - } - - activateNextItem({wrap, stopAtBounds} = {}) { - const key = this.getActiveListKey(); - const listInfo = this.listInfoByKey.get(key); - const newItemIndex = listInfo.activeIndex + 1; - if (newItemIndex < listInfo.items.length) { - this.activateItemAtIndexForKey(key, newItemIndex); - } else { - if (!stopAtBounds) { this.activateNextList({activateFirst: true, wrap}); } - } - } - - activatePreviousItem({wrap, stopAtBounds} = {}) { - const key = this.getActiveListKey(); - const listInfo = this.listInfoByKey.get(key); - const newItemIndex = listInfo.activeIndex - 1; - if (newItemIndex >= 0) { - this.activateItemAtIndexForKey(key, newItemIndex); - } else { - if (!stopAtBounds) { this.activatePreviousList({activateLast: true, wrap}); } - } - } - - getItemsAndKeysInRange(endPoint1, endPoint2) { - const index1 = this.listOrderByKey.indexOf(endPoint1.key); - const index2 = this.listOrderByKey.indexOf(endPoint2.key); - - if (index1 < 0) { throw new Error(`key "${endPoint1.key}" not found`); } - if (index2 < 0) { throw new Error(`key "${endPoint2.key}" not found`); } - let startPoint, endPoint, startKeyIndex, endKeyIndex; - if (index1 < index2) { - startPoint = endPoint1; - endPoint = endPoint2; - startKeyIndex = index1; - endKeyIndex = index2; - } else { - startPoint = endPoint2; - endPoint = endPoint1; - startKeyIndex = index2; - endKeyIndex = index1; - } - const startItemIndex = this.getItemIndexForKey(startPoint.key, startPoint.item); - const endItemIndex = this.getItemIndexForKey(endPoint.key, endPoint.item); - if (startItemIndex < 0) { throw new Error(`item "${startPoint.item}" not found`); } - if (endItemIndex < 0) { throw new Error(`item "${endPoint.item}" not found`); } - - if (startKeyIndex === endKeyIndex) { - const items = this.getItemsForKey(this.listOrderByKey[startKeyIndex]); - const indexes = [startItemIndex, endItemIndex].sort(); - return { - items: items.slice(indexes[0], indexes[1] + 1), - keys: [startPoint.key], - }; - } - - let itemsInRange; - for (let i = startKeyIndex; i <= endKeyIndex; i++) { - const items = this.getItemsForKey(this.listOrderByKey[i]); - if (i === startKeyIndex) { - itemsInRange = items.slice(startItemIndex); - } else if (i === endKeyIndex) { - itemsInRange = itemsInRange.concat(items.slice(0, endItemIndex + 1)); - } else { - itemsInRange = itemsInRange.concat(items); - } - } - return { - items: itemsInRange, - keys: this.listOrderByKey.slice(startKeyIndex, endKeyIndex + 1), - }; - } - - updateLists(newLists, {suppressCallback, oldActiveListIndex, oldActiveListItemIndex} = {}) { - const oldActiveItem = this.getActiveItem(); - const oldActiveListKey = this.getActiveListKey(); - oldActiveListIndex = oldActiveListIndex || this.listOrderByKey.indexOf(oldActiveListKey); - - const newListInfo = this.getNewListInfoAndOrder(newLists, {oldActiveListIndex, oldActiveListItemIndex}); - const {newListOrderByKey, newListInfoByKey, selectNext} = newListInfo; - this.listInfoByKey = newListInfoByKey; - this.listOrderByKey = newListOrderByKey; - - if (!newListOrderByKey.includes(oldActiveListKey)) { - this.activateItemBasedOnIndex(oldActiveListIndex); - } - - if (this.getItemsInActiveList().length === 0 || selectNext) { - this.activateNextList({suppressCallback: true, activateFirst: true}); - if (this.getItemsInActiveList().length === 0) { - this.activatePreviousList({suppressCallback: true, activateLast: true}); - } - } - - if (this.getActiveItem() !== oldActiveItem && this.didChangeActiveItem && !suppressCallback) { - this.didChangeActiveItem(this.getActiveItem(), this.getActiveListKey()); - } - } - - getNewListInfoAndOrder(newLists, {oldActiveListIndex, oldActiveListItemIndex}) { - const {retained} = compareSets(new Set(this.listOrderByKey), new Set(newLists.map(list => list.key))); - if (retained.size > 0) { - return this.getInfoBasedOnOldActiveItem(newLists); - } else { - return this.getInfoBasedOnOldActiveIndex(newLists, {oldActiveListIndex, oldActiveListItemIndex}); - } - } - - getInfoBasedOnOldActiveIndex(newLists, {oldActiveListIndex, oldActiveListItemIndex}) { - let selectNext; - const newListInfoByKey = new Map(); - const newListOrderByKey = newLists.map((list, listIndex) => { - const newListItems = list.items; - let newInfo; - if (oldActiveListItemIndex !== undefined && listIndex === oldActiveListIndex) { - const items = list.items; - const item = items[oldActiveListItemIndex]; - if (item !== undefined) { - newInfo = { - activeItem: item, - activeIndex: oldActiveListItemIndex, - }; - } else { - selectNext = true; - newInfo = { - activeItem: items[items.length - 1], - activeIndex: Math.max(items.length - 1, 0), - }; - } - } else { - newInfo = { - activeItem: newListItems[0], - activeIndex: 0, - }; - } - newInfo.items = newListItems; - newListInfoByKey.set(list.key, newInfo); - return list.key; - }); - - return {newListOrderByKey, newListInfoByKey, selectNext}; - } - - getInfoBasedOnOldActiveItem(newLists) { - const newListInfoByKey = new Map(); - const newListOrderByKey = newLists.map(list => { - const oldInfo = this.listInfoByKey.get(list.key); - const key = list.key; - const newListItems = list.items; - let newInfo; - if (oldInfo && newListItems.length > 0) { - const activeItemIndex = newListItems.indexOf(oldInfo.activeItem); - if (activeItemIndex > -1) { - newInfo = { - activeItem: oldInfo.activeItem, - activeIndex: activeItemIndex, - }; - } else if (newListItems[oldInfo.activeIndex] !== undefined) { - newInfo = { - activeItem: newListItems[oldInfo.activeIndex], - activeIndex: oldInfo.activeIndex, - }; - } else { - newInfo = { - activeItem: newListItems[newListItems.length - 1], - activeIndex: newListItems.length - 1, - }; - } - } else { - newInfo = { - activeItem: newListItems[0], - activeIndex: 0, - }; - } - newInfo.items = newListItems; - - newListInfoByKey.set(key, newInfo); - return key; - }); - - return {newListOrderByKey, newListInfoByKey}; - } - - activateItemBasedOnIndex(oldActiveListIndex) { - let newActiveListKey = this.listOrderByKey[oldActiveListIndex]; - if (newActiveListKey) { - this.activateListForKey(newActiveListKey, {suppressCallback: true}); - } else { - newActiveListKey = this.listOrderByKey[this.listOrderByKey.length - 1]; - const items = this.getItemsForKey(newActiveListKey); - this.activateItemAtIndexForKey(newActiveListKey, items.length - 1, {suppressCallback: true}); - } - } - - toObject() { - const {listOrderByKey, activeListKey} = this; - return {listOrderByKey, activeListKey}; - } -} diff --git a/test/multi-list-collection.test.js b/test/multi-list-collection.test.js deleted file mode 100644 index 968be1a43d..0000000000 --- a/test/multi-list-collection.test.js +++ /dev/null @@ -1,154 +0,0 @@ -import MultiListCollection from '../lib/multi-list-collection'; - -describe('MultiListCollection', function() { - describe('selectItemsAndKeysInRange(endPoint1, endPoint2)', function() { - it('takes endpoints ({key, item}) and returns an array of items between those points', function() { - const mlc = new MultiListCollection([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - {key: 'list3', items: ['f', 'g', 'h']}, - ]); - - mlc.selectItemsAndKeysInRange({key: 'list1', item: 'b'}, {key: 'list1', item: 'c'}); - assert.deepEqual([...mlc.getSelectedItems()], ['b', 'c']); - assert.deepEqual([...mlc.getSelectedKeys()], ['list1']); - - // endpoints can be specified in any order - mlc.selectItemsAndKeysInRange({key: 'list1', item: 'c'}, {key: 'list1', item: 'b'}); - assert.deepEqual([...mlc.getSelectedItems()], ['b', 'c']); - assert.deepEqual([...mlc.getSelectedKeys()], ['list1']); - - // endpoints can be in different lists - mlc.selectItemsAndKeysInRange({key: 'list1', item: 'c'}, {key: 'list3', item: 'g'}); - assert.deepEqual([...mlc.getSelectedItems()], ['c', 'd', 'e', 'f', 'g']); - assert.deepEqual([...mlc.getSelectedKeys()], ['list1', 'list2', 'list3']); - - mlc.selectItemsAndKeysInRange({key: 'list3', item: 'g'}, {key: 'list1', item: 'c'}); - assert.deepEqual([...mlc.getSelectedItems()], ['c', 'd', 'e', 'f', 'g']); - assert.deepEqual([...mlc.getSelectedKeys()], ['list1', 'list2', 'list3']); - - // endpoints can be the same - mlc.selectItemsAndKeysInRange({key: 'list1', item: 'c'}, {key: 'list1', item: 'c'}); - assert.deepEqual([...mlc.getSelectedItems()], ['c']); - assert.deepEqual([...mlc.getSelectedKeys()], ['list1']); - }); - - it('sets the first key and first item as active when multiple are selected', function() { - const mlc = new MultiListCollection([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - {key: 'list3', items: ['f', 'g', 'h']}, - ]); - - mlc.selectItemsAndKeysInRange({key: 'list1', item: 'b'}, {key: 'list3', item: 'g'}); - assert.equal(mlc.getActiveListKey(), 'list1'); - assert.equal(mlc.getActiveItem(), 'b'); - }); - - it('sorts endpoint item indexes correctly based on numerical values and not strings', function() { - // this addresses a bug where selecting across the 10th item index would return an empty set - // because the indices would be stringified by the sort function ("12" < "7") - const mlc = new MultiListCollection([ - {key: 'list1', items: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]}, - ]); - - mlc.selectItemsAndKeysInRange({key: 'list1', item: 7}, {key: 'list1', item: 12}); - assert.deepEqual([...mlc.getSelectedItems()], [7, 8, 9, 10, 11, 12]); - }); - - it('throws error when keys or items aren\'t found', function() { - const mlc = new MultiListCollection([ - {key: 'list1', items: ['a', 'b', 'c']}, - ]); - - assert.throws(() => { - mlc.selectItemsAndKeysInRange({key: 'non-existent-key', item: 'b'}, {key: 'list1', item: 'c'}); - }, 'key "non-existent-key" not found'); - - assert.throws(() => { - mlc.selectItemsAndKeysInRange({key: 'list1', item: 'b'}, {key: 'non-existent-key', item: 'c'}); - }, 'key "non-existent-key" not found'); - - assert.throws(() => { - mlc.selectItemsAndKeysInRange({key: 'list1', item: 'x'}, {key: 'list1', item: 'c'}); - }, 'item "x" not found'); - - assert.throws(() => { - mlc.selectItemsAndKeysInRange({key: 'list1', item: 'b'}, {key: 'list1', item: 'x'}); - }, 'item "x" not found'); - }); - }); - - describe('updateLists', function() { - describe('when the active list key and item is still present after update', function() { - it('maintains active item regardless of positional changes', function() { - const mlc = new MultiListCollection([ - {key: 'list1', items: ['a']}, - ]); - - assert.equal(mlc.getActiveItem(), 'a'); - - mlc.updateLists([ - {key: 'list1', items: ['b', 'a']}, - ]); - assert.equal(mlc.getActiveItem(), 'a'); - - mlc.updateLists([ - {key: 'list1', items: ['a']}, - ]); - assert.equal(mlc.getActiveItem(), 'a'); - - mlc.updateLists([ - {key: 'list2', items: ['c']}, - {key: 'list1', items: ['a']}, - ]); - assert.equal(mlc.getActiveItem(), 'a'); - - mlc.updateLists([ - {key: 'list1', items: ['a']}, - ]); - assert.equal(mlc.getActiveItem(), 'a'); - }); - }); - - describe('when the active list key and item is NOT present after update', function() { - it('updates selection based on the location of the previously active item and key', function() { - const mlc = new MultiListCollection([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - ]); - - mlc.selectItems(['b']); - assert.equal(mlc.getActiveItem(), 'b'); - - mlc.updateLists([ - {key: 'list3', items: ['a', 'c']}, - {key: 'list4', items: ['d', 'e']}, - ]); - assert.equal(mlc.getActiveItem(), 'c'); - - mlc.updateLists([ - {key: 'list5', items: ['a']}, - {key: 'list6', items: ['d', 'e']}, - {key: 'list7', items: ['f', 'g', 'h']}, - ]); - assert.equal(mlc.getActiveItem(), 'd'); - - mlc.selectItemsAndKeysInRange({key: 'list6', item: 'e'}, {key: 'list7', item: 'g'}); - assert.equal(mlc.getActiveItem(), 'e'); - mlc.updateLists([ - {key: 'list8', items: ['a']}, - {key: 'list9', items: ['d', 'h']}, - ]); - assert.equal(mlc.getActiveItem(), 'h'); - - mlc.selectItemsAndKeysInRange({key: 'list9', item: 'd'}, {key: 'list9', item: 'h'}); - assert.equal(mlc.getActiveItem(), 'd'); - mlc.updateLists([ - {key: 'list10', items: ['a', 'i', 'j']}, - ]); - assert.equal(mlc.getActiveItem(), 'j'); - }); - }); - }); -}); diff --git a/test/multi-list.test.js b/test/multi-list.test.js deleted file mode 100644 index 3e314f5ce5..0000000000 --- a/test/multi-list.test.js +++ /dev/null @@ -1,509 +0,0 @@ -import MultiList from '../lib/multi-list'; - -describe('MultiList', function() { - describe('constructing a MultiList instance', function() { - it('activates the first item from each list, and marks the first list as active', function() { - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - {key: 'list3', items: ['f', 'g', 'h']}, - ]); - - assert.equal(ml.getActiveListKey(), 'list1'); - assert.equal(ml.getActiveItem(), 'a'); - assert.equal(ml.getActiveItemForKey('list2'), 'd'); - assert.equal(ml.getActiveItemForKey('list3'), 'f'); - }); - }); - - describe('activateListForKey(key)', function() { - it('activates the list at the given index and calls the provided changed-activateion callback', function() { - const didChangeActiveItem = sinon.spy(); - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - {key: 'list3', items: ['f', 'g', 'h']}, - ], didChangeActiveItem); - - ml.activateListForKey('list2'); - assert.equal(ml.getActiveListKey(), 'list2'); - assert.equal(ml.getActiveItem(), 'd'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['d', 'list2']); - - didChangeActiveItem.resetHistory(); - ml.activateListForKey('list3'); - assert.equal(ml.getActiveListKey(), 'list3'); - assert.equal(ml.getActiveItem(), 'f'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['f', 'list3']); - }); - }); - - describe('activateItemAtIndexForKey(key, itemIndex)', function() { - it('activates the item, calls the provided changed-activateion callback, and remembers which item is active for each list', function() { - const didChangeActiveItem = sinon.spy(); - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - {key: 'list3', items: ['f', 'g', 'h']}, - ], didChangeActiveItem); - - ml.activateItemAtIndexForKey('list1', 2); - assert.equal(ml.getActiveItem(), 'c'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['c', 'list1']); - - didChangeActiveItem.resetHistory(); - ml.activateItemAtIndexForKey('list2', 1); - assert.equal(ml.getActiveItem(), 'e'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['e', 'list2']); - - ml.activateItemAtIndexForKey('list3', 2); - assert.equal(ml.getActiveItem(), 'h'); - - ml.activateListForKey('list1'); - assert.equal(ml.getActiveItem(), 'c'); - - ml.activateListForKey('list2'); - assert.equal(ml.getActiveItem(), 'e'); - - ml.activateListForKey('list3'); - assert.equal(ml.getActiveItem(), 'h'); - }); - }); - - describe('activateItem(item)', function() { - it('activates the provided item and calls the provided changed-activateion callback', function() { - const didChangeActiveItem = sinon.spy(); - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - {key: 'list3', items: ['f', 'g', 'h']}, - ], didChangeActiveItem); - - ml.activateItem('b'); - assert.equal(ml.getActiveItem(), 'b'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['b', 'list1']); - - didChangeActiveItem.resetHistory(); - ml.activateItem('e'); - assert.equal(ml.getActiveItem(), 'e'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['e', 'list2']); - }); - }); - - describe('activateNextList({wrap, activateFirst}) and activatePreviousList({wrap, activateLast})', function() { - it('activates the next/previous list', function() { - const didChangeActiveItem = sinon.spy(); - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - {key: 'list3', items: ['f', 'g', 'h']}, - ], didChangeActiveItem); - assert.equal(ml.getActiveListKey(), 'list1'); - - ml.activateNextList(); - assert.equal(ml.getActiveListKey(), 'list2'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['d', 'list2']); - - didChangeActiveItem.resetHistory(); - ml.activateNextList(); - assert.equal(ml.getActiveListKey(), 'list3'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['f', 'list3']); - - ml.activatePreviousList(); - assert.equal(ml.getActiveListKey(), 'list2'); - - ml.activatePreviousList(); - assert.equal(ml.getActiveListKey(), 'list1'); - }); - - it('wraps across beginning and end lists for wrap option is truthy, otherwise stops at beginning/end lists', function() { - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - {key: 'list3', items: ['f', 'g', 'h']}, - ]); - assert.equal(ml.getActiveListKey(), 'list1'); - - ml.activatePreviousList({wrap: true}); - assert.equal(ml.getActiveListKey(), 'list3'); - - ml.activateNextList({wrap: true}); - assert.equal(ml.getActiveListKey(), 'list1'); - - ml.activatePreviousList(); - assert.equal(ml.getActiveListKey(), 'list1'); - - ml.activateListForKey('list3'); - assert.equal(ml.getActiveListKey(), 'list3'); - - ml.activateNextList(); - assert.equal(ml.getActiveListKey(), 'list3'); - }); - - it('activates first/last item in list if activateFirst/activateLast options are set to true', function() { - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - {key: 'list3', items: ['f', 'g', 'h']}, - ]); - ml.activateListForKey('list2'); - - ml.activatePreviousList({activateLast: true}); - assert.equal(ml.getActiveItem(), 'c'); - - ml.activateItemAtIndexForKey('list2', 1); - assert.equal(ml.getActiveItem(), 'e'); - ml.activateNextList({activateFirst: true}); - assert.equal(ml.getActiveItem(), 'f'); - }); - }); - - describe('activateNextItem({wrap, stopAtBounds}) and activatePreviousItem({wrap, stopAtBounds})', function() { - it('activates the next/previous item in the currently active list', function() { - const didChangeActiveItem = sinon.spy(); - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - ], didChangeActiveItem); - assert.equal(ml.getActiveItem(), 'a'); - - ml.activateNextItem(); - assert.equal(ml.getActiveItem(), 'b'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['b', 'list1']); - - didChangeActiveItem.resetHistory(); - ml.activateNextItem(); - assert.equal(ml.getActiveItem(), 'c'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['c', 'list1']); - - ml.activatePreviousItem(); - assert.equal(ml.getActiveItem(), 'b'); - - ml.activatePreviousItem(); - assert.equal(ml.getActiveItem(), 'a'); - }); - - it('activates the next/previous list if one exists when activateing past the last/first item of a list, unless stopAtBounds is true', function() { - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b']}, - {key: 'list2', items: ['c']}, - ]); - - assert.equal(ml.getActiveItem(), 'a'); - assert.equal(ml.getActiveListKey(), 'list1'); - ml.activateNextItem(); - assert.equal(ml.getActiveItem(), 'b'); - assert.equal(ml.getActiveListKey(), 'list1'); - ml.activateNextItem({stopAtBounds: true}); - assert.equal(ml.getActiveItem(), 'b'); - assert.equal(ml.getActiveListKey(), 'list1'); - ml.activateNextItem(); - assert.equal(ml.getActiveItem(), 'c'); - assert.equal(ml.getActiveListKey(), 'list2'); - ml.activateNextItem(); - assert.equal(ml.getActiveItem(), 'c'); - assert.equal(ml.getActiveListKey(), 'list2'); - ml.activateNextItem({stopAtBounds: true}); - assert.equal(ml.getActiveItem(), 'c'); - assert.equal(ml.getActiveListKey(), 'list2'); - ml.activatePreviousItem(); - assert.equal(ml.getActiveItem(), 'b'); - assert.equal(ml.getActiveListKey(), 'list1'); - ml.activatePreviousItem(); - assert.equal(ml.getActiveItem(), 'a'); - assert.equal(ml.getActiveListKey(), 'list1'); - ml.activatePreviousItem(); - assert.equal(ml.getActiveItem(), 'a'); - assert.equal(ml.getActiveListKey(), 'list1'); - }); - - it('wraps across beginning and end lists if the wrap option is set to true', function() { - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - {key: 'list3', items: ['f', 'g', 'h']}, - ]); - assert.equal(ml.getActiveItem(), 'a'); - - ml.activatePreviousItem({wrap: true}); - assert.equal(ml.getActiveItem(), 'h'); - - ml.activateNextItem({wrap: true}); - assert.equal(ml.getActiveItem(), 'a'); - }); - }); - - describe('updateLists(lists, {suppressCallback, oldActiveListIndex, oldActiveListItemIndex})', function() { - describe('when referential identity of list keys is NOT maintained', function() { - it('updates selected item based on options passed in', function() { - function getRandomKey() { - return performance.now() + Math.random() * 100000; - } - - let options; - - const ml = new MultiList([ - {key: getRandomKey(), items: ['a', 'b', 'c']}, - {key: getRandomKey(), items: ['d', 'e']}, - {key: getRandomKey(), items: ['f', 'g', 'h']}, - ]); - - ml.activateItem('b'); - options = {oldActiveListIndex: 0, oldActiveListItemIndex: 1}; - - ml.updateLists([ - {key: getRandomKey(), items: ['a', 'c']}, - {key: getRandomKey(), items: ['d', 'e']}, - {key: getRandomKey(), items: ['f', 'g', 'h']}, - ], options); - - assert.equal(ml.getActiveItem(), 'c'); - options = {oldActiveListIndex: 0, oldActiveListItemIndex: 1}; - - ml.updateLists([ - {key: getRandomKey(), items: ['a']}, - {key: getRandomKey(), items: ['d', 'e']}, - {key: getRandomKey(), items: ['f', 'g', 'h']}, - ], options); - - assert.equal(ml.getActiveItem(), 'd'); - options = {oldActiveListIndex: 1, oldActiveListItemIndex: 0}; - - ml.updateLists([ - {key: getRandomKey(), items: ['a']}, - {key: getRandomKey(), items: ['f', 'g', 'h']}, - ], options); - - assert.equal(ml.getActiveItem(), 'f'); - options = {oldActiveListIndex: 1, oldActiveListItemIndex: 1}; - - ml.updateLists([ - {key: getRandomKey(), items: ['a']}, - ], options); - - assert.equal(ml.getActiveItem(), 'a'); - options = {oldActiveListIndex: 0, oldActiveListItemIndex: 0}; - - ml.updateLists([ - {key: getRandomKey(), items: []}, - {key: getRandomKey(), items: ['j']}, - ], options); - - assert.equal(ml.getActiveItem(), 'j'); - }); - }); - - describe('when referential identity of list keys is maintained', function() { - it('adds and removes lists based on list keys and updates order accordingly, remembering the active list', function() { - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - ]); - assert.deepEqual(ml.getListKeys(), ['list1', 'list2']); - assert.equal(ml.getActiveListKey(), 'list1'); - - ml.updateLists([ - {key: 'list3', items: ['f', 'g', 'h']}, - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - ]); - assert.deepEqual(ml.getListKeys(), ['list3', 'list1', 'list2']); - assert.equal(ml.getActiveListKey(), 'list1'); - - ml.updateLists([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list3', items: ['f', 'g', 'h']}, - ]); - assert.deepEqual(ml.getListKeys(), ['list1', 'list3']); - assert.equal(ml.getActiveListKey(), 'list1'); - - ml.updateLists([ - {key: 'list3', items: ['f', 'g', 'h']}, - {key: 'list2', items: ['d', 'e']}, - {key: 'list1', items: ['a', 'b', 'c']}, - ]); - assert.deepEqual(ml.getListKeys(), ['list3', 'list2', 'list1']); - assert.equal(ml.getActiveListKey(), 'list1'); - }); - - describe('when active list is removed', function() { - describe('when there is a new list in its place', function() { - it('activates the new list in its place', function() { - const didChangeActiveItem = sinon.spy(); - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - ], didChangeActiveItem); - - assert.equal(ml.getActiveListKey(), 'list1'); - - ml.updateLists([ - {key: 'list2', items: ['d', 'e']}, - ]); - assert.equal(ml.getActiveListKey(), 'list2'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['d', 'list2']); - }); - }); - - describe('when there is no list in its place', function() { - it('activates the last item in the last list', function() { - const didChangeActiveItem = sinon.spy(); - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - ], didChangeActiveItem); - - ml.activateListForKey('list2'); - - didChangeActiveItem.resetHistory(); - ml.updateLists([ - {key: 'list1', items: ['a', 'b', 'c']}, - ]); - assert.equal(ml.getActiveListKey(), 'list1'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['c', 'list1']); - }); - }); - }); - - it('maintains the active items for each list, even if location has changed in list', function() { - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - {key: 'list2', items: ['d', 'e']}, - ]); - - ml.activateItemAtIndexForKey('list1', 1); - assert.equal(ml.getActiveItem(), 'b'); - ml.activateItemAtIndexForKey('list2', 1); - assert.equal(ml.getActiveItem(), 'e'); - - ml.updateLists([ - {key: 'list1', items: ['b', 'c']}, - {key: 'list2', items: ['a', 'd', 'e']}, - ]); - - assert.equal(ml.getActiveListKey(), 'list2'); - - ml.activateListForKey('list1'); - assert.equal(ml.getActiveItem(), 'b'); - - ml.activateListForKey('list2'); - assert.equal(ml.getActiveItem(), 'e'); - }); - - describe('when list item is no longer in the list upon update', function() { - describe('when there is a new item in its place', function() { - it('keeps the same active item index and shows the new item as active', function() { - const didChangeActiveItem = sinon.spy(); - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - ], didChangeActiveItem); - - ml.activateItemAtIndexForKey('list1', 0); - assert.equal(ml.getActiveItem(), 'a'); - - didChangeActiveItem.resetHistory(); - ml.updateLists([ - {key: 'list1', items: ['b', 'c']}, - ]); - assert.equal(ml.getActiveItem(), 'b'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['b', 'list1']); - - didChangeActiveItem.resetHistory(); - ml.updateLists([ - {key: 'list1', items: ['b', 'c']}, - ]); - assert.equal(ml.getActiveItem(), 'b'); - assert.equal(didChangeActiveItem.callCount, 0); - }); - }); - - describe('when there is no item in its place, but there is still an item in the list', function() { - it('activates the last item in the list', function() { - const didChangeActiveItem = sinon.spy(); - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b', 'c']}, - ], didChangeActiveItem); - - ml.activateItemAtIndexForKey('list1', 2); - assert.equal(ml.getActiveItem(), 'c'); - - didChangeActiveItem.resetHistory(); - ml.updateLists([ - {key: 'list1', items: ['a', 'b']}, - ]); - assert.equal(ml.getActiveItem(), 'b'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['b', 'list1']); - - didChangeActiveItem.resetHistory(); - ml.updateLists([ - {key: 'list1', items: ['a']}, - ]); - assert.equal(ml.getActiveItem(), 'a'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['a', 'list1']); - }); - }); - - describe('when there are no more items in the list', function() { - describe('when there is a non-empty list following the active list', function() { - it('activates the first item in the following list', function() { - const didChangeActiveItem = sinon.spy(); - const ml = new MultiList([ - {key: 'list1', items: ['a']}, - {key: 'list2', items: ['b', 'c']}, - ], didChangeActiveItem); - - ml.activateItemAtIndexForKey('list1', 0); - assert.equal(ml.getActiveItem(), 'a'); - - didChangeActiveItem.resetHistory(); - ml.updateLists([ - {key: 'list1', items: []}, - {key: 'list2', items: ['b', 'c']}, - ]); - assert.equal(ml.getActiveItem(), 'b'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['b', 'list2']); - }); - }); - - describe('when the following list is empty, but the preceeding list is non-empty', function() { - it('activates the last item in the preceeding list', function() { - const didChangeActiveItem = sinon.spy(); - const ml = new MultiList([ - {key: 'list1', items: ['a', 'b']}, - {key: 'list2', items: ['c']}, - ], didChangeActiveItem); - - ml.activateItemAtIndexForKey('list2', 0); - assert.equal(ml.getActiveItem(), 'c'); - - didChangeActiveItem.resetHistory(); - ml.updateLists([ - {key: 'list1', items: ['a', 'b']}, - {key: 'list2', items: []}, - ]); - assert.equal(ml.getActiveItem(), 'b'); - assert.equal(ml.getActiveItem(), 'b'); - assert.equal(didChangeActiveItem.callCount, 1); - assert.deepEqual(didChangeActiveItem.args[0], ['b', 'list1']); - }); - }); - }); - }); - }); - }); -}); From 0b46fe15e9d96c8e1feb6ccd2f06f555270a2a86 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 12 Jun 2018 10:20:16 -0400 Subject: [PATCH 0163/4847] Accordion component --- lib/views/accordion.js | 85 +++++++++++++++++++++++++++ test/views/accordion.test.js | 109 +++++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 lib/views/accordion.js create mode 100644 test/views/accordion.test.js diff --git a/lib/views/accordion.js b/lib/views/accordion.js new file mode 100644 index 0000000000..612b8ee1ec --- /dev/null +++ b/lib/views/accordion.js @@ -0,0 +1,85 @@ +import React, {Fragment} from 'react'; +import PropTypes from 'prop-types'; + +import {autobind} from '../helpers'; + +export default class Accordion extends React.Component { + static propTypes = { + leftTitle: PropTypes.string.isRequired, + rightTitle: PropTypes.string, + results: PropTypes.arrayOf(PropTypes.any).isRequired, + isLoading: PropTypes.bool.isRequired, + loadingComponent: PropTypes.func, + emptyComponent: PropTypes.func, + children: PropTypes.func.isRequired, + }; + + static defaultProps = { + loadingComponent: () => null, + emptyComponent: () => null, + }; + + constructor(props) { + super(props); + autobind(this, 'toggle'); + + this.state = { + expanded: true, + }; + } + + render() { + return ( +
+ + {this.renderHeader()} + +
+ {this.renderContent()} +
+
+ ); + } + + renderHeader() { + return ( + + + {this.props.leftTitle} + + {this.props.rightTitle && ( + + {this.props.rightTitle} + + )} + + ); + } + + renderContent() { + if (this.props.isLoading) { + const Loading = this.props.loadingComponent; + return ; + } + + if (this.props.results.length === 0) { + const Empty = this.props.emptyComponent; + return ; + } + + return ( +
    + {this.props.results.map((item, index) => { + const key = item.key !== undefined ? item.key : index; + return
  • {this.props.children(item)}
  • ; + })} +
+ ); + } + + toggle() { + return new Promise(resolve => { + this.setState(prevState => ({expanded: !prevState.expanded}), resolve); + }); + } +} diff --git a/test/views/accordion.test.js b/test/views/accordion.test.js new file mode 100644 index 0000000000..75022296a8 --- /dev/null +++ b/test/views/accordion.test.js @@ -0,0 +1,109 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import Accordion from '../../lib/views/accordion'; + +class CustomChild extends React.Component { + render() { + return
; + } +} + +class WrongChild extends React.Component { + render() { + return
; + } +} + +describe('Accordion', function() { + function buildApp(overrideProps = {}) { + return ( + null} + {...overrideProps} + /> + ); + } + + it('renders a left title', function() { + const wrapper = shallow(buildApp({leftTitle: 'left'})); + assert.strictEqual( + wrapper.find('summary.github-Accordion-header span.github-Accordion--leftTitle').text(), + 'left', + ); + }); + + it('renders a right title', function() { + const wrapper = shallow(buildApp({rightTitle: 'right'})); + assert.strictEqual( + wrapper.find('summary.github-Accordion-header span.github-Accordion--rightTitle').text(), + 'right', + ); + }); + + it('is initially expanded', function() { + const wrapper = shallow(buildApp()); + assert.isTrue(wrapper.find('details.github-Accordion[open]').exists()); + }); + + it('toggles expansion state on a header click', function() { + const wrapper = shallow(buildApp()); + wrapper.find('.github-Accordion-header').simulate('click'); + assert.isFalse(wrapper.find('details.github-Accordion[open="false"]').exists()); + }); + + describe('while loading', function() { + it('defaults to rendering no children', function() { + const wrapper = shallow(buildApp({isLoading: true, children: WrongChild})); + assert.lengthOf(wrapper.find('CustomChild'), 0); + }); + + it('renders a custom child component', function() { + const wrapper = shallow(buildApp({ + isLoading: true, + loadingComponent: CustomChild, + emptyComponent: WrongChild, + })); + assert.lengthOf(wrapper.find('CustomChild'), 1); + assert.lengthOf(wrapper.find('WrongChild'), 0); + }); + }); + + describe('when empty', function() { + it('defaults to rendering no children', function() { + const wrapper = shallow(buildApp({results: [], children: WrongChild})); + assert.lengthOf(wrapper.find('WrongChild'), 0); + }); + + it('renders a custom child component', function() { + const wrapper = shallow(buildApp({ + results: [], + loadingComponent: WrongChild, + emptyComponent: CustomChild, + })); + assert.lengthOf(wrapper.find('CustomChild'), 1); + assert.lengthOf(wrapper.find('WrongChild'), 0); + }); + }); + + describe('with results', function() { + it('renders its child render prop with each', function() { + const results = [1, 2, 3]; + const wrapper = shallow(buildApp({ + results, + loadingComponent: WrongChild, + emptyComponent: WrongChild, + children: each => , + })); + + assert.lengthOf(wrapper.find('WrongChild'), 0); + assert.lengthOf(wrapper.find('CustomChild'), 3); + for (const i of results) { + assert.isTrue(wrapper.find('CustomChild').someWhere(c => c.prop('item') === i)); + } + }); + }); +}); From af6a3719e67c69cb7bc265a318f58a5dba743885 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 12 Jun 2018 14:03:51 -0400 Subject: [PATCH 0164/4847] Search Issueishes with an IssueishListContainer --- .../issueishListContainerQuery.graphql.js | 267 ++++++++++++++++++ lib/containers/issueish-list-container.js | 68 +++++ .../issueishListController_results.graphql.js | 147 ++++++++++ lib/controllers/issueish-list-controller.js | 32 +++ lib/models/search.js | 10 + lib/prop-types.js | 4 + .../issueish-list-container.test.js | 102 +++++++ 7 files changed, 630 insertions(+) create mode 100644 lib/containers/__generated__/issueishListContainerQuery.graphql.js create mode 100644 lib/containers/issueish-list-container.js create mode 100644 lib/controllers/__generated__/issueishListController_results.graphql.js create mode 100644 lib/controllers/issueish-list-controller.js create mode 100644 lib/models/search.js create mode 100644 test/containers/issueish-list-container.test.js diff --git a/lib/containers/__generated__/issueishListContainerQuery.graphql.js b/lib/containers/__generated__/issueishListContainerQuery.graphql.js new file mode 100644 index 0000000000..6d4cdb2986 --- /dev/null +++ b/lib/containers/__generated__/issueishListContainerQuery.graphql.js @@ -0,0 +1,267 @@ +/** + * @flow + * @relayHash ee7e665e11510ad35c15e1943a427d90 + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest } from 'relay-runtime'; +type issueishListController_results$ref = any; +export type issueishListContainerQueryVariables = {| + query: string +|}; +export type issueishListContainerQueryResponse = {| + +search: {| + +$fragmentRefs: issueishListController_results$ref + |} +|}; +*/ + + +/* +query issueishListContainerQuery( + $query: String! +) { + search(first: 20, query: $query, type: ISSUE) { + ...issueishListController_results + } +} + +fragment issueishListController_results on SearchResultItemConnection { + issueCount + nodes { + __typename + ... on PullRequest { + number + title + url + author { + __typename + login + avatarUrl + ... on Node { + id + } + } + createdAt + headRefName + headRepository { + nameWithOwner + id + } + } + ... on Node { + id + } + } +} +*/ + +const node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "LocalArgument", + "name": "query", + "type": "String!", + "defaultValue": null + } +], +v1 = [ + { + "kind": "Literal", + "name": "first", + "value": 20, + "type": "Int" + }, + { + "kind": "Variable", + "name": "query", + "variableName": "query", + "type": "String!" + }, + { + "kind": "Literal", + "name": "type", + "value": "ISSUE", + "type": "SearchType!" + } +], +v2 = { + "kind": "ScalarField", + "alias": null, + "name": "__typename", + "args": null, + "storageKey": null +}, +v3 = { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null +}; +return { + "kind": "Request", + "operationKind": "query", + "name": "issueishListContainerQuery", + "id": null, + "text": "query issueishListContainerQuery(\n $query: String!\n) {\n search(first: 20, query: $query, type: ISSUE) {\n ...issueishListController_results\n }\n}\n\nfragment issueishListController_results on SearchResultItemConnection {\n issueCount\n nodes {\n __typename\n ... on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n headRepository {\n nameWithOwner\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n", + "metadata": {}, + "fragment": { + "kind": "Fragment", + "name": "issueishListContainerQuery", + "type": "Query", + "metadata": null, + "argumentDefinitions": v0, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "search", + "storageKey": null, + "args": v1, + "concreteType": "SearchResultItemConnection", + "plural": false, + "selections": [ + { + "kind": "FragmentSpread", + "name": "issueishListController_results", + "args": null + } + ] + } + ] + }, + "operation": { + "kind": "Operation", + "name": "issueishListContainerQuery", + "argumentDefinitions": v0, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "search", + "storageKey": null, + "args": v1, + "concreteType": "SearchResultItemConnection", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "issueCount", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": true, + "selections": [ + v2, + v3, + { + "kind": "InlineFragment", + "type": "PullRequest", + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "number", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "title", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v2, + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + }, + v3 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "headRefName", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "headRepository", + "storageKey": null, + "args": null, + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "nameWithOwner", + "args": null, + "storageKey": null + }, + v3 + ] + } + ] + } + ] + } + ] + } + ] + } +}; +})(); +// prettier-ignore +(node/*: any*/).hash = 'ef13a7f2814860cf84f1c0da2d44d7ee'; +module.exports = node; diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js new file mode 100644 index 0000000000..652e83833b --- /dev/null +++ b/lib/containers/issueish-list-container.js @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {QueryRenderer, graphql} from 'react-relay'; + +import {autobind} from '../helpers'; +import {SearchPropType} from '../prop-types'; +import IssueishListController from '../controllers/issueish-list-controller'; +import RelayNetworkLayerManager from '../relay-network-layer-manager'; + +export default class IssueishListContainer extends React.Component { + static propTypes = { + token: PropTypes.string.isRequired, + host: PropTypes.string.isRequired, + + search: SearchPropType.isRequired, + } + + constructor(props) { + super(props); + + autobind(this, 'renderQueryResult'); + } + + render() { + const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, this.props.token); + const query = graphql` + query issueishListContainerQuery($query: String!) { + search(first: 20, query: $query, type: ISSUE) { + ...issueishListController_results + } + } + `; + const variables = { + query: this.props.search.createQuery(), + }; + + return ( + + ); + } + + renderQueryResult({error, props}) { + if (error) { + return null; + } + + if (props === null) { + return ( + + ); + } + + return ( + + ); + } +} diff --git a/lib/controllers/__generated__/issueishListController_results.graphql.js b/lib/controllers/__generated__/issueishListController_results.graphql.js new file mode 100644 index 0000000000..f4cf4d42e1 --- /dev/null +++ b/lib/controllers/__generated__/issueishListController_results.graphql.js @@ -0,0 +1,147 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type issueishListController_results$ref: FragmentReference; +export type issueishListController_results = {| + +issueCount: number, + +nodes: ?$ReadOnlyArray, + +$refType: issueishListController_results$ref, +|}; +*/ + + +const node/*: ConcreteFragment*/ = { + "kind": "Fragment", + "name": "issueishListController_results", + "type": "SearchResultItemConnection", + "metadata": null, + "argumentDefinitions": [], + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "issueCount", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": true, + "selections": [ + { + "kind": "InlineFragment", + "type": "PullRequest", + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "number", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "title", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "headRefName", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "headRepository", + "storageKey": null, + "args": null, + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "nameWithOwner", + "args": null, + "storageKey": null + } + ] + } + ] + } + ] + } + ] +}; +// prettier-ignore +(node/*: any*/).hash = '972050cf8a1b45617db5fbde6fd21231'; +module.exports = node; diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js new file mode 100644 index 0000000000..44c48432d9 --- /dev/null +++ b/lib/controllers/issueish-list-controller.js @@ -0,0 +1,32 @@ +import React from 'react'; +import {graphql, createFragmentContainer} from 'react-relay'; + +export class IssueishListController extends React.Component { + render() { + return null; + } +} + +export default createFragmentContainer(IssueishListController, { + results: graphql` + fragment issueishListController_results on SearchResultItemConnection { + issueCount + nodes { + ... on PullRequest { + number + title + url + author { + login + avatarUrl + } + createdAt + headRefName + headRepository { + nameWithOwner + } + } + } + } + `, +}); diff --git a/lib/models/search.js b/lib/models/search.js new file mode 100644 index 0000000000..aa4247ee74 --- /dev/null +++ b/lib/models/search.js @@ -0,0 +1,10 @@ +export default class Search { + constructor(name, query) { + this.name = name; + this.query = query; + } + + createQuery() { + return this.query; + } +} diff --git a/lib/prop-types.js b/lib/prop-types.js index 2d17a1994a..471c9c635a 100644 --- a/lib/prop-types.js +++ b/lib/prop-types.js @@ -24,6 +24,10 @@ export const BranchPropType = PropTypes.shape({ isPresent: PropTypes.func.isRequired, }); +export const SearchPropType = PropTypes.shape({ + createQuery: PropTypes.func.isRequired, +}); + export const BranchSetPropType = PropTypes.shape({ getNames: PropTypes.func.isRequired, getPullTargets: PropTypes.func.isRequired, diff --git a/test/containers/issueish-list-container.test.js b/test/containers/issueish-list-container.test.js new file mode 100644 index 0000000000..61678c803b --- /dev/null +++ b/test/containers/issueish-list-container.test.js @@ -0,0 +1,102 @@ +import React from 'react'; +import {shallow, mount} from 'enzyme'; + +import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; +import Search from '../../lib/models/search'; +import IssueishListContainer from '../../lib/containers/issueish-list-container'; + +describe.only('IssueishListContainer', function() { + function buildApp(overrideProps = {}) { + return ( + + ); + } + + function createPullRequest(number) { + return { + __typename: 'PullRequest', + id: number.toString(), + number, + title: 'One', + url: 'https://github.com/atom/github/1', + author: { + __typename: 'User', + id: 'u0', + login: 'smashwilson', + avatarUrl: 'https://avatar.com/yes.jpg', + }, + createdAt: '2018-06-12T14:50:08Z', + headRefName: 'aw/something', + headRepository: { + id: 'r0', + nameWithOwner: 'atom/github', + }, + }; + } + + it('renders a query for the Search', function() { + const {resolve} = expectRelayQuery({ + name: 'issueishListContainerQuery', + variables: { + query: 'type:pr author:me', + }, + }, { + search: {issueCount: 0, nodes: []}, + }); + + const search = new Search('pull requests', 'type:pr author:me'); + const wrapper = shallow(buildApp({search})); + assert.strictEqual(wrapper.find('ReactRelayQueryRenderer').prop('variables').query, 'type:pr author:me'); + resolve(); + }); + + it('passes an empty result list and an isLoading prop to the controller while loading', function() { + const {resolve} = expectRelayQuery({ + name: 'issueishListContainerQuery', + variables: { + query: 'type:pr author:me', + }, + }, { + search: {issueCount: 0, nodes: []}, + }); + + const search = new Search('pull requests', 'type:pr author:me'); + const wrapper = mount(buildApp({search})); + + const controller = wrapper.find('IssueishListController'); + assert.isTrue(controller.prop('isLoading')); + + resolve(); + }); + + it('passes results to the controller', async function() { + const {promise, resolve} = expectRelayQuery({ + name: 'issueishListContainerQuery', + variables: { + query: 'type:pr author:me', + }, + }, { + search: { + issueCount: 2, + nodes: [ + createPullRequest(1), + createPullRequest(2), + ], + }, + }); + + const search = new Search('pull requests', 'type:pr author:me'); + const wrapper = mount(buildApp({search})); + + resolve(); + await promise; + + const controller = wrapper.update().find('IssueishListController'); + assert.isFalse(controller.prop('isLoading')); + }); +}); From 552418389eac7791adc97cba65aa96888afc8f22 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 12 Jun 2018 14:09:00 -0400 Subject: [PATCH 0165/4847] :fire: .only() --- test/containers/issueish-list-container.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/containers/issueish-list-container.test.js b/test/containers/issueish-list-container.test.js index 61678c803b..0b0cd08ab0 100644 --- a/test/containers/issueish-list-container.test.js +++ b/test/containers/issueish-list-container.test.js @@ -5,7 +5,7 @@ import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import Search from '../../lib/models/search'; import IssueishListContainer from '../../lib/containers/issueish-list-container'; -describe.only('IssueishListContainer', function() { +describe('IssueishListContainer', function() { function buildApp(overrideProps = {}) { return ( Date: Tue, 12 Jun 2018 14:58:29 -0400 Subject: [PATCH 0166/4847] IssueishListController --- lib/controllers/issueish-list-controller.js | 50 +++++++++++++++- lib/models/issueish.js | 44 ++++++++++++++ lib/views/issueish-list-view.js | 14 +++++ .../issueish-list-controller.test.js | 57 +++++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 lib/models/issueish.js create mode 100644 lib/views/issueish-list-view.js create mode 100644 test/controllers/issueish-list-controller.test.js diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index 44c48432d9..af24217aec 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -1,9 +1,57 @@ import React from 'react'; +import PropTypes from 'prop-types'; import {graphql, createFragmentContainer} from 'react-relay'; +import IssueishListView from '../views/issueish-list-view'; +import Issueish from '../models/issueish'; + export class IssueishListController extends React.Component { + static propTypes = { + results: PropTypes.shape({ + issueCount: PropTypes.number.isRequired, + nodes: PropTypes.arrayOf( + PropTypes.shape({ + number: PropTypes.number.isRequired, + title: PropTypes.string.isRequired, + url: PropTypes.string.isRequired, + author: PropTypes.shape({ + login: PropTypes.string.isRequired, + avatarUrl: PropTypes.string.isRequired, + }).isRequired, + createdAt: PropTypes.string.isRequired, + headRefName: PropTypes.string.isRequired, + headRepository: PropTypes.shape({ + nameWithOwner: PropTypes.string.isRequired, + }).isRequired, + }), + ), + }), + }; + + static getDerivedStateFromProps(props, state) { + if (props.results === null) { + return { + isLoading: true, + total: 0, + issueishes: [], + }; + } + + return { + isLoading: false, + total: props.results.issueCount, + issueishes: props.results.nodes.map(node => new Issueish(node)), + }; + } + render() { - return null; + return ( + + ); } } diff --git a/lib/models/issueish.js b/lib/models/issueish.js new file mode 100644 index 0000000000..fede4c9501 --- /dev/null +++ b/lib/models/issueish.js @@ -0,0 +1,44 @@ +export default class Issueish { + constructor(data) { + this.number = data.number; + this.title = data.title; + this.url = data.url; + this.authorLogin = data.author.login; + this.authorAvatarURL = data.author.avatarUrl; + this.createdAt = data.createdAt; + this.headRefName = data.headRefName; + this.headRepositoryName = data.headRepository.nameWithOwner; + } + + getNumber() { + return this.number; + } + + getTitle() { + return this.title; + } + + getGitHubURL() { + return this.url; + } + + getAuthorLogin() { + return this.authorLogin; + } + + getAuthorAvatarURL() { + return this.authorAvatarURL; + } + + getCreatedAt() { + return this.createdAt; + } + + getHeadRefName() { + return this.headRefName; + } + + getHeadRepositoryName() { + return this.headRepositoryName; + } +} diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js new file mode 100644 index 0000000000..3dfc9d30b3 --- /dev/null +++ b/lib/views/issueish-list-view.js @@ -0,0 +1,14 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +export default class IssueishListView extends React.Component { + static propTypes = { + isLoading: PropTypes.bool.isRequired, + total: PropTypes.number.isRequired, + issueishes: PropTypes.arrayOf(PropTypes.any).isRequired, + } + + render() { + return null; + } +} diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js new file mode 100644 index 0000000000..1c7a5aa960 --- /dev/null +++ b/test/controllers/issueish-list-controller.test.js @@ -0,0 +1,57 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import Issueish from '../../lib/models/issueish'; +import {IssueishListController} from '../../lib/controllers/issueish-list-controller'; + +describe('IssueishListController', function() { + function buildApp(overrideProps = {}) { + return ( + + ); + } + + it('renders an IssueishListView in a loading state', function() { + const wrapper = shallow(buildApp()); + + const view = wrapper.find('IssueishListView'); + assert.isTrue(view.prop('isLoading')); + assert.strictEqual(view.prop('total'), 0); + assert.lengthOf(view.prop('issueishes'), 0); + }); + + it('renders an IssueishListView with issueish results', function() { + const mockPullRequest = { + number: 1, + title: 'One', + url: 'https://github.com/atom/github/pulls/1', + author: { + login: 'smashwilson', + avatarUrl: 'https://avatars2.githubusercontent.com/u/17565?v=4', + }, + createdAt: '2018-06-12T14:50:08Z', + headRefName: 'aw/accordion-solo', + headRepository: { + nameWithOwner: 'atom/github', + }, + }; + + const wrapper = shallow(buildApp({ + results: { + issueCount: 1, + nodes: [mockPullRequest], + }, + })); + + const view = wrapper.find('IssueishListView'); + assert.isFalse(view.prop('isLoading')); + assert.strictEqual(view.prop('total'), 1); + assert.lengthOf(view.prop('issueishes'), 1); + assert.deepEqual(view.prop('issueishes'), [ + new Issueish(mockPullRequest), + ]); + }); +}); From 3ac5236c2f7482a1605fa3a858f8ce9850c6d841 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 12 Jun 2018 15:36:22 -0400 Subject: [PATCH 0167/4847] IssueishListView, first pass --- lib/models/search.js | 4 ++ lib/prop-types.js | 1 + lib/views/issueish-list-view.js | 46 ++++++++++++++++++++++- test/views/issueish-list-view.test.js | 54 +++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 test/views/issueish-list-view.test.js diff --git a/lib/models/search.js b/lib/models/search.js index aa4247ee74..f898306397 100644 --- a/lib/models/search.js +++ b/lib/models/search.js @@ -4,6 +4,10 @@ export default class Search { this.query = query; } + getName() { + return this.name; + } + createQuery() { return this.query; } diff --git a/lib/prop-types.js b/lib/prop-types.js index 471c9c635a..8855db50a6 100644 --- a/lib/prop-types.js +++ b/lib/prop-types.js @@ -25,6 +25,7 @@ export const BranchPropType = PropTypes.shape({ }); export const SearchPropType = PropTypes.shape({ + getName: PropTypes.func.isRequired, createQuery: PropTypes.func.isRequired, }); diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 3dfc9d30b3..1c8da41092 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -1,14 +1,56 @@ -import React from 'react'; +import React, {Fragment} from 'react'; import PropTypes from 'prop-types'; +import {SearchPropType} from '../prop-types'; +import {autobind} from '../helpers'; +import Accordion from './accordion'; + export default class IssueishListView extends React.Component { static propTypes = { + search: SearchPropType.isRequired, isLoading: PropTypes.bool.isRequired, total: PropTypes.number.isRequired, issueishes: PropTypes.arrayOf(PropTypes.any).isRequired, } + constructor(props) { + super(props); + + autobind(this, 'renderIssueish'); + } + render() { - return null; + return ( + + {this.renderIssueish} + + ); + } + + renderIssueish(issueish) { + return ( + + + + {issueish.getTitle()} + + + #{issueish.getNumber()} + + + ... + + + ... + + + ); } } diff --git a/test/views/issueish-list-view.test.js b/test/views/issueish-list-view.test.js new file mode 100644 index 0000000000..6c6cc1f6aa --- /dev/null +++ b/test/views/issueish-list-view.test.js @@ -0,0 +1,54 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import Search from '../../lib/models/search'; +import IssueishListView from '../../lib/views/issueish-list-view'; + +describe('IssueishListView', function() { + function buildApp(overrideProps = {}) { + return ( + + ); + } + + it('sets the accordion title to the Search name', function() { + const wrapper = shallow(buildApp({ + search: new Search('the search name', ''), + })); + assert.strictEqual(wrapper.find('Accordion').prop('leftTitle'), 'the search name'); + }); + + describe('while loading', function() { + it('sets its accordion as isLoading', function() { + const wrapper = shallow(buildApp()); + assert.isTrue(wrapper.find('Accordion').prop('isLoading')); + }); + + it('passes an empty result list', function() { + const wrapper = shallow(buildApp()); + assert.lengthOf(wrapper.find('Accordion').prop('results'), 0); + }); + }); + + describe('with empty results', function() { + it('uses a custom EmptyComponent if the search requests one'); + }); + + describe('with nonempty results', function() { + it('passes its results to the accordion', function() { + const issueishes = [Symbol('zero'), Symbol('one'), Symbol('two')]; + const wrapper = shallow(buildApp({ + isLoading: false, + total: 3, + issueishes, + })); + assert.deepEqual(wrapper.find('Accordion').prop('results'), issueishes); + }); + }); +}); From f30be0b27b1852e11c37bae6146b77bec241ad3a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 10:03:32 -0400 Subject: [PATCH 0168/4847] Refactor RemoteSelectorView into its own source file --- lib/controllers/github-tab-controller.js | 34 ++---------------------- lib/views/remote-selector-view.js | 34 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 32 deletions(-) create mode 100644 lib/views/remote-selector-view.js diff --git a/lib/controllers/github-tab-controller.js b/lib/controllers/github-tab-controller.js index 2f7c603076..9b4a1dc41c 100644 --- a/lib/controllers/github-tab-controller.js +++ b/lib/controllers/github-tab-controller.js @@ -2,42 +2,12 @@ import React from 'react'; import PropTypes from 'prop-types'; import yubikiri from 'yubikiri'; +import RemoteSelectorView from '../views/remote-selector-view'; import RemotePrController from './remote-pr-controller'; import GithubLoginModel from '../models/github-login-model'; import ObserveModel from '../views/observe-model'; -import {RemotePropType, BranchPropType} from '../prop-types'; import {autobind} from '../helpers'; -class RemoteSelector extends React.Component { - static propTypes = { - remotes: PropTypes.arrayOf(RemotePropType).isRequired, - currentBranch: BranchPropType.isRequired, - selectRemote: PropTypes.func.isRequired, - } - - render() { - const {remotes, currentBranch, selectRemote} = this.props; - return ( -
-

- This repository has multiple remotes hosted at GitHub.com. - Select a remote to see pull requests associated - with the {currentBranch.getName()} branch. -

- -
- ); - } -} - export default class GithubTabController extends React.Component { static propTypes = { repository: PropTypes.object, @@ -122,7 +92,7 @@ export default class GithubTabController extends React.Component { /> } {!remote && manyRemotesAvailable && - +

+ This repository has multiple remotes hosted at GitHub.com. + Select a remote to see pull requests associated + with the {currentBranch.getName()} branch. +

+ +
+ ); + } +} From 2d9290e7b2cdb33069686e439f958b4f89398ada Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 11:21:57 -0400 Subject: [PATCH 0169/4847] Search model with factory methods --- lib/models/branch.js | 8 ++++++ lib/models/search.js | 29 +++++++++++++++++++++- test/models/search.test.js | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 test/models/search.test.js diff --git a/lib/models/branch.js b/lib/models/branch.js index daa6b04508..0bbd6ca931 100644 --- a/lib/models/branch.js +++ b/lib/models/branch.js @@ -22,6 +22,10 @@ export default class Branch { return this.name; } + getShortRef() { + return this.getName().replace(/^(refs\/)?(heads|remotes)\//, ''); + } + getFullRef() { if (this.isDetached()) { return ''; @@ -59,6 +63,10 @@ export default class Branch { return this.attributes[REMOTE_TRACKING].remoteRef; } + getShortRemoteRef() { + return this.getRemoteRef().replace(/^(refs\/)?(heads|remotes)\//, ''); + } + getSha() { return this.attributes.sha || ''; } diff --git a/lib/models/search.js b/lib/models/search.js index f898306397..650a3ea380 100644 --- a/lib/models/search.js +++ b/lib/models/search.js @@ -1,7 +1,10 @@ +const NULL = Symbol('null'); + export default class Search { - constructor(name, query) { + constructor(name, query, attrs = {}) { this.name = name; this.query = query; + this.attrs = attrs; } getName() { @@ -11,4 +14,28 @@ export default class Search { createQuery() { return this.query; } + + // A null search has insufficient information to construct a canned query, so it should always return no results. + isNull() { + return this.attrs[NULL] || false; + } + + static forCurrentPR(remote, branch) { + const name = 'Current pull request'; + + const upstream = branch.getUpstream(); + if (!remote.isPresent() || !remote.isGithubRepo() || !upstream.isRemoteTracking()) { + return new this(name, '', {[NULL]: true}); + } + + return new this(name, `repo:${remote.getOwner()}/${remote.getRepo()} type:pr head:${upstream.getShortRemoteRef()}`); + } + + static inRemote(remote, name, query) { + if (!remote.isPresent()) { + return new this(name, '', {[NULL]: true}); + } + + return new this(name, `repo:${remote.getOwner()}/${remote.getRepo()} ${query.trim()}`); + } } diff --git a/test/models/search.test.js b/test/models/search.test.js new file mode 100644 index 0000000000..48a42be02e --- /dev/null +++ b/test/models/search.test.js @@ -0,0 +1,50 @@ +import Remote, {nullRemote} from '../../lib/models/remote'; +import Branch from '../../lib/models/branch'; + +import Search from '../../lib/models/search'; + +describe('Search', function() { + const origin = new Remote('origin', 'git@github.com:atom/github.git'); + const originMaster = Branch.createRemoteTracking('origin/master', 'origin', 'refs/heads/master'); + const master = new Branch('master', originMaster); + const local = new Branch('local'); + const tracksLocal = new Branch('tracks-local', local); + + describe('for the current pull request', function() { + it('is a null search when the Branch has no upstream', function() { + const s = Search.forCurrentPR(origin, local); + assert.isTrue(s.isNull()); + }); + + it("is a null search when the Branch's upstream is not a remote tracking branch", function() { + const s = Search.forCurrentPR(origin, tracksLocal); + assert.isTrue(s.isNull()); + }); + + it('is a null search when no Remote is available', function() { + const s = Search.forCurrentPR(nullRemote, master); + assert.isTrue(s.isNull()); + }); + + it('creates a templated search query for a remote and branch', function() { + const s = Search.forCurrentPR(origin, master); + assert.isFalse(s.isNull()); + assert.strictEqual(s.createQuery(), 'repo:atom/github type:pr head:master'); + }); + }); + + describe('when scoped to a remote', function() { + it('is a null search when the remote is not present', function() { + const s = Search.inRemote(nullRemote, 'name', 'query'); + assert.isTrue(s.isNull()); + assert.strictEqual(s.getName(), 'name'); + }); + + it('prepends a repo: criteria to the search query', function() { + const s = Search.inRemote(origin, 'name', 'query'); + assert.isFalse(s.isNull()); + assert.strictEqual(s.getName(), 'name'); + assert.strictEqual(s.createQuery(), 'repo:atom/github query'); + }); + }); +}); From 7bd62039a3315ec0c362b2baf9b481c3f4ccffe9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 11:54:34 -0400 Subject: [PATCH 0170/4847] Use inRemote to implement forCurrentPR --- lib/models/search.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/models/search.js b/lib/models/search.js index 650a3ea380..3445ea273c 100644 --- a/lib/models/search.js +++ b/lib/models/search.js @@ -24,15 +24,15 @@ export default class Search { const name = 'Current pull request'; const upstream = branch.getUpstream(); - if (!remote.isPresent() || !remote.isGithubRepo() || !upstream.isRemoteTracking()) { + if (!upstream.isRemoteTracking()) { return new this(name, '', {[NULL]: true}); } - return new this(name, `repo:${remote.getOwner()}/${remote.getRepo()} type:pr head:${upstream.getShortRemoteRef()}`); + return this.inRemote(remote, name, `type:pr head:${upstream.getShortRemoteRef()}`); } static inRemote(remote, name, query) { - if (!remote.isPresent()) { + if (!remote.isGithubRepo()) { return new this(name, '', {[NULL]: true}); } From df3158e60fb6db838bef710f287b0c492d0c47cc Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 11:54:56 -0400 Subject: [PATCH 0171/4847] IssueishSearchController to house Searches and IssueishListContainers --- lib/controllers/issueish-search-controller.js | 40 +++++++++++++++++++ .../issueish-search-controller.test.js | 38 ++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 lib/controllers/issueish-search-controller.js create mode 100644 test/controllers/issueish-search-controller.test.js diff --git a/lib/controllers/issueish-search-controller.js b/lib/controllers/issueish-search-controller.js new file mode 100644 index 0000000000..e37ebc3bd1 --- /dev/null +++ b/lib/controllers/issueish-search-controller.js @@ -0,0 +1,40 @@ +import React, {Fragment} from 'react'; +import PropTypes from 'prop-types'; + +import {RemotePropType, BranchPropType} from '../prop-types'; +import Search from '../models/search'; +import IssueishListContainer from '../containers/issueish-list-container'; + +export default class IssueishSearchController extends React.Component { + static propTypes = { + host: PropTypes.string.isRequired, + token: PropTypes.string.isRequired, + + remote: RemotePropType.isRequired, + currentBranch: BranchPropType.isRequired, + } + + static getDerivedStateFromProps(props) { + return { + searches: [ + Search.forCurrentPR(props.remote, props.currentBranch), + Search.inRemote(props.remote, 'Open pull requests', 'type:pr state:open'), + ], + }; + } + + render() { + return ( + + {this.state.searches.map(search => ( + + ))} + + ); + } +} diff --git a/test/controllers/issueish-search-controller.test.js b/test/controllers/issueish-search-controller.test.js new file mode 100644 index 0000000000..9e09d6706e --- /dev/null +++ b/test/controllers/issueish-search-controller.test.js @@ -0,0 +1,38 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import IssueishSearchController from '../../lib/controllers/issueish-search-controller'; +import Remote from '../../lib/models/remote'; +import Branch from '../../lib/models/branch'; + +describe('IssueishSearchController', function() { + const origin = new Remote('origin', 'git@github.com:atom/github.git'); + const upstreamMaster = Branch.createRemoteTracking('origin/master', 'origin', 'refs/heads/master'); + const master = new Branch('master', upstreamMaster); + + function buildApp(overloadProps = {}) { + return ( + + ); + } + + it('renders an IssueishListContainer for each Search', function() { + const wrapper = shallow(buildApp()); + assert.isTrue(wrapper.state('searches').length > 0); + + for (const search of wrapper.state('searches')) { + const list = wrapper.find('IssueishListContainer').filterWhere(w => w.prop('search') === search); + assert.isTrue(list.exists()); + assert.strictEqual(list.prop('token'), '1234'); + assert.strictEqual(list.prop('host'), 'https://api.github.com'); + } + }); +}); From 253219eaf757f4c0ba6ff94a15ee911bb8b3e6a3 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 13 Jun 2018 17:20:07 +0000 Subject: [PATCH 0172/4847] fix(package): update react to version 16.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 38542b4160..9033164694 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "lodash.memoize": "4.1.2", "moment": "2.22.2", "prop-types": "15.6.1", - "react": "16.4.0", + "react": "16.4.1", "react-dom": "16.4.0", "react-relay": "1.6.0", "react-select": "1.2.1", From 5fc679b0f6a7062c1cae0f4e706ad7968d767ec6 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 13 Jun 2018 17:24:52 +0000 Subject: [PATCH 0173/4847] fix(package): update react-dom to version 16.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9033164694..dcd403f1eb 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "moment": "2.22.2", "prop-types": "15.6.1", "react": "16.4.1", - "react-dom": "16.4.0", + "react-dom": "16.4.1", "react-relay": "1.6.0", "react-select": "1.2.1", "relay-runtime": "1.6.0", From 0f643685cda984afc5c153e1c502960f1a87d10d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 14:20:53 -0400 Subject: [PATCH 0174/4847] Pass Search through the Issueish components --- lib/containers/issueish-list-container.js | 2 ++ lib/controllers/issueish-list-controller.js | 9 +++++++++ lib/controllers/issueish-search-controller.js | 6 ++++++ lib/controllers/remote-pr-controller.js | 20 ++++++------------- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index 652e83833b..92de75aa41 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -54,6 +54,7 @@ export default class IssueishListContainer extends React.Component { ); } @@ -62,6 +63,7 @@ export default class IssueishListContainer extends React.Component { ); } diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index af24217aec..14ccf6acc1 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {graphql, createFragmentContainer} from 'react-relay'; +import {SearchPropType} from '../prop-types'; import IssueishListView from '../views/issueish-list-view'; import Issueish from '../models/issueish'; @@ -26,8 +27,15 @@ export class IssueishListController extends React.Component { }), ), }), + search: SearchPropType.isRequired, }; + constructor(props) { + super(props); + + this.state = {}; + } + static getDerivedStateFromProps(props, state) { if (props.results === null) { return { @@ -50,6 +58,7 @@ export class IssueishListController extends React.Component { isLoading={this.state.isLoading} total={this.state.total} issueishes={this.state.issueishes} + search={this.props.search} /> ); } diff --git a/lib/controllers/issueish-search-controller.js b/lib/controllers/issueish-search-controller.js index e37ebc3bd1..b2e8340e8c 100644 --- a/lib/controllers/issueish-search-controller.js +++ b/lib/controllers/issueish-search-controller.js @@ -14,6 +14,12 @@ export default class IssueishSearchController extends React.Component { currentBranch: BranchPropType.isRequired, } + constructor(props) { + super(props); + + this.state = {}; + } + static getDerivedStateFromProps(props) { return { searches: [ diff --git a/lib/controllers/remote-pr-controller.js b/lib/controllers/remote-pr-controller.js index 19100aef4d..8d161f98fd 100644 --- a/lib/controllers/remote-pr-controller.js +++ b/lib/controllers/remote-pr-controller.js @@ -9,7 +9,7 @@ import GithubLoginView from '../views/github-login-view'; import ObserveModel from '../views/observe-model'; import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; import {nullRemote} from '../models/remote'; -import PrInfoController from './pr-info-controller'; +import IssueishSearchController from './issueish-search-controller'; import {autobind} from '../helpers'; export default class RemotePrController extends React.Component { @@ -65,20 +65,12 @@ export default class RemotePrController extends React.Component { ); } else { - const { - host, remote, branches, loginModel, selectedPrUrl, - aheadCount, pushInProgress, onSelectPr, onUnpinPr, - } = this.props; - inner = ( - ); } From 99481e355e15c6aca8ed461de7312d51ed9362cb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 14:35:24 -0400 Subject: [PATCH 0175/4847] :white_check_mark: RemotePrController tests --- test/controllers/remote-pr-controller.test.js | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/test/controllers/remote-pr-controller.test.js b/test/controllers/remote-pr-controller.test.js index 7a9e3a4462..192987b4a2 100644 --- a/test/controllers/remote-pr-controller.test.js +++ b/test/controllers/remote-pr-controller.test.js @@ -3,24 +3,27 @@ import {mount} from 'enzyme'; import GithubLoginModel from '../../lib/models/github-login-model'; import BranchSet from '../../lib/models/branch-set'; +import Branch, {nullBranch} from '../../lib/models/branch'; import Remote from '../../lib/models/remote'; import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import {InMemoryStrategy, UNAUTHENTICATED, INSUFFICIENT} from '../../lib/shared/keytar-strategy'; import RemotePrController from '../../lib/controllers/remote-pr-controller'; describe('RemotePrController', function() { - let loginModel, remote, branchSet; + let loginModel, remote, branchSet, currentBranch; beforeEach(function() { loginModel = new GithubLoginModel(InMemoryStrategy); sinon.stub(loginModel, 'getToken').returns(Promise.resolve('1234')); remote = new Remote('origin', 'git@github.com:atom/github'); + currentBranch = new Branch('master', nullBranch, nullBranch, true); branchSet = new BranchSet(); + branchSet.add(currentBranch); expectRelayQuery({ - name: 'prInfoControllerByBranchQuery', - variables: {repoOwner: 'atom', repoName: 'github', branchName: ''}, + name: 'issueishListContainerQuery', + variables: {query: 'repo:atom/github type:pr state:open'}, }, { repository: { defaultBranchRef: { @@ -84,14 +87,15 @@ describe('RemotePrController', function() { ); }); - it('renders pull request info if authenticated', async function() { + it('renders issueish searches if authenticated', async function() { const wrapper = mount(createApp()); - await assert.async.isTrue(wrapper.update().find('PrInfoController').exists()); + await assert.async.isTrue(wrapper.update().find('IssueishSearchController').exists()); - const controller = wrapper.update().find('PrInfoController'); + const controller = wrapper.update().find('IssueishSearchController'); + assert.strictEqual(controller.prop('token'), '1234'); + assert.strictEqual(controller.prop('host'), 'https://api.github.com'); assert.strictEqual(controller.prop('remote'), remote); - assert.strictEqual(controller.prop('branches'), branchSet); - assert.strictEqual(controller.prop('loginModel'), loginModel); + assert.strictEqual(controller.prop('currentBranch'), currentBranch); }); }); From 1c26fcda44b830d5af539737d18ac4c41f49bb4e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 14:44:50 -0400 Subject: [PATCH 0176/4847] Don't bother to actually execute null searches --- lib/containers/issueish-list-container.js | 10 +++++++--- lib/models/search.js | 2 ++ test/containers/issueish-list-container.test.js | 12 +++++++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index 92de75aa41..00c32cb0e2 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -22,6 +22,10 @@ export default class IssueishListContainer extends React.Component { } render() { + if (this.props.search.isNull()) { + return this.renderQueryResult({error: null, props: null, nullSearch: true}); + } + const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, this.props.token); const query = graphql` query issueishListContainerQuery($query: String!) { @@ -44,15 +48,15 @@ export default class IssueishListContainer extends React.Component { ); } - renderQueryResult({error, props}) { + renderQueryResult({error, props, nullSearch}) { if (error) { return null; } - if (props === null) { + if (props === null || nullSearch) { return ( diff --git a/lib/models/search.js b/lib/models/search.js index 3445ea273c..09727bd6b9 100644 --- a/lib/models/search.js +++ b/lib/models/search.js @@ -39,3 +39,5 @@ export default class Search { return new this(name, `repo:${remote.getOwner()}/${remote.getRepo()} ${query.trim()}`); } } + +export const nullSearch = new Search('', '', {[NULL]: true}); diff --git a/test/containers/issueish-list-container.test.js b/test/containers/issueish-list-container.test.js index 0b0cd08ab0..d7e64285b7 100644 --- a/test/containers/issueish-list-container.test.js +++ b/test/containers/issueish-list-container.test.js @@ -2,7 +2,7 @@ import React from 'react'; import {shallow, mount} from 'enzyme'; import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; -import Search from '../../lib/models/search'; +import Search, {nullSearch} from '../../lib/models/search'; import IssueishListContainer from '../../lib/containers/issueish-list-container'; describe('IssueishListContainer', function() { @@ -39,6 +39,16 @@ describe('IssueishListContainer', function() { }; } + it('performs no query for a null Search', function() { + const wrapper = shallow(buildApp({search: nullSearch})); + + assert.isFalse(wrapper.find('ReactRelayQueryRenderer').exists()); + const list = wrapper.find('Relay(IssueishListController)'); + assert.isTrue(list.exists()); + assert.isFalse(list.prop('isLoading')); + assert.isNull(list.prop('results')); + }); + it('renders a query for the Search', function() { const {resolve} = expectRelayQuery({ name: 'issueishListContainerQuery', From 4d7a10d3872547649d34879926480ef6c07e95d0 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 15:07:49 -0400 Subject: [PATCH 0177/4847] Avoid classname confusion with a BareIssueishListController --- lib/controllers/issueish-list-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index 14ccf6acc1..784744ddbb 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -6,7 +6,7 @@ import {SearchPropType} from '../prop-types'; import IssueishListView from '../views/issueish-list-view'; import Issueish from '../models/issueish'; -export class IssueishListController extends React.Component { +export class BareIssueishListController extends React.Component { static propTypes = { results: PropTypes.shape({ issueCount: PropTypes.number.isRequired, @@ -64,7 +64,7 @@ export class IssueishListController extends React.Component { } } -export default createFragmentContainer(IssueishListController, { +export default createFragmentContainer(BareIssueishListController, { results: graphql` fragment issueishListController_results on SearchResultItemConnection { issueCount From 639002ac94b4258d1548b64992ccc43089843ad6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 15:08:16 -0400 Subject: [PATCH 0178/4847] Render a BareIssueishListController directly when loading --- lib/containers/issueish-list-container.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index 00c32cb0e2..642f53f2d6 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -4,7 +4,7 @@ import {QueryRenderer, graphql} from 'react-relay'; import {autobind} from '../helpers'; import {SearchPropType} from '../prop-types'; -import IssueishListController from '../controllers/issueish-list-controller'; +import IssueishListController, {BareIssueishListController} from '../controllers/issueish-list-controller'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; export default class IssueishListContainer extends React.Component { @@ -22,11 +22,12 @@ export default class IssueishListContainer extends React.Component { } render() { + const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, this.props.token); + if (this.props.search.isNull()) { - return this.renderQueryResult({error: null, props: null, nullSearch: true}); + return ; } - const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, this.props.token); const query = graphql` query issueishListContainerQuery($query: String!) { search(first: 20, query: $query, type: ISSUE) { @@ -48,19 +49,13 @@ export default class IssueishListContainer extends React.Component { ); } - renderQueryResult({error, props, nullSearch}) { + renderQueryResult({error, props}) { if (error) { return null; } - if (props === null || nullSearch) { - return ( - - ); + if (props === null) { + return ; } return ( From 7732a3f7341c49f43fb1ce31135f15eee4a599a9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 15:08:31 -0400 Subject: [PATCH 0179/4847] Default results to an empty search result --- lib/controllers/issueish-list-controller.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index 784744ddbb..e3bea38080 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -30,6 +30,13 @@ export class BareIssueishListController extends React.Component { search: SearchPropType.isRequired, }; + static defaultProps = { + results: { + issueCount: 0, + nodes: [], + }, + } + constructor(props) { super(props); From d2a97a1e8b6291b36ab203c5a009804ad9089bbd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 15:16:28 -0400 Subject: [PATCH 0180/4847] Update Enzyme expectations --- test/containers/issueish-list-container.test.js | 11 +++++++---- test/controllers/issueish-list-controller.test.js | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/test/containers/issueish-list-container.test.js b/test/containers/issueish-list-container.test.js index d7e64285b7..260372c0de 100644 --- a/test/containers/issueish-list-container.test.js +++ b/test/containers/issueish-list-container.test.js @@ -43,10 +43,13 @@ describe('IssueishListContainer', function() { const wrapper = shallow(buildApp({search: nullSearch})); assert.isFalse(wrapper.find('ReactRelayQueryRenderer').exists()); - const list = wrapper.find('Relay(IssueishListController)'); + const list = wrapper.find('BareIssueishListController'); assert.isTrue(list.exists()); assert.isFalse(list.prop('isLoading')); - assert.isNull(list.prop('results')); + assert.deepEqual(list.prop('results'), { + issueCount: 0, + nodes: [], + }); }); it('renders a query for the Search', function() { @@ -78,7 +81,7 @@ describe('IssueishListContainer', function() { const search = new Search('pull requests', 'type:pr author:me'); const wrapper = mount(buildApp({search})); - const controller = wrapper.find('IssueishListController'); + const controller = wrapper.find('BareIssueishListController'); assert.isTrue(controller.prop('isLoading')); resolve(); @@ -106,7 +109,7 @@ describe('IssueishListContainer', function() { resolve(); await promise; - const controller = wrapper.update().find('IssueishListController'); + const controller = wrapper.update().find('BareIssueishListController'); assert.isFalse(controller.prop('isLoading')); }); }); diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index 1c7a5aa960..12ed118ca7 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -2,12 +2,12 @@ import React from 'react'; import {shallow} from 'enzyme'; import Issueish from '../../lib/models/issueish'; -import {IssueishListController} from '../../lib/controllers/issueish-list-controller'; +import {BareIssueishListController} from '../../lib/controllers/issueish-list-controller'; describe('IssueishListController', function() { function buildApp(overrideProps = {}) { return ( - From 373b0aa48cd2584c6ef442fdd7a9b3d3b7a4686d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 13 Jun 2018 15:39:12 -0400 Subject: [PATCH 0181/4847] Boolean toggle to show a "create" tile when empty --- lib/models/search.js | 14 ++++++++++---- test/models/search.test.js | 8 ++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/models/search.js b/lib/models/search.js index 09727bd6b9..d6a3dc2699 100644 --- a/lib/models/search.js +++ b/lib/models/search.js @@ -1,4 +1,5 @@ const NULL = Symbol('null'); +const CREATE_ON_EMPTY = Symbol('create on empty'); export default class Search { constructor(name, query, attrs = {}) { @@ -20,20 +21,25 @@ export default class Search { return this.attrs[NULL] || false; } + showCreateOnEmpty() { + return this.attrs[CREATE_ON_EMPTY] || false; + } + static forCurrentPR(remote, branch) { const name = 'Current pull request'; + const attrs = {[NULL]: true, [CREATE_ON_EMPTY]: true}; const upstream = branch.getUpstream(); if (!upstream.isRemoteTracking()) { - return new this(name, '', {[NULL]: true}); + return new this(name, '', attrs); } - return this.inRemote(remote, name, `type:pr head:${upstream.getShortRemoteRef()}`); + return this.inRemote(remote, name, `type:pr head:${upstream.getShortRemoteRef()}`, attrs); } - static inRemote(remote, name, query) { + static inRemote(remote, name, query, attrs = {}) { if (!remote.isGithubRepo()) { - return new this(name, '', {[NULL]: true}); + return new this(name, '', {...attrs, [NULL]: true}); } return new this(name, `repo:${remote.getOwner()}/${remote.getRepo()} ${query.trim()}`); diff --git a/test/models/search.test.js b/test/models/search.test.js index 48a42be02e..20def53cc5 100644 --- a/test/models/search.test.js +++ b/test/models/search.test.js @@ -31,6 +31,10 @@ describe('Search', function() { assert.isFalse(s.isNull()); assert.strictEqual(s.createQuery(), 'repo:atom/github type:pr head:master'); }); + + it('uses a PR creation empty list tile when the Branch has no upstream', function() { + assert.isTrue(Search.forCurrentPR(origin, local).showCreateOnEmpty()); + }); }); describe('when scoped to a remote', function() { @@ -46,5 +50,9 @@ describe('Search', function() { assert.strictEqual(s.getName(), 'name'); assert.strictEqual(s.createQuery(), 'repo:atom/github query'); }); + + it('uses a default empty list tile', function() { + assert.isFalse(Search.inRemote(origin, 'name', 'query').showCreateOnEmpty()); + }); }); }); From ae1c067af0c0752a239afe2a644862b9e4679c78 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 13 Jun 2018 16:53:31 -0700 Subject: [PATCH 0182/4847] add some styling to the avatars --- styles/issuesish-list-view.less | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 styles/issuesish-list-view.less diff --git a/styles/issuesish-list-view.less b/styles/issuesish-list-view.less new file mode 100644 index 0000000000..2db012c383 --- /dev/null +++ b/styles/issuesish-list-view.less @@ -0,0 +1,16 @@ +@import "variables"; + +@size: 16px; + +.github-IssueishList { + &-item { + &--avatar { + border-radius: @component-border-radius; + height: @size; + width: @size; + + line-height: @size; + margin: 2px; + } + } +} From ac276857703d5232513b6f0049528c6d71fd348e Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 14 Jun 2018 16:17:46 +0900 Subject: [PATCH 0183/4847] Style PR list --- styles/accordion.less | 35 ++++++++++++++++++++++++ styles/github-controller.less | 1 + styles/issuesish-list-view.less | 47 ++++++++++++++++++++++++++++++--- styles/pr-info.less | 1 + 4 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 styles/accordion.less diff --git a/styles/accordion.less b/styles/accordion.less new file mode 100644 index 0000000000..cec914c983 --- /dev/null +++ b/styles/accordion.less @@ -0,0 +1,35 @@ +@import "variables"; + +.github-Accordion { + cursor: default; + user-select: none; + + &-header { + font-weight: 600; + color: @text-color-subtle; + padding: @component-padding/2; + border-bottom: 1px solid @base-border-color; + } + + &-content { + // Add an "Empty" label for empty items + &:empty::before { + content: "Empty"; + display: block; + font-style: italic; + text-align: center; + color: @text-color-subtle; + } + } + + &-list { + margin: 0; + padding: 0; + list-style: none; + } + + &[open] &-header { + color: @text-color-highlight; + } + +} diff --git a/styles/github-controller.less b/styles/github-controller.less index e7c9d6bbde..b6eb33e95a 100644 --- a/styles/github-controller.less +++ b/styles/github-controller.less @@ -5,6 +5,7 @@ .github-GithubTabController { flex: 1; + min-width: 0; display: flex; flex-direction: column; diff --git a/styles/issuesish-list-view.less b/styles/issuesish-list-view.less index 2db012c383..2211625554 100644 --- a/styles/issuesish-list-view.less +++ b/styles/issuesish-list-view.less @@ -1,16 +1,57 @@ @import "variables"; -@size: 16px; +// TODO: Rename +.github-Accordion-list--item { + display: flex; + align-items: center; + padding: @component-padding / 4; + border-bottom: 1px solid @base-border-color; + background-color: @base-background-color; + + &:active { + background-color: @background-color-highlight; + } +} .github-IssueishList { &-item { + + // TODO: Rename + &--avatar, + &--title, + &--number, + &--status, + &--age { + margin: @component-padding / 4; + } + &--avatar { + @size: 16px; border-radius: @component-border-radius; height: @size; width: @size; + } - line-height: @size; - margin: 2px; + &--title { + flex: 1; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } + + &--number { + font-size: .9em; + color: @text-color-subtle; + } + + &--status { + + } + + &--age { + color: @text-color-subtle; + font-size: .9em; + } + } } diff --git a/styles/pr-info.less b/styles/pr-info.less index b5d0cae05f..9ad3781e10 100644 --- a/styles/pr-info.less +++ b/styles/pr-info.less @@ -5,6 +5,7 @@ .github-RemotePrController { flex: 1; + min-width: 0; display: flex; flex-direction: column; } From 78b2eb4ba3e247abcde02d853d410272fd39e3f2 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 14 Jun 2018 16:40:16 +0900 Subject: [PATCH 0184/4847] Add example staus and age Still needs wiring up --- lib/views/issueish-list-view.js | 7 +++---- styles/issuesish-list-view.less | 10 +++++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 1c8da41092..f762026a52 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import {SearchPropType} from '../prop-types'; import {autobind} from '../helpers'; import Accordion from './accordion'; +import Octicon from '../atom/octicon'; export default class IssueishListView extends React.Component { static propTypes = { @@ -44,11 +45,9 @@ export default class IssueishListView extends React.Component { #{issueish.getNumber()} - - ... - + {/* TODO: wire up */} - ... + 1d {/* TODO: wire up */} ); diff --git a/styles/issuesish-list-view.less b/styles/issuesish-list-view.less index 2211625554..f482ddd3b0 100644 --- a/styles/issuesish-list-view.less +++ b/styles/issuesish-list-view.less @@ -45,7 +45,15 @@ } &--status { - + &:before { + margin-right: 0; + } + &.icon-check { + color: @text-color-success; + } + &.icon-x { + color: @text-color-error; + } } &--age { From 81e9d955d5630c1efcac5296cd363bdf31489b15 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 14 Jun 2018 17:11:22 +0900 Subject: [PATCH 0185/4847] Load smaller avatar size --- lib/views/issueish-list-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index f762026a52..57421a25ba 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -36,7 +36,7 @@ export default class IssueishListView extends React.Component { From 4806ea6d744e92dd607052d9d8e43fc15796c19c Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 14 Jun 2018 17:16:20 +0900 Subject: [PATCH 0186/4847] Add overflow scrolling --- styles/pr-info.less | 1 + 1 file changed, 1 insertion(+) diff --git a/styles/pr-info.less b/styles/pr-info.less index 9ad3781e10..7e9d1064c3 100644 --- a/styles/pr-info.less +++ b/styles/pr-info.less @@ -8,6 +8,7 @@ min-width: 0; display: flex; flex-direction: column; + overflow-y: auto; } .github-PrInfo { From 8672bccd40955d6c36eba83830fc9a74f43b4b8c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 09:09:24 -0400 Subject: [PATCH 0187/4847] Use Node's URL manipulation facilities to append an ?s= query parameter --- lib/models/issueish.js | 14 +++++++++----- lib/views/issueish-list-view.js | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/models/issueish.js b/lib/models/issueish.js index fede4c9501..077db91342 100644 --- a/lib/models/issueish.js +++ b/lib/models/issueish.js @@ -1,10 +1,12 @@ +import {URL} from 'url'; + export default class Issueish { constructor(data) { this.number = data.number; this.title = data.title; - this.url = data.url; + this.url = new URL(data.url); this.authorLogin = data.author.login; - this.authorAvatarURL = data.author.avatarUrl; + this.authorAvatarURL = new URL(data.author.avatarUrl); this.createdAt = data.createdAt; this.headRefName = data.headRefName; this.headRepositoryName = data.headRepository.nameWithOwner; @@ -19,15 +21,17 @@ export default class Issueish { } getGitHubURL() { - return this.url; + return this.url.toString(); } getAuthorLogin() { return this.authorLogin; } - getAuthorAvatarURL() { - return this.authorAvatarURL; + getAuthorAvatarURL(size = 32) { + const u = new URL(this.authorAvatarURL.toString()); + u.searchParams.set('s', size); + return u.toString(); } getCreatedAt() { diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 57421a25ba..0c63e71fd7 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -36,7 +36,7 @@ export default class IssueishListView extends React.Component { From ff11c09a7bc5b7874ec7b65c5b8be5ac00dc9cf5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 09:23:02 -0400 Subject: [PATCH 0188/4847] Prevent the default behavior of clicking on a
element --- lib/views/accordion.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/views/accordion.js b/lib/views/accordion.js index 612b8ee1ec..a3ce0abf0b 100644 --- a/lib/views/accordion.js +++ b/lib/views/accordion.js @@ -77,7 +77,8 @@ export default class Accordion extends React.Component { ); } - toggle() { + toggle(e) { + e.preventDefault(); return new Promise(resolve => { this.setState(prevState => ({expanded: !prevState.expanded}), resolve); }); From bbb8aba3374bde1413de46e2c4ad545907243644 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 09:23:15 -0400 Subject: [PATCH 0189/4847] Don't bother rendering children if an Accordion isn't expanded --- lib/views/accordion.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/views/accordion.js b/lib/views/accordion.js index a3ce0abf0b..cb3344e29f 100644 --- a/lib/views/accordion.js +++ b/lib/views/accordion.js @@ -67,6 +67,10 @@ export default class Accordion extends React.Component { return ; } + if (!this.state.expanded) { + return null; + } + return (
    {this.props.results.map((item, index) => { From 431d3b25eff8acd81fde1560b85d027465758739 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 09:29:22 -0400 Subject: [PATCH 0190/4847] Oh right, that isn't always there for Enzyme --- lib/views/accordion.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/accordion.js b/lib/views/accordion.js index cb3344e29f..056e94d7fa 100644 --- a/lib/views/accordion.js +++ b/lib/views/accordion.js @@ -82,7 +82,7 @@ export default class Accordion extends React.Component { } toggle(e) { - e.preventDefault(); + e.preventDefault && e.preventDefault(); return new Promise(resolve => { this.setState(prevState => ({expanded: !prevState.expanded}), resolve); }); From 2c045fc7e7b83cc056f97e862470768388f8e0f6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 09:40:30 -0400 Subject: [PATCH 0191/4847] Fix it in Enzyme, not in the component --- lib/views/accordion.js | 2 +- test/views/accordion.test.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/views/accordion.js b/lib/views/accordion.js index 056e94d7fa..cb3344e29f 100644 --- a/lib/views/accordion.js +++ b/lib/views/accordion.js @@ -82,7 +82,7 @@ export default class Accordion extends React.Component { } toggle(e) { - e.preventDefault && e.preventDefault(); + e.preventDefault(); return new Promise(resolve => { this.setState(prevState => ({expanded: !prevState.expanded}), resolve); }); diff --git a/test/views/accordion.test.js b/test/views/accordion.test.js index 75022296a8..58328ce08a 100644 --- a/test/views/accordion.test.js +++ b/test/views/accordion.test.js @@ -51,8 +51,10 @@ describe('Accordion', function() { it('toggles expansion state on a header click', function() { const wrapper = shallow(buildApp()); - wrapper.find('.github-Accordion-header').simulate('click'); + const e = {preventDefault: sinon.stub()}; + wrapper.find('.github-Accordion-header').simulate('click', e); assert.isFalse(wrapper.find('details.github-Accordion[open="false"]').exists()); + assert.isTrue(e.preventDefault.called); }); describe('while loading', function() { From f956556af9c79af1d4eeb4e601ccd5f4d5bd8051 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 10:53:07 -0400 Subject: [PATCH 0192/4847] Pass the props we need for a PR creation tile through IssueishSearch --- lib/containers/issueish-list-container.js | 52 +++++++++++++++++-- lib/controllers/issueish-list-controller.js | 24 ++++++++- lib/controllers/issueish-search-controller.js | 24 +++++++-- lib/controllers/remote-pr-controller.js | 19 ++++--- lib/views/issueish-list-view.js | 13 ++++- .../issueish-list-container.test.js | 16 +++++- .../issueish-list-controller.test.js | 17 ++++++ .../issueish-search-controller.test.js | 10 +++- test/controllers/remote-pr-controller.test.js | 12 +++-- test/views/issueish-list-view.test.js | 17 ++++++ 10 files changed, 182 insertions(+), 22 deletions(-) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index 642f53f2d6..f6a6bedd41 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {QueryRenderer, graphql} from 'react-relay'; import {autobind} from '../helpers'; -import {SearchPropType} from '../prop-types'; +import {SearchPropType, RemotePropType, BranchSetPropType} from '../prop-types'; import IssueishListController, {BareIssueishListController} from '../controllers/issueish-list-controller'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; @@ -12,7 +12,17 @@ export default class IssueishListContainer extends React.Component { token: PropTypes.string.isRequired, host: PropTypes.string.isRequired, + repository: PropTypes.shape({ + defaultBranchRef: PropTypes.string, + }), + search: SearchPropType.isRequired, + remote: RemotePropType.isRequired, + branches: BranchSetPropType.isRequired, + aheadCount: PropTypes.number.isRequired, + pushInProgress: PropTypes.bool.isRequired, + + onCreatePr: PropTypes.func.isRequired, } constructor(props) { @@ -25,7 +35,20 @@ export default class IssueishListContainer extends React.Component { const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, this.props.token); if (this.props.search.isNull()) { - return ; + return ( + + ); } const query = graphql` @@ -55,14 +78,35 @@ export default class IssueishListContainer extends React.Component { } if (props === null) { - return ; + return ( + + ); } return ( ); } diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index e3bea38080..3817a1c387 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {graphql, createFragmentContainer} from 'react-relay'; -import {SearchPropType} from '../prop-types'; +import {SearchPropType, RemotePropType, BranchSetPropType} from '../prop-types'; import IssueishListView from '../views/issueish-list-view'; import Issueish from '../models/issueish'; @@ -27,7 +27,18 @@ export class BareIssueishListController extends React.Component { }), ), }), + repository: PropTypes.shape({ + defaultBranchRef: PropTypes.string, + }), + search: SearchPropType.isRequired, + remote: RemotePropType.isRequired, + branches: BranchSetPropType.isRequired, + aheadCount: PropTypes.number.isRequired, + pushInProgress: PropTypes.bool.isRequired, + isLoading: PropTypes.bool.isRequired, + + onCreatePr: PropTypes.func.isRequired, }; static defaultProps = { @@ -62,10 +73,19 @@ export class BareIssueishListController extends React.Component { render() { return ( ); } diff --git a/lib/controllers/issueish-search-controller.js b/lib/controllers/issueish-search-controller.js index b2e8340e8c..313a1906c8 100644 --- a/lib/controllers/issueish-search-controller.js +++ b/lib/controllers/issueish-search-controller.js @@ -1,7 +1,7 @@ import React, {Fragment} from 'react'; import PropTypes from 'prop-types'; -import {RemotePropType, BranchPropType} from '../prop-types'; +import {RemotePropType, BranchSetPropType} from '../prop-types'; import Search from '../models/search'; import IssueishListContainer from '../containers/issueish-list-container'; @@ -10,8 +10,16 @@ export default class IssueishSearchController extends React.Component { host: PropTypes.string.isRequired, token: PropTypes.string.isRequired, + repository: PropTypes.shape({ + defaultBranchRef: PropTypes.string, + }), + remote: RemotePropType.isRequired, - currentBranch: BranchPropType.isRequired, + branches: BranchSetPropType.isRequired, + aheadCount: PropTypes.number.isRequired, + pushInProgress: PropTypes.bool.isRequired, + + onCreatePr: PropTypes.func.isRequired, } constructor(props) { @@ -23,7 +31,7 @@ export default class IssueishSearchController extends React.Component { static getDerivedStateFromProps(props) { return { searches: [ - Search.forCurrentPR(props.remote, props.currentBranch), + Search.forCurrentPR(props.remote, props.branches.getHeadBranch()), Search.inRemote(props.remote, 'Open pull requests', 'type:pr state:open'), ], }; @@ -35,9 +43,19 @@ export default class IssueishSearchController extends React.Component { {this.state.searches.map(search => ( ))} diff --git a/lib/controllers/remote-pr-controller.js b/lib/controllers/remote-pr-controller.js index 8d161f98fd..a663dc2a4f 100644 --- a/lib/controllers/remote-pr-controller.js +++ b/lib/controllers/remote-pr-controller.js @@ -16,13 +16,13 @@ export default class RemotePrController extends React.Component { static propTypes = { loginModel: PropTypes.object.isRequired, host: PropTypes.string, // fully qualified URI to the API endpoint, e.g. 'https://api.github.com' + remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, - selectedPrUrl: PropTypes.string, + aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, - onSelectPr: PropTypes.func.isRequired, - onUnpinPr: PropTypes.func.isRequired, + onPushBranch: PropTypes.func.isRequired, } @@ -33,7 +33,7 @@ export default class RemotePrController extends React.Component { constructor(props) { super(props); - autobind(this, 'fetchData', 'handleLogin', 'handleLogout', 'handleCreatePr'); + autobind(this, 'fetchData', 'handleLogin', 'handleLogout', 'onCreatePr'); } fetchData(loginModel) { @@ -69,8 +69,15 @@ export default class RemotePrController extends React.Component { ); } @@ -86,7 +93,7 @@ export default class RemotePrController extends React.Component { this.props.loginModel.removeToken(this.props.host); } - async handleCreatePr() { + async onCreatePr() { const currentBranch = this.props.branches.getHeadBranch(); const upstream = currentBranch.getUpstream(); if (!upstream.isPresent() || this.props.aheadCount > 0) { diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 0c63e71fd7..2fc3fc6b38 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -1,7 +1,7 @@ import React, {Fragment} from 'react'; import PropTypes from 'prop-types'; -import {SearchPropType} from '../prop-types'; +import {SearchPropType, RemotePropType, BranchSetPropType} from '../prop-types'; import {autobind} from '../helpers'; import Accordion from './accordion'; import Octicon from '../atom/octicon'; @@ -12,6 +12,17 @@ export default class IssueishListView extends React.Component { isLoading: PropTypes.bool.isRequired, total: PropTypes.number.isRequired, issueishes: PropTypes.arrayOf(PropTypes.any).isRequired, + + repository: PropTypes.shape({ + defaultBranchRef: PropTypes.string, + }), + + remote: RemotePropType.isRequired, + branches: BranchSetPropType.isRequired, + aheadCount: PropTypes.number.isRequired, + pushInProgress: PropTypes.bool.isRequired, + + onCreatePr: PropTypes.func.isRequired, } constructor(props) { diff --git a/test/containers/issueish-list-container.test.js b/test/containers/issueish-list-container.test.js index 260372c0de..5aab0ce753 100644 --- a/test/containers/issueish-list-container.test.js +++ b/test/containers/issueish-list-container.test.js @@ -3,15 +3,29 @@ import {shallow, mount} from 'enzyme'; import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import Search, {nullSearch} from '../../lib/models/search'; +import Remote from '../../lib/models/remote'; +import Branch, {nullBranch} from '../../lib/models/branch'; +import BranchSet from '../../lib/models/branch-set'; import IssueishListContainer from '../../lib/containers/issueish-list-container'; describe('IssueishListContainer', function() { function buildApp(overrideProps = {}) { + const origin = new Remote('origin', 'git@github.com:atom/github.git'); + const branch = new Branch('master', nullBranch, nullBranch, true); + const branchSet = new BranchSet(); + branchSet.add(branch); + return ( ); diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index 12ed118ca7..4c189e8483 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -2,13 +2,30 @@ import React from 'react'; import {shallow} from 'enzyme'; import Issueish from '../../lib/models/issueish'; +import Search from '../../lib/models/search'; +import Remote from '../../lib/models/remote'; +import BranchSet from '../../lib/models/branch-set'; +import Branch, {nullBranch} from '../../lib/models/branch'; import {BareIssueishListController} from '../../lib/controllers/issueish-list-controller'; describe('IssueishListController', function() { function buildApp(overrideProps = {}) { + const branches = new BranchSet(); + branches.add(new Branch('master', nullBranch, nullBranch, true)); + return ( {}} + {...overrideProps} /> ); diff --git a/test/controllers/issueish-search-controller.test.js b/test/controllers/issueish-search-controller.test.js index 9e09d6706e..6cf52eefc7 100644 --- a/test/controllers/issueish-search-controller.test.js +++ b/test/controllers/issueish-search-controller.test.js @@ -4,6 +4,7 @@ import {shallow} from 'enzyme'; import IssueishSearchController from '../../lib/controllers/issueish-search-controller'; import Remote from '../../lib/models/remote'; import Branch from '../../lib/models/branch'; +import BranchSet from '../../lib/models/branch-set'; describe('IssueishSearchController', function() { const origin = new Remote('origin', 'git@github.com:atom/github.git'); @@ -11,13 +12,20 @@ describe('IssueishSearchController', function() { const master = new Branch('master', upstreamMaster); function buildApp(overloadProps = {}) { + const branches = new BranchSet(); + branches.add(master); + return ( {}} {...overloadProps} /> diff --git a/test/controllers/remote-pr-controller.test.js b/test/controllers/remote-pr-controller.test.js index 192987b4a2..c6cf6f4317 100644 --- a/test/controllers/remote-pr-controller.test.js +++ b/test/controllers/remote-pr-controller.test.js @@ -44,13 +44,17 @@ describe('RemotePrController', function() { return ( ); @@ -96,6 +100,6 @@ describe('RemotePrController', function() { assert.strictEqual(controller.prop('token'), '1234'); assert.strictEqual(controller.prop('host'), 'https://api.github.com'); assert.strictEqual(controller.prop('remote'), remote); - assert.strictEqual(controller.prop('currentBranch'), currentBranch); + assert.strictEqual(controller.prop('branches'), branchSet); }); }); diff --git a/test/views/issueish-list-view.test.js b/test/views/issueish-list-view.test.js index 6c6cc1f6aa..098853232c 100644 --- a/test/views/issueish-list-view.test.js +++ b/test/views/issueish-list-view.test.js @@ -1,17 +1,34 @@ import React from 'react'; import {shallow} from 'enzyme'; +import Remote from '../../lib/models/remote'; +import Branch, {nullBranch} from '../../lib/models/branch'; +import BranchSet from '../../lib/models/branch-set'; import Search from '../../lib/models/search'; import IssueishListView from '../../lib/views/issueish-list-view'; describe('IssueishListView', function() { function buildApp(overrideProps = {}) { + const origin = new Remote('origin', 'git@github.com:atom/github.git'); + const branch = new Branch('master', nullBranch, nullBranch, true); + const branchSet = new BranchSet(); + branchSet.add(branch); + return ( {}} + {...overrideProps} /> ); From 42b686abee42173894cfc45354496b799b6d6c02 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 10:55:28 -0400 Subject: [PATCH 0193/4847] Rename RemotePrController to RemoteController --- lib/controllers/github-tab-controller.js | 4 ++-- .../{remote-pr-controller.js => remote-controller.js} | 2 +- ...mote-pr-controller.test.js => remote-controller.test.js} | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) rename lib/controllers/{remote-pr-controller.js => remote-controller.js} (98%) rename test/controllers/{remote-pr-controller.test.js => remote-controller.test.js} (95%) diff --git a/lib/controllers/github-tab-controller.js b/lib/controllers/github-tab-controller.js index 9b4a1dc41c..794793d67d 100644 --- a/lib/controllers/github-tab-controller.js +++ b/lib/controllers/github-tab-controller.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import yubikiri from 'yubikiri'; import RemoteSelectorView from '../views/remote-selector-view'; -import RemotePrController from './remote-pr-controller'; +import RemoteController from './remote-controller'; import GithubLoginModel from '../models/github-login-model'; import ObserveModel from '../views/observe-model'; import {autobind} from '../helpers'; @@ -78,7 +78,7 @@ export default class GithubTabController extends React.Component {
    {/* only supporting GH.com for now, hardcoded values */} {remote && - this.handleSelectPrByUrl(prUrl, currentBranch)} diff --git a/lib/controllers/remote-pr-controller.js b/lib/controllers/remote-controller.js similarity index 98% rename from lib/controllers/remote-pr-controller.js rename to lib/controllers/remote-controller.js index a663dc2a4f..1edaa42bf2 100644 --- a/lib/controllers/remote-pr-controller.js +++ b/lib/controllers/remote-controller.js @@ -12,7 +12,7 @@ import {nullRemote} from '../models/remote'; import IssueishSearchController from './issueish-search-controller'; import {autobind} from '../helpers'; -export default class RemotePrController extends React.Component { +export default class RemoteController extends React.Component { static propTypes = { loginModel: PropTypes.object.isRequired, host: PropTypes.string, // fully qualified URI to the API endpoint, e.g. 'https://api.github.com' diff --git a/test/controllers/remote-pr-controller.test.js b/test/controllers/remote-controller.test.js similarity index 95% rename from test/controllers/remote-pr-controller.test.js rename to test/controllers/remote-controller.test.js index c6cf6f4317..53ec0c3cc4 100644 --- a/test/controllers/remote-pr-controller.test.js +++ b/test/controllers/remote-controller.test.js @@ -7,9 +7,9 @@ import Branch, {nullBranch} from '../../lib/models/branch'; import Remote from '../../lib/models/remote'; import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import {InMemoryStrategy, UNAUTHENTICATED, INSUFFICIENT} from '../../lib/shared/keytar-strategy'; -import RemotePrController from '../../lib/controllers/remote-pr-controller'; +import RemoteController from '../../lib/controllers/remote-controller'; -describe('RemotePrController', function() { +describe('RemoteController', function() { let loginModel, remote, branchSet, currentBranch; beforeEach(function() { @@ -43,7 +43,7 @@ describe('RemotePrController', function() { const noop = () => {}; return ( - Date: Thu, 14 Jun 2018 11:00:46 -0400 Subject: [PATCH 0194/4847] Pass isLoading=false when not loading --- lib/containers/issueish-list-container.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index f6a6bedd41..239d1658c9 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -104,7 +104,7 @@ export default class IssueishListContainer extends React.Component { branches={this.props.branches} aheadCount={this.props.aheadCount} pushInProgress={this.props.pushInProgress} - isLoading={true} + isLoading={false} onCreatePr={this.props.onCreatePr} /> From 6785a37908d2953f48905373b1dd9f51438f8256 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 11:00:57 -0400 Subject: [PATCH 0195/4847] Accept isLoading from props instead of state --- lib/controllers/issueish-list-controller.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index 3817a1c387..0e512e1e2e 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -57,14 +57,12 @@ export class BareIssueishListController extends React.Component { static getDerivedStateFromProps(props, state) { if (props.results === null) { return { - isLoading: true, total: 0, issueishes: [], }; } return { - isLoading: false, total: props.results.issueCount, issueishes: props.results.nodes.map(node => new Issueish(node)), }; @@ -74,7 +72,7 @@ export class BareIssueishListController extends React.Component { return ( Date: Thu, 14 Jun 2018 11:01:04 -0400 Subject: [PATCH 0196/4847] onCreatePr is required --- test/containers/issueish-list-container.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/containers/issueish-list-container.test.js b/test/containers/issueish-list-container.test.js index 5aab0ce753..728ba1878d 100644 --- a/test/containers/issueish-list-container.test.js +++ b/test/containers/issueish-list-container.test.js @@ -26,6 +26,8 @@ describe('IssueishListContainer', function() { aheadCount={0} pushInProgress={false} + onCreatePr={() => {}} + {...overrideProps} /> ); From 46cbe6616e229de061f15f05b7e28bfb709d61a4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 11:01:18 -0400 Subject: [PATCH 0197/4847] Adjust tests for external isLoading prop --- test/controllers/issueish-list-controller.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index 4c189e8483..449253ebcf 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -23,6 +23,7 @@ describe('IssueishListController', function() { branches={branches} aheadCount={0} pushInProgress={false} + isLoading={false} onCreatePr={() => {}} @@ -32,7 +33,7 @@ describe('IssueishListController', function() { } it('renders an IssueishListView in a loading state', function() { - const wrapper = shallow(buildApp()); + const wrapper = shallow(buildApp({isLoading: true})); const view = wrapper.find('IssueishListView'); assert.isTrue(view.prop('isLoading')); From a5f70d8b9b38fc613cbba7ba627b022abd22b8d9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 13:06:14 -0400 Subject: [PATCH 0198/4847] Extract a RemoteContainer from RemoteController --- .../remoteContainerQuery.graphql.js | 170 ++++++++++++++++++ lib/containers/remote-container.js | 118 ++++++++++++ test/containers/remote-container.test.js | 119 ++++++++++++ 3 files changed, 407 insertions(+) create mode 100644 lib/containers/__generated__/remoteContainerQuery.graphql.js create mode 100644 lib/containers/remote-container.js create mode 100644 test/containers/remote-container.test.js diff --git a/lib/containers/__generated__/remoteContainerQuery.graphql.js b/lib/containers/__generated__/remoteContainerQuery.graphql.js new file mode 100644 index 0000000000..ebae27e2e1 --- /dev/null +++ b/lib/containers/__generated__/remoteContainerQuery.graphql.js @@ -0,0 +1,170 @@ +/** + * @flow + * @relayHash 31f49e2054e5af61819d6f3ca8228979 + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest } from 'relay-runtime'; +export type remoteContainerQueryVariables = {| + owner: string, + name: string, +|}; +export type remoteContainerQueryResponse = {| + +repository: ?{| + +defaultBranchRef: ?{| + +prefix: string, + +name: string, + |} + |} +|}; +*/ + + +/* +query remoteContainerQuery( + $owner: String! + $name: String! +) { + repository(owner: $owner, name: $name) { + defaultBranchRef { + prefix + name + id + } + id + } +} +*/ + +const node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "LocalArgument", + "name": "owner", + "type": "String!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "name", + "type": "String!", + "defaultValue": null + } +], +v1 = [ + { + "kind": "Variable", + "name": "name", + "variableName": "name", + "type": "String!" + }, + { + "kind": "Variable", + "name": "owner", + "variableName": "owner", + "type": "String!" + } +], +v2 = { + "kind": "ScalarField", + "alias": null, + "name": "prefix", + "args": null, + "storageKey": null +}, +v3 = { + "kind": "ScalarField", + "alias": null, + "name": "name", + "args": null, + "storageKey": null +}, +v4 = { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null +}; +return { + "kind": "Request", + "operationKind": "query", + "name": "remoteContainerQuery", + "id": null, + "text": "query remoteContainerQuery(\n $owner: String!\n $name: String!\n) {\n repository(owner: $owner, name: $name) {\n defaultBranchRef {\n prefix\n name\n id\n }\n id\n }\n}\n", + "metadata": {}, + "fragment": { + "kind": "Fragment", + "name": "remoteContainerQuery", + "type": "Query", + "metadata": null, + "argumentDefinitions": v0, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": v1, + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "defaultBranchRef", + "storageKey": null, + "args": null, + "concreteType": "Ref", + "plural": false, + "selections": [ + v2, + v3 + ] + } + ] + } + ] + }, + "operation": { + "kind": "Operation", + "name": "remoteContainerQuery", + "argumentDefinitions": v0, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": v1, + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "defaultBranchRef", + "storageKey": null, + "args": null, + "concreteType": "Ref", + "plural": false, + "selections": [ + v2, + v3, + v4 + ] + }, + v4 + ] + } + ] + } +}; +})(); +// prettier-ignore +(node/*: any*/).hash = '491900781f0ba3de667b2d5262aa5ab4'; +module.exports = node; diff --git a/lib/containers/remote-container.js b/lib/containers/remote-container.js new file mode 100644 index 0000000000..f8c8eec522 --- /dev/null +++ b/lib/containers/remote-container.js @@ -0,0 +1,118 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {QueryRenderer, graphql} from 'react-relay'; + +import {autobind} from '../helpers'; +import {RemotePropType, BranchSetPropType} from '../prop-types'; +import RelayNetworkLayerManager from '../relay-network-layer-manager'; +import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; +import RemoteController from '../controllers/remote-controller'; +import ObserveModel from '../views/observe-model'; +import LoadingView from '../views/loading-view'; +import GithubLoginView from '../views/github-login-view'; + +export default class RemoteContainer extends React.Component { + static propTypes = { + loginModel: PropTypes.object.isRequired, + + host: PropTypes.string.isRequired, + + remote: RemotePropType.isRequired, + branches: BranchSetPropType.isRequired, + + aheadCount: PropTypes.number, + pushInProgress: PropTypes.bool.isRequired, + + onPushBranch: PropTypes.func.isRequired, + } + + constructor(props) { + super(props); + + autobind(this, 'fetchToken', 'renderWithToken', 'renderWithResult', 'handleLogin'); + } + + fetchToken(loginModel) { + return loginModel.getToken(this.props.host); + } + + render() { + return ( + + {this.renderWithToken} + + ); + } + + renderWithToken(token) { + if (token === null) { + return ; + } + + if (token === UNAUTHENTICATED) { + return ; + } + + if (token === INSUFFICIENT) { + return ( + +

    + Your token no longer has sufficient authorizations. Please re-authenticate and generate a new one. +

    +
    + ); + } + + const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, token); + const query = graphql` + query remoteContainerQuery($owner: String!, $name: String!) { + repository(owner: $owner, name: $name) { + defaultBranchRef { + prefix + name + } + } + } + `; + const variables = { + owner: this.props.remote.getOwner(), + name: this.props.remote.getRepo(), + }; + + return ( + this.renderWithResult(result, token)} + /> + ); + } + + renderWithResult({error, props}, token) { + if (props === null) { + return ; + } + + return ( + + ); + } + + handleLogin(token) { + this.props.loginModel.setToken(this.props.host, token); + } +} diff --git a/test/containers/remote-container.test.js b/test/containers/remote-container.test.js new file mode 100644 index 0000000000..4017e0756d --- /dev/null +++ b/test/containers/remote-container.test.js @@ -0,0 +1,119 @@ +import React from 'react'; +import {mount} from 'enzyme'; + +import Remote from '../../lib/models/remote'; +import Branch, {nullBranch} from '../../lib/models/branch'; +import BranchSet from '../../lib/models/branch-set'; +import GithubLoginModel from '../../lib/models/github-login-model'; +import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; +import RemoteContainer from '../../lib/containers/remote-container'; +import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; + +describe('RemoteContainer', function() { + let model; + + beforeEach(function() { + model = new GithubLoginModel(InMemoryStrategy); + }); + + function buildApp(overrideProps = {}) { + const origin = new Remote('origin', 'git@github.com:atom/github.git'); + const branch = new Branch('master', nullBranch, nullBranch, true); + const branchSet = new BranchSet(); + branchSet.add(branch); + + return ( + {}} + + {...overrideProps} + /> + ); + } + + function expectSuccessfulQuery() { + return expectRelayQuery({ + name: 'remoteContainerQuery', + variables: { + owner: 'atom', + name: 'github', + }, + }, { + repository: { + defaultBranchRef: { + prefix: 'refs/heads/', + name: 'master', + id: 'ref0', + }, + id: 'repo0', + }, + }); + } + + it('renders a loading spinner while the token is being fetched', function() { + const wrapper = mount(buildApp()); + assert.isTrue(wrapper.find('LoadingView').exists()); + }); + + it('renders a loading spinner while the GraphQL query is being performed', async function() { + expectSuccessfulQuery(); + model.setToken('https://api.github.com', '1234'); + sinon.spy(model, 'getToken'); + sinon.stub(model, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); + + const wrapper = mount(buildApp()); + await model.getToken.returnValues[0]; + + assert.isTrue(wrapper.find('LoadingView').exists()); + }); + + it('renders a login prompt if no token is found', async function() { + sinon.spy(model, 'getToken'); + + const wrapper = mount(buildApp()); + await model.getToken.returnValues[0]; + + assert.isTrue(wrapper.update().find('GithubLoginView').exists()); + }); + + it('renders a login prompt if the token has insufficient OAuth scopes', async function() { + model.setToken('https://api.github.com', '1234'); + sinon.spy(model, 'getToken'); + sinon.stub(model, 'getScopes').resolves([]); + + const wrapper = mount(buildApp()); + await model.getToken.returnValues[0]; + + assert.match(wrapper.update().find('GithubLoginView').find('p').text(), /sufficient/); + }); + + it('renders the controller once results have arrived', async function() { + const {resolve} = expectSuccessfulQuery(); + model.setToken('https://api.github.com', '1234'); + sinon.stub(model, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); + + const wrapper = mount(buildApp()); + + resolve(); + + await assert.async.isTrue(wrapper.update().find('RemoteController').exists()); + const controller = wrapper.find('RemoteController'); + assert.strictEqual(controller.prop('token'), '1234'); + assert.deepEqual(controller.prop('repository'), { + defaultBranchRef: { + prefix: 'refs/heads/', + name: 'master', + }, + }); + }); +}); From c89c943b434d5577a34508a01d96d5fd2af4c2c8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 13:26:48 -0400 Subject: [PATCH 0199/4847] I had the wrong schema for defaultBranchRef --- lib/containers/issueish-list-container.js | 5 ++++- lib/controllers/issueish-list-controller.js | 5 ++++- lib/controllers/issueish-search-controller.js | 5 ++++- lib/views/issueish-list-view.js | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index 239d1658c9..a13982735a 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -13,7 +13,10 @@ export default class IssueishListContainer extends React.Component { host: PropTypes.string.isRequired, repository: PropTypes.shape({ - defaultBranchRef: PropTypes.string, + defaultBranchRef: PropTypes.shape({ + prefix: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + }), }), search: SearchPropType.isRequired, diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index 0e512e1e2e..6a102c523d 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -28,7 +28,10 @@ export class BareIssueishListController extends React.Component { ), }), repository: PropTypes.shape({ - defaultBranchRef: PropTypes.string, + defaultBranchRef: PropTypes.shape({ + prefix: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + }), }), search: SearchPropType.isRequired, diff --git a/lib/controllers/issueish-search-controller.js b/lib/controllers/issueish-search-controller.js index 313a1906c8..62e6a17fa5 100644 --- a/lib/controllers/issueish-search-controller.js +++ b/lib/controllers/issueish-search-controller.js @@ -11,7 +11,10 @@ export default class IssueishSearchController extends React.Component { token: PropTypes.string.isRequired, repository: PropTypes.shape({ - defaultBranchRef: PropTypes.string, + defaultBranchRef: PropTypes.shape({ + prefix: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + }), }), remote: RemotePropType.isRequired, diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 2fc3fc6b38..6f2cabb86c 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -14,7 +14,10 @@ export default class IssueishListView extends React.Component { issueishes: PropTypes.arrayOf(PropTypes.any).isRequired, repository: PropTypes.shape({ - defaultBranchRef: PropTypes.string, + defaultBranchRef: PropTypes.shape({ + prefix: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + }), }), remote: RemotePropType.isRequired, From bc69723e04ce5b90dfcad717202e2a4d3db63481 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 13:32:27 -0400 Subject: [PATCH 0200/4847] Explicitly pass a null Repository when we don't care about it --- test/containers/issueish-list-container.test.js | 6 ++++-- test/controllers/issueish-search-controller.test.js | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/containers/issueish-list-container.test.js b/test/containers/issueish-list-container.test.js index 728ba1878d..c65ad2da28 100644 --- a/test/containers/issueish-list-container.test.js +++ b/test/containers/issueish-list-container.test.js @@ -17,8 +17,10 @@ describe('IssueishListContainer', function() { return ( Date: Thu, 14 Jun 2018 13:32:44 -0400 Subject: [PATCH 0201/4847] Add handleLogout for symmetry --- lib/containers/remote-container.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/containers/remote-container.js b/lib/containers/remote-container.js index f8c8eec522..a1755dbe84 100644 --- a/lib/containers/remote-container.js +++ b/lib/containers/remote-container.js @@ -29,7 +29,7 @@ export default class RemoteContainer extends React.Component { constructor(props) { super(props); - autobind(this, 'fetchToken', 'renderWithToken', 'renderWithResult', 'handleLogin'); + autobind(this, 'fetchToken', 'renderWithToken', 'renderWithResult', 'handleLogin', 'handleLogout'); } fetchToken(loginModel) { @@ -115,4 +115,8 @@ export default class RemoteContainer extends React.Component { handleLogin(token) { this.props.loginModel.setToken(this.props.host, token); } + + handleLogout() { + this.props.loginModel.removeToken(this.props.host); + } } From b954c291be66c16fb9211ff1ac2ba2f69ca570ef Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 13:33:08 -0400 Subject: [PATCH 0202/4847] Expect the downstream Issueish query --- test/containers/remote-container.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/containers/remote-container.test.js b/test/containers/remote-container.test.js index 4017e0756d..4c4f0515a9 100644 --- a/test/containers/remote-container.test.js +++ b/test/containers/remote-container.test.js @@ -60,6 +60,20 @@ describe('RemoteContainer', function() { }); } + function expectEmptyIssueishQuery() { + return expectRelayQuery({ + name: 'issueishListContainerQuery', + variables: { + query: 'repo:atom/github type:pr state:open', + }, + }, { + search: { + issueCount: 0, + nodes: [], + }, + }); + } + it('renders a loading spinner while the token is being fetched', function() { const wrapper = mount(buildApp()); assert.isTrue(wrapper.find('LoadingView').exists()); @@ -99,6 +113,7 @@ describe('RemoteContainer', function() { it('renders the controller once results have arrived', async function() { const {resolve} = expectSuccessfulQuery(); + expectEmptyIssueishQuery(); model.setToken('https://api.github.com', '1234'); sinon.stub(model, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); From 8499d670f32fa47d3a5b03003ebe7631519898fe Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 13:35:24 -0400 Subject: [PATCH 0203/4847] Remove RemoteContainer functionality from RemoteController --- lib/controllers/remote-controller.js | 87 ++++++---------------- test/controllers/remote-controller.test.js | 68 ++--------------- 2 files changed, 29 insertions(+), 126 deletions(-) diff --git a/lib/controllers/remote-controller.js b/lib/controllers/remote-controller.js index 1edaa42bf2..2819abff41 100644 --- a/lib/controllers/remote-controller.js +++ b/lib/controllers/remote-controller.js @@ -1,21 +1,22 @@ import React from 'react'; import PropTypes from 'prop-types'; -import yubikiri from 'yubikiri'; import {shell} from 'electron'; +import {autobind} from '../helpers'; import {RemotePropType, BranchSetPropType} from '../prop-types'; -import LoadingView from '../views/loading-view'; -import GithubLoginView from '../views/github-login-view'; -import ObserveModel from '../views/observe-model'; -import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; -import {nullRemote} from '../models/remote'; import IssueishSearchController from './issueish-search-controller'; -import {autobind} from '../helpers'; export default class RemoteController extends React.Component { static propTypes = { - loginModel: PropTypes.object.isRequired, - host: PropTypes.string, // fully qualified URI to the API endpoint, e.g. 'https://api.github.com' + host: PropTypes.string.isRequired, + token: PropTypes.string.isRequired, + + repository: PropTypes.shape({ + defaultBranchRef: PropTypes.shape({ + prefix: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + }), + }), remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, @@ -26,71 +27,27 @@ export default class RemoteController extends React.Component { onPushBranch: PropTypes.func.isRequired, } - static defaultProps = { - host: 'https://api.github.com', - remote: nullRemote, - } - constructor(props) { super(props); - autobind(this, 'fetchData', 'handleLogin', 'handleLogout', 'onCreatePr'); - } - - fetchData(loginModel) { - return yubikiri({ - token: loginModel.getToken(this.props.host), - }); + autobind(this, 'onCreatePr'); } render() { return ( - - {data => this.renderWithData(data || {token: null})} - - ); - } - - renderWithData({token}) { - let inner; - if (token === null) { - inner = ; - } else if (token === UNAUTHENTICATED) { - inner = ; - } else if (token === INSUFFICIENT) { - inner = ( - -

    - Your token no longer has sufficient authorizations. Please re-authenticate and generate a new one. -

    -
    - ); - } else { - inner = ( - - ); - } - - return
    {inner}
    ; - } - - handleLogin(token) { - this.props.loginModel.setToken(this.props.host, token); - } - - handleLogout() { - this.props.loginModel.removeToken(this.props.host); + onCreatePr={this.onCreatePr} + /> + ); } async onCreatePr() { diff --git a/test/controllers/remote-controller.test.js b/test/controllers/remote-controller.test.js index 53ec0c3cc4..1f5d41faf6 100644 --- a/test/controllers/remote-controller.test.js +++ b/test/controllers/remote-controller.test.js @@ -1,42 +1,19 @@ import React from 'react'; -import {mount} from 'enzyme'; +import {shallow} from 'enzyme'; -import GithubLoginModel from '../../lib/models/github-login-model'; import BranchSet from '../../lib/models/branch-set'; import Branch, {nullBranch} from '../../lib/models/branch'; import Remote from '../../lib/models/remote'; -import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; -import {InMemoryStrategy, UNAUTHENTICATED, INSUFFICIENT} from '../../lib/shared/keytar-strategy'; import RemoteController from '../../lib/controllers/remote-controller'; describe('RemoteController', function() { - let loginModel, remote, branchSet, currentBranch; + let remote, branchSet, currentBranch; beforeEach(function() { - loginModel = new GithubLoginModel(InMemoryStrategy); - sinon.stub(loginModel, 'getToken').returns(Promise.resolve('1234')); - remote = new Remote('origin', 'git@github.com:atom/github'); currentBranch = new Branch('master', nullBranch, nullBranch, true); branchSet = new BranchSet(); branchSet.add(currentBranch); - - expectRelayQuery({ - name: 'issueishListContainerQuery', - variables: {query: 'repo:atom/github type:pr state:open'}, - }, { - repository: { - defaultBranchRef: { - prefix: 'refs/heads', - name: 'master', - }, - pullRequests: { - totalCount: 0, - edges: [], - }, - id: '1', - }, - }); }); function createApp(props = {}) { @@ -44,8 +21,10 @@ describe('RemoteController', function() { return ( Date: Thu, 14 Jun 2018 13:35:52 -0400 Subject: [PATCH 0204/4847] Port a CreatePullRequestTile from the existing "publish PR" work --- lib/views/create-pull-request-tile.js | 148 ++++++++++++++++++++++++++ lib/views/issueish-list-view.js | 23 +++- 2 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 lib/views/create-pull-request-tile.js diff --git a/lib/views/create-pull-request-tile.js b/lib/views/create-pull-request-tile.js new file mode 100644 index 0000000000..d76dfa6790 --- /dev/null +++ b/lib/views/create-pull-request-tile.js @@ -0,0 +1,148 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import {RemotePropType, BranchSetPropType} from '../prop-types'; + +export default class CreatePullRequestTile extends React.Component { + static propTypes = { + repository: PropTypes.shape({ + defaultBranchRef: PropTypes.shape({ + prefix: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + }), + }), + + remote: RemotePropType.isRequired, + branches: BranchSetPropType.isRequired, + aheadCount: PropTypes.number.isRequired, + pushInProgress: PropTypes.bool.isRequired, + + onCreatePr: PropTypes.func.isRequired, + } + + render() { + if (this.isRepositoryNotFound()) { + return ( +
    + Repository not found for the remote {this.props.remote.getName()}. + Do you need to update your remote URL? +
    + ); + } + + if (this.isDetachedHead()) { + return ( +
    + You are not currently on any branch. + Create a new branch  + to share your work with a pull request. +
    + ); + } + + if (this.hasNoDefaultRef()) { + return ( +
    + The repository at remote {this.props.remote.getName()} is + empty. Push a main branch to begin sharing your work. +
    + ); + } + + if (this.isOnDefaultRef()) { + return ( +
    + You are currently on your repository's default branch. + Create a new branch  + to share your work with a pull request. +
    + ); + } + + if (this.isSameAsDefaultRef()) { + return ( +
    + Your current branch has not moved from the repository's default branch. + Make some commits  + to share your work with a pull request. +
    + ); + } + + let message = 'Open new pull request'; + let disable = false; + const differentRemote = this.pushesToDifferentRemote(); + if (this.props.pushInProgress) { + message = 'Pushing...'; + disable = true; + } else if (!this.hasUpstreamBranch() || differentRemote) { + message = 'Publish + open new pull request'; + } else if (this.props.aheadCount > 0) { + message = 'Push + open new pull request'; + } + + return ( +
    + {differentRemote && +
    + Your current branch is configured to push to the remote + {this.props.branches.getHeadBranch().getPush().getRemoteName()}. + Publish it to {this.props.remote.getName()} instead? +
    + } +

    + +

    +
    + ); + } + + isRepositoryNotFound() { + return !this.props.repository; + } + + isDetachedHead() { + return !this.props.branches.getHeadBranch().isPresent(); + } + + hasNoDefaultRef() { + return !this.props.repository.defaultBranchRef; + } + + isOnDefaultRef() { + if (!this.props.repository) { return false; } + const defaultRef = this.props.repository.defaultBranchRef; + if (!defaultRef) { return false; } + + const currentBranch = this.props.branches.getHeadBranch(); + return currentBranch.getPush().getRemoteRef() === `${defaultRef.prefix}${defaultRef.name}`; + } + + isSameAsDefaultRef() { + if (!this.props.repository) { return false; } + const defaultRef = this.props.repository.defaultBranchRef; + if (!defaultRef) { return false; } + + const currentBranch = this.props.branches.getHeadBranch(); + const mainBranches = this.props.branches.getPushSources( + this.props.remote.getName(), `${defaultRef.prefix}${defaultRef.name}`); + return mainBranches.some(branch => branch.getSha() === currentBranch.getSha()); + } + + pushesToDifferentRemote() { + const p = this.props.branches.getHeadBranch().getPush(); + if (!p.isRemoteTracking()) { return false; } + + const pushRemoteName = p.getRemoteName(); + return pushRemoteName !== this.props.remote.getName(); + } + + hasUpstreamBranch() { + return this.props.branches.getHeadBranch().getUpstream().isPresent(); + } +} diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 6f2cabb86c..4a95e311ed 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import {SearchPropType, RemotePropType, BranchSetPropType} from '../prop-types'; import {autobind} from '../helpers'; import Accordion from './accordion'; +import CreatePullRequestTile from './create-pull-request-tile'; import Octicon from '../atom/octicon'; export default class IssueishListView extends React.Component { @@ -31,7 +32,7 @@ export default class IssueishListView extends React.Component { constructor(props) { super(props); - autobind(this, 'renderIssueish'); + autobind(this, 'renderIssueish', 'renderEmptyTile'); } render() { @@ -39,7 +40,8 @@ export default class IssueishListView extends React.Component { + results={this.props.issueishes} + emptyComponent={this.renderEmptyTile}> {this.renderIssueish} ); @@ -66,4 +68,21 @@ export default class IssueishListView extends React.Component { ); } + + renderEmptyTile() { + if (this.props.search.showCreateOnEmpty()) { + return ( + + ); + } + + return null; + } } From d76743d9975b128e297f526b1d4e3c3c52506c76 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 13:38:57 -0400 Subject: [PATCH 0205/4847] Render the RemoteContainer in GithubTabController --- lib/controllers/github-tab-controller.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/controllers/github-tab-controller.js b/lib/controllers/github-tab-controller.js index 794793d67d..a95ccb9154 100644 --- a/lib/controllers/github-tab-controller.js +++ b/lib/controllers/github-tab-controller.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import yubikiri from 'yubikiri'; import RemoteSelectorView from '../views/remote-selector-view'; -import RemoteController from './remote-controller'; +import RemoteContainer from '../containers/remote-container'; import GithubLoginModel from '../models/github-login-model'; import ObserveModel from '../views/observe-model'; import {autobind} from '../helpers'; @@ -78,12 +78,10 @@ export default class GithubTabController extends React.Component {
    {/* only supporting GH.com for now, hardcoded values */} {remote && - this.handleSelectPrByUrl(prUrl, currentBranch)} selectedPrUrl={selectedPrUrl} - onUnpinPr={() => this.handleUnpinPr(currentBranch)} onPushBranch={() => this.handlePushBranch(currentBranch, remote)} remote={remote} branches={branches} From f3fa2bfc78b7ddb68904a498fc15da374ede30de Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 13:42:46 -0400 Subject: [PATCH 0206/4847] Move RemotePrController styles to github-IssueishSearch --- lib/controllers/issueish-search-controller.js | 4 ++-- styles/issueish-search.less | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 styles/issueish-search.less diff --git a/lib/controllers/issueish-search-controller.js b/lib/controllers/issueish-search-controller.js index 62e6a17fa5..2ae50372c1 100644 --- a/lib/controllers/issueish-search-controller.js +++ b/lib/controllers/issueish-search-controller.js @@ -42,7 +42,7 @@ export default class IssueishSearchController extends React.Component { render() { return ( - +
    {this.state.searches.map(search => ( ))} - +
    ); } } diff --git a/styles/issueish-search.less b/styles/issueish-search.less new file mode 100644 index 0000000000..d9010602c5 --- /dev/null +++ b/styles/issueish-search.less @@ -0,0 +1,9 @@ +@import 'variables'; + +.github-IssueishSearch { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + overflow-y: auto; +} From 9a99c1ec1a3222c54d059bf5b09ff32dd714c0fb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 14:06:15 -0400 Subject: [PATCH 0207/4847] Developer art: go :art: --- styles/issuesish-list-view.less | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/styles/issuesish-list-view.less b/styles/issuesish-list-view.less index f482ddd3b0..6aea5880d5 100644 --- a/styles/issuesish-list-view.less +++ b/styles/issuesish-list-view.less @@ -63,3 +63,11 @@ } } + +.github-CreatePullRequestTile { + &-message, + &-controls { + padding: @component-padding; + text-align: center; + } +} From 0fa1b39120b3c5440089a43249a0bc9b5815b9b8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 14:06:22 -0400 Subject: [PATCH 0208/4847] Some spacing issues --- lib/views/create-pull-request-tile.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/views/create-pull-request-tile.js b/lib/views/create-pull-request-tile.js index d76dfa6790..48e38b6528 100644 --- a/lib/views/create-pull-request-tile.js +++ b/lib/views/create-pull-request-tile.js @@ -34,7 +34,7 @@ export default class CreatePullRequestTile extends React.Component { return (
    You are not currently on any branch. - Create a new branch  +  Create a new branch  to share your work with a pull request.
    ); @@ -53,7 +53,7 @@ export default class CreatePullRequestTile extends React.Component { return (
    You are currently on your repository's default branch. - Create a new branch  +  Create a new branch  to share your work with a pull request.
    ); @@ -63,7 +63,7 @@ export default class CreatePullRequestTile extends React.Component { return (
    Your current branch has not moved from the repository's default branch. - Make some commits  +  Make some commits  to share your work with a pull request.
    ); From 371b16dc2a5aa8ff2b5c824099ca63dc63a1a178 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 14:06:30 -0400 Subject: [PATCH 0209/4847] Pass attrs to inRemote searches --- lib/models/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/search.js b/lib/models/search.js index d6a3dc2699..abc0f3ff31 100644 --- a/lib/models/search.js +++ b/lib/models/search.js @@ -42,7 +42,7 @@ export default class Search { return new this(name, '', {...attrs, [NULL]: true}); } - return new this(name, `repo:${remote.getOwner()}/${remote.getRepo()} ${query.trim()}`); + return new this(name, `repo:${remote.getOwner()}/${remote.getRepo()} ${query.trim()}`, attrs); } } From 5f6b828ce98e92bb66efdd1791ab4054d55bf656 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 14:11:58 -0400 Subject: [PATCH 0210/4847] ... Right. Not all currentPR searches are null searches. --- lib/models/search.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/models/search.js b/lib/models/search.js index abc0f3ff31..aa2a8be919 100644 --- a/lib/models/search.js +++ b/lib/models/search.js @@ -27,11 +27,11 @@ export default class Search { static forCurrentPR(remote, branch) { const name = 'Current pull request'; - const attrs = {[NULL]: true, [CREATE_ON_EMPTY]: true}; + const attrs = {[CREATE_ON_EMPTY]: true}; const upstream = branch.getUpstream(); if (!upstream.isRemoteTracking()) { - return new this(name, '', attrs); + return new this(name, '', {[NULL]: true, ...attrs}); } return this.inRemote(remote, name, `type:pr head:${upstream.getShortRemoteRef()}`, attrs); From 048a9bcb29e0e7a1d85e3dbcaf5561c1ee2dcd1c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 15:33:27 -0400 Subject: [PATCH 0211/4847] Summarize pull request status from Issueish --- lib/models/issueish.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/models/issueish.js b/lib/models/issueish.js index 077db91342..77ff637fef 100644 --- a/lib/models/issueish.js +++ b/lib/models/issueish.js @@ -1,4 +1,5 @@ import {URL} from 'url'; +import {category} from '../containers/pr-statuses-container'; export default class Issueish { constructor(data) { @@ -10,6 +11,10 @@ export default class Issueish { this.createdAt = data.createdAt; this.headRefName = data.headRefName; this.headRepositoryName = data.headRepository.nameWithOwner; + this.statusContexts = data.commits.nodes.reduce((acc, node) => { + acc.push(...node.commit.status.contexts); + return acc; + }, []); } getNumber() { @@ -45,4 +50,11 @@ export default class Issueish { getHeadRepositoryName() { return this.headRepositoryName; } + + getStatusCounts() { + return this.statusContexts.reduce((acc, context) => { + acc[category(context.state).toLowerCase()]++; + return acc; + }, {pending: 0, failure: 0, success: 0}); + } } From 329389772db6a9298db12a33459ed24a4700f947 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 15:33:42 -0400 Subject: [PATCH 0212/4847] A helper that'll let us nix a few eslint ignores --- lib/helpers.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/helpers.js b/lib/helpers.js index 0a70358ceb..4b9459f13b 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -46,6 +46,16 @@ export function extractProps(props, propTypes) { }, {}); } +// The opposite of extractProps. Return a subset of props that do *not* appear in a component's prop types. +export function unusedProps(props, propTypes) { + return Object.keys(props).reduce((opts, propName) => { + if (propTypes[propName] === undefined) { + opts[propName] = props[propName]; + } + return opts; + }, {}); +} + export function getPackageRoot() { const {resourcePath} = atom.getLoadSettings(); const currentFileWasRequiredFromSnapshot = !path.isAbsolute(__dirname); From 68cc531f6767f14dd29c537dcd5c60e55859db62 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 15:34:06 -0400 Subject: [PATCH 0213/4847] Extract StatusDonusChart from PrStatusesController --- lib/containers/pr-statuses-container.js | 29 ++++--------------------- lib/views/status-donut-chart.js | 25 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 25 deletions(-) create mode 100644 lib/views/status-donut-chart.js diff --git a/lib/containers/pr-statuses-container.js b/lib/containers/pr-statuses-container.js index 8ada4762cf..28751be8b7 100644 --- a/lib/containers/pr-statuses-container.js +++ b/lib/containers/pr-statuses-container.js @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; import {toSentence, autobind} from '../helpers'; import PrStatusContextContainer from './pr-status-context-container'; import Octicon from '../atom/octicon'; -import DonutChart from '../views/donut-chart'; +import StatusDonutChart from '../views/status-donut-chart'; import PeriodicRefresher from '../periodic-refresher'; import {RelayConnectionPropType} from '../prop-types'; @@ -17,7 +17,7 @@ export const stateToIconAndStyle = { FAILURE: {category: 'FAILURE', icon: 'x', style: 'status-error'}, }; -function category(state) { +export function category(state) { const info = stateToIconAndStyle[state]; if (!info) { throw new Error(`Unknown state ${state}`); @@ -25,27 +25,6 @@ function category(state) { return info.category; } -class StatusDonutChart extends React.Component { - static propTypes = { - pending: PropTypes.number, - failed: PropTypes.number, - succeeded: PropTypes.number, - } - - render() { - const {pending, failed, succeeded, ...others} = this.props; // eslint-disable-line no-unused-vars - const slices = ['pending', 'failed', 'succeeded'].reduce((acc, type) => { - const count = this.props[type]; - if (count > 0) { - acc.push({type, className: type, count}); - } - return acc; - }, []); - - return ; - } -} - export class PrStatuses extends React.Component { static propTypes = { relay: PropTypes.shape({ @@ -158,8 +137,8 @@ export class PrStatuses extends React.Component { return ( ); } diff --git a/lib/views/status-donut-chart.js b/lib/views/status-donut-chart.js new file mode 100644 index 0000000000..a9a671ee8c --- /dev/null +++ b/lib/views/status-donut-chart.js @@ -0,0 +1,25 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import DonutChart from './donut-chart'; + +import {unusedProps} from '../helpers'; + +export default class StatusDonutChart extends React.Component { + static propTypes = { + pending: PropTypes.number, + failure: PropTypes.number, + success: PropTypes.number, + } + + render() { + const slices = ['pending', 'failed', 'success'].reduce((acc, type) => { + const count = this.props[type]; + if (count > 0) { + acc.push({type, className: type, count}); + } + return acc; + }, []); + + return ; + } +} From 57dffaf9cd6845fb1bccb98e416d80b8df0106dc Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 15:34:27 -0400 Subject: [PATCH 0214/4847] Query GraphQL for PR status --- .../issueishListContainerQuery.graphql.js | 92 ++++++++++++++++++- .../issueishListController_results.graphql.js | 83 ++++++++++++++++- lib/controllers/issueish-list-controller.js | 30 ++++++ 3 files changed, 202 insertions(+), 3 deletions(-) diff --git a/lib/containers/__generated__/issueishListContainerQuery.graphql.js b/lib/containers/__generated__/issueishListContainerQuery.graphql.js index 6d4cdb2986..da32bc00c5 100644 --- a/lib/containers/__generated__/issueishListContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishListContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash ee7e665e11510ad35c15e1943a427d90 + * @relayHash b3e3bf197fd0e0eb104928d61effc8cb */ /* eslint-disable */ @@ -52,6 +52,21 @@ fragment issueishListController_results on SearchResultItemConnection { nameWithOwner id } + commits(last: 1) { + nodes { + commit { + status { + contexts { + state + id + } + id + } + id + } + id + } + } } ... on Node { id @@ -108,7 +123,7 @@ return { "operationKind": "query", "name": "issueishListContainerQuery", "id": null, - "text": "query issueishListContainerQuery(\n $query: String!\n) {\n search(first: 20, query: $query, type: ISSUE) {\n ...issueishListController_results\n }\n}\n\nfragment issueishListController_results on SearchResultItemConnection {\n issueCount\n nodes {\n __typename\n ... on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n headRepository {\n nameWithOwner\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n", + "text": "query issueishListContainerQuery(\n $query: String!\n) {\n search(first: 20, query: $query, type: ISSUE) {\n ...issueishListController_results\n }\n}\n\nfragment issueishListController_results on SearchResultItemConnection {\n issueCount\n nodes {\n __typename\n ... on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n headRepository {\n nameWithOwner\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n }\n ... on Node {\n id\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -251,6 +266,79 @@ return { }, v3 ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "commits", + "storageKey": "commits(last:1)", + "args": [ + { + "kind": "Literal", + "name": "last", + "value": 1, + "type": "Int" + } + ], + "concreteType": "PullRequestCommitConnection", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestCommit", + "plural": true, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "status", + "storageKey": null, + "args": null, + "concreteType": "Status", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "contexts", + "storageKey": null, + "args": null, + "concreteType": "StatusContext", + "plural": true, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "state", + "args": null, + "storageKey": null + }, + v3 + ] + }, + v3 + ] + }, + v3 + ] + }, + v3 + ] + } + ] } ] } diff --git a/lib/controllers/__generated__/issueishListController_results.graphql.js b/lib/controllers/__generated__/issueishListController_results.graphql.js index f4cf4d42e1..1a88e6b10f 100644 --- a/lib/controllers/__generated__/issueishListController_results.graphql.js +++ b/lib/controllers/__generated__/issueishListController_results.graphql.js @@ -8,6 +8,7 @@ /*:: import type { ConcreteFragment } from 'relay-runtime'; +export type StatusState = "ERROR" | "EXPECTED" | "FAILURE" | "PENDING" | "SUCCESS" | "%future added value"; import type { FragmentReference } from "relay-runtime"; declare export opaque type issueishListController_results$ref: FragmentReference; export type issueishListController_results = {| @@ -25,6 +26,17 @@ export type issueishListController_results = {| +headRepository?: ?{| +nameWithOwner: string |}, + +commits?: {| + +nodes: ?$ReadOnlyArray + |} + |} + |}> + |}, |}>, +$refType: issueishListController_results$ref, |}; @@ -135,6 +147,75 @@ const node/*: ConcreteFragment*/ = { "storageKey": null } ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "commits", + "storageKey": "commits(last:1)", + "args": [ + { + "kind": "Literal", + "name": "last", + "value": 1, + "type": "Int" + } + ], + "concreteType": "PullRequestCommitConnection", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestCommit", + "plural": true, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "status", + "storageKey": null, + "args": null, + "concreteType": "Status", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "contexts", + "storageKey": null, + "args": null, + "concreteType": "StatusContext", + "plural": true, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "state", + "args": null, + "storageKey": null + } + ] + } + ] + } + ] + } + ] + } + ] } ] } @@ -143,5 +224,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = '972050cf8a1b45617db5fbde6fd21231'; +(node/*: any*/).hash = '7ab450dd0df53e3e0e9a79563fdcd9ed'; module.exports = node; diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index 6a102c523d..da1f8d2f27 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -6,6 +6,8 @@ import {SearchPropType, RemotePropType, BranchSetPropType} from '../prop-types'; import IssueishListView from '../views/issueish-list-view'; import Issueish from '../models/issueish'; +const StatePropType = PropTypes.oneOf(['EXPECTED', 'PENDING', 'SUCCESS', 'ERROR', 'FAILURE']); + export class BareIssueishListController extends React.Component { static propTypes = { results: PropTypes.shape({ @@ -24,6 +26,21 @@ export class BareIssueishListController extends React.Component { headRepository: PropTypes.shape({ nameWithOwner: PropTypes.string.isRequired, }).isRequired, + commits: PropTypes.shape({ + nodes: PropTypes.arrayOf(PropTypes.shape({ + commit: PropTypes.shape({ + status: PropTypes.shape({ + state: StatePropType.isRequired, + contexts: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + state: StatePropType.isRequired, + }).isRequired, + ).isRequired, + }), + }), + })), + }), }), ), }), @@ -106,10 +123,23 @@ export default createFragmentContainer(BareIssueishListController, { avatarUrl } createdAt + headRefName headRepository { nameWithOwner } + + commits(last:1) { + nodes { + commit { + status { + contexts { + state + } + } + } + } + } } } } From 664b7320fbfebb707dd9f9ca5e8f6fedcfe1307e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 15:34:40 -0400 Subject: [PATCH 0215/4847] Render a check, X, or donut chart --- lib/views/issueish-list-view.js | 15 +++- test/views/issueish-list-view.test.js | 105 ++++++++++++++++++++++++-- 2 files changed, 112 insertions(+), 8 deletions(-) diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 4a95e311ed..53ce9d4616 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import {SearchPropType, RemotePropType, BranchSetPropType} from '../prop-types'; import {autobind} from '../helpers'; import Accordion from './accordion'; +import StatusDonutChart from './status-donut-chart'; import CreatePullRequestTile from './create-pull-request-tile'; import Octicon from '../atom/octicon'; @@ -61,7 +62,7 @@ export default class IssueishListView extends React.Component { #{issueish.getNumber()} - {/* TODO: wire up */} + {this.renderStatusSummary(issueish.getStatusCounts())} 1d {/* TODO: wire up */} @@ -69,6 +70,18 @@ export default class IssueishListView extends React.Component { ); } + renderStatusSummary(statusCounts) { + if (statusCounts.success > 0 && statusCounts.failure === 0 && statusCounts.pending === 0) { + return ; + } + + if (statusCounts.success === 0 && statusCounts.failure > 0 && statusCounts.pending === 0) { + return ; + } + + return ; + } + renderEmptyTile() { if (this.props.search.showCreateOnEmpty()) { return ( diff --git a/test/views/issueish-list-view.test.js b/test/views/issueish-list-view.test.js index 098853232c..95d4b73340 100644 --- a/test/views/issueish-list-view.test.js +++ b/test/views/issueish-list-view.test.js @@ -1,19 +1,86 @@ import React from 'react'; -import {shallow} from 'enzyme'; +import {shallow, mount} from 'enzyme'; import Remote from '../../lib/models/remote'; import Branch, {nullBranch} from '../../lib/models/branch'; import BranchSet from '../../lib/models/branch-set'; import Search from '../../lib/models/search'; +import Issueish from '../../lib/models/issueish'; import IssueishListView from '../../lib/views/issueish-list-view'; +function makeCommit(...states) { + return { + nodes: [ + { + commit: { + status: { + contexts: states.map(state => ({state})), + }, + }, + }, + ], + }; +} + +const allGreen = new Issueish({ + number: 1, + title: 'One', + url: 'https://github.com/atom/github/pulls/1', + author: { + login: 'me', + avatarUrl: 'https://avatars.githubusercontent.com/u/100?v=24', + }, + createdAt: '2018-06-12T14:50:08Z', + headRefName: 'head-ref', + headRepository: { + nameWithOwner: 'me/github', + }, + commits: makeCommit('SUCCESS', 'SUCCESS', 'SUCCESS'), +}); + +const mixed = new Issueish({ + number: 2, + title: 'Two', + url: 'https://github.com/atom/github/pulls/2', + author: { + login: 'me', + avatarUrl: 'https://avatars.githubusercontent.com/u/100?v=24', + }, + createdAt: '2018-06-12T14:50:08Z', + headRefName: 'head-ref', + headRepository: { + nameWithOwner: 'me/github', + }, + commits: makeCommit('SUCCESS', 'PENDING', 'FAILURE'), +}); + +const allRed = new Issueish({ + number: 3, + title: 'Three', + url: 'https://github.com/atom/github/pulls/3', + author: { + login: 'me', + avatarUrl: 'https://avatars.githubusercontent.com/u/100?v=24', + }, + createdAt: '2018-06-12T14:50:08Z', + headRefName: 'head-ref', + headRepository: { + nameWithOwner: 'me/github', + }, + commits: makeCommit('FAILURE', 'ERROR', 'FAILURE'), +}); + describe('IssueishListView', function() { - function buildApp(overrideProps = {}) { - const origin = new Remote('origin', 'git@github.com:atom/github.git'); - const branch = new Branch('master', nullBranch, nullBranch, true); - const branchSet = new BranchSet(); + let origin, branch, branchSet; + + beforeEach(function() { + origin = new Remote('origin', 'git@github.com:atom/github.git'); + branch = new Branch('master', nullBranch, nullBranch, true); + branchSet = new BranchSet(); branchSet.add(branch); + }); + function buildApp(overrideProps = {}) { return ( Date: Thu, 14 Jun 2018 15:38:15 -0400 Subject: [PATCH 0216/4847] aheadCount is not always present --- lib/containers/issueish-list-container.js | 2 +- lib/controllers/issueish-list-controller.js | 2 +- lib/controllers/issueish-search-controller.js | 2 +- lib/views/create-pull-request-tile.js | 2 +- lib/views/issueish-list-view.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index a13982735a..a8b8e54730 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -22,7 +22,7 @@ export default class IssueishListContainer extends React.Component { search: SearchPropType.isRequired, remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, - aheadCount: PropTypes.number.isRequired, + aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, onCreatePr: PropTypes.func.isRequired, diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index da1f8d2f27..94f91af7a4 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -54,7 +54,7 @@ export class BareIssueishListController extends React.Component { search: SearchPropType.isRequired, remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, - aheadCount: PropTypes.number.isRequired, + aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, isLoading: PropTypes.bool.isRequired, diff --git a/lib/controllers/issueish-search-controller.js b/lib/controllers/issueish-search-controller.js index 2ae50372c1..6b95b886ee 100644 --- a/lib/controllers/issueish-search-controller.js +++ b/lib/controllers/issueish-search-controller.js @@ -19,7 +19,7 @@ export default class IssueishSearchController extends React.Component { remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, - aheadCount: PropTypes.number.isRequired, + aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, onCreatePr: PropTypes.func.isRequired, diff --git a/lib/views/create-pull-request-tile.js b/lib/views/create-pull-request-tile.js index 48e38b6528..43cf8305c3 100644 --- a/lib/views/create-pull-request-tile.js +++ b/lib/views/create-pull-request-tile.js @@ -14,7 +14,7 @@ export default class CreatePullRequestTile extends React.Component { remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, - aheadCount: PropTypes.number.isRequired, + aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, onCreatePr: PropTypes.func.isRequired, diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 53ce9d4616..d8dbbd2694 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -24,7 +24,7 @@ export default class IssueishListView extends React.Component { remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, - aheadCount: PropTypes.number.isRequired, + aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, onCreatePr: PropTypes.func.isRequired, From 39f666d229a2fcf1ac094180a17efb4127c6e0e2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 15:46:49 -0400 Subject: [PATCH 0217/4847] .status is optional --- lib/models/issueish.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/models/issueish.js b/lib/models/issueish.js index 77ff637fef..8691d806ca 100644 --- a/lib/models/issueish.js +++ b/lib/models/issueish.js @@ -12,7 +12,10 @@ export default class Issueish { this.headRefName = data.headRefName; this.headRepositoryName = data.headRepository.nameWithOwner; this.statusContexts = data.commits.nodes.reduce((acc, node) => { - acc.push(...node.commit.status.contexts); + const status = node.commit.status; + if (status !== null) { + acc.push(...status.contexts); + } return acc; }, []); } From d5427d3e0db5ee35b42406d8d78541c9579076c9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 15:47:01 -0400 Subject: [PATCH 0218/4847] Give the donut chart a fixed size --- styles/issuesish-list-view.less | 2 ++ 1 file changed, 2 insertions(+) diff --git a/styles/issuesish-list-view.less b/styles/issuesish-list-view.less index 6aea5880d5..35cdceb4e7 100644 --- a/styles/issuesish-list-view.less +++ b/styles/issuesish-list-view.less @@ -54,6 +54,8 @@ &.icon-x { color: @text-color-error; } + height: 1em; + width: 1em; } &--age { From 7b96adfdf4ac93e93024a74521140b11defa4aa0 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 14 Jun 2018 15:47:10 -0400 Subject: [PATCH 0219/4847] Extract donut chart styles --- styles/donut-chart.less | 13 +++++++++++++ styles/pr-statuses.less | 12 ------------ 2 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 styles/donut-chart.less diff --git a/styles/donut-chart.less b/styles/donut-chart.less new file mode 100644 index 0000000000..156c1c044e --- /dev/null +++ b/styles/donut-chart.less @@ -0,0 +1,13 @@ +@import 'variables'; + +.donut-ring-pending { + stroke: @gh-background-color-yellow; +} + +.donut-ring-succeeded { + stroke: @gh-background-color-green; +} + +.donut-ring-failed { + stroke: @gh-background-color-red; +} diff --git a/styles/pr-statuses.less b/styles/pr-statuses.less index 659749a477..7172ae8fdc 100644 --- a/styles/pr-statuses.less +++ b/styles/pr-statuses.less @@ -1,18 +1,6 @@ @import 'variables'; .github-PrStatuses { - .donut-ring-pending { - stroke: @gh-background-color-yellow; - } - - .donut-ring-succeeded { - stroke: @gh-background-color-green; - } - - .donut-ring-failed { - stroke: @gh-background-color-red; - } - &-header { display: flex; From 72663d5222b989b1e541a4fd8df9c56c7687efdc Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 15 Jun 2018 14:12:17 +0900 Subject: [PATCH 0220/4847] Rename github-Accordion-listItem --- lib/views/accordion.js | 2 +- styles/accordion.less | 12 ++++++++++++ styles/issuesish-list-view.less | 13 ------------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/views/accordion.js b/lib/views/accordion.js index cb3344e29f..3b7bb794d9 100644 --- a/lib/views/accordion.js +++ b/lib/views/accordion.js @@ -75,7 +75,7 @@ export default class Accordion extends React.Component {
      {this.props.results.map((item, index) => { const key = item.key !== undefined ? item.key : index; - return
    • {this.props.children(item)}
    • ; + return
    • {this.props.children(item)}
    • ; })}
    ); diff --git a/styles/accordion.less b/styles/accordion.less index cec914c983..235ab51c5a 100644 --- a/styles/accordion.less +++ b/styles/accordion.less @@ -32,4 +32,16 @@ color: @text-color-highlight; } + &-listItem { + display: flex; + align-items: center; + padding: @component-padding / 4; + border-bottom: 1px solid @base-border-color; + background-color: @base-background-color; + + &:active { + background-color: @background-color-highlight; + } + } + } diff --git a/styles/issuesish-list-view.less b/styles/issuesish-list-view.less index 35cdceb4e7..1da8e09887 100644 --- a/styles/issuesish-list-view.less +++ b/styles/issuesish-list-view.less @@ -1,18 +1,5 @@ @import "variables"; -// TODO: Rename -.github-Accordion-list--item { - display: flex; - align-items: center; - padding: @component-padding / 4; - border-bottom: 1px solid @base-border-color; - background-color: @base-background-color; - - &:active { - background-color: @background-color-highlight; - } -} - .github-IssueishList { &-item { From f7a7b4c2aab2773e1ee80974c2904b35aab0ed33 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 15 Jun 2018 14:22:54 +0900 Subject: [PATCH 0221/4847] Add github-IssueishList-item main class --- lib/views/issueish-list-view.js | 14 +++++++------- styles/issuesish-list-view.less | 10 +--------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index d8dbbd2694..26d153460b 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -52,18 +52,18 @@ export default class IssueishListView extends React.Component { return ( - + {issueish.getTitle()} - + #{issueish.getNumber()} {this.renderStatusSummary(issueish.getStatusCounts())} - + 1d {/* TODO: wire up */} @@ -72,14 +72,14 @@ export default class IssueishListView extends React.Component { renderStatusSummary(statusCounts) { if (statusCounts.success > 0 && statusCounts.failure === 0 && statusCounts.pending === 0) { - return ; + return ; } if (statusCounts.success === 0 && statusCounts.failure > 0 && statusCounts.pending === 0) { - return ; + return ; } - return ; + return ; } renderEmptyTile() { diff --git a/styles/issuesish-list-view.less b/styles/issuesish-list-view.less index 1da8e09887..5f2bcb7fcd 100644 --- a/styles/issuesish-list-view.less +++ b/styles/issuesish-list-view.less @@ -2,15 +2,7 @@ .github-IssueishList { &-item { - - // TODO: Rename - &--avatar, - &--title, - &--number, - &--status, - &--age { - margin: @component-padding / 4; - } + margin: @component-padding / 4; &--avatar { @size: 16px; From 8a8118361b628bcdac776c280f41e18d13ed98b5 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 15 Jun 2018 15:38:46 +0900 Subject: [PATCH 0222/4847] Resize donut ring --- styles/issuesish-list-view.less | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/styles/issuesish-list-view.less b/styles/issuesish-list-view.less index 5f2bcb7fcd..d5c7561749 100644 --- a/styles/issuesish-list-view.less +++ b/styles/issuesish-list-view.less @@ -33,8 +33,17 @@ &.icon-x { color: @text-color-error; } - height: 1em; - width: 1em; + svg& { + height: 16px; + width: 16px; + + circle { + cx: 8; + cy: 8; + r: 5.5; + stroke-width: 3; + } + } } &--age { From db98550988fd35dbc0d2acdbaec9a3ffa99ae7e4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 08:10:48 -0400 Subject: [PATCH 0223/4847] Update donut chart classNames --- lib/views/status-donut-chart.js | 2 +- styles/donut-chart.less | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/views/status-donut-chart.js b/lib/views/status-donut-chart.js index a9a671ee8c..6ac211d168 100644 --- a/lib/views/status-donut-chart.js +++ b/lib/views/status-donut-chart.js @@ -12,7 +12,7 @@ export default class StatusDonutChart extends React.Component { } render() { - const slices = ['pending', 'failed', 'success'].reduce((acc, type) => { + const slices = ['pending', 'failure', 'success'].reduce((acc, type) => { const count = this.props[type]; if (count > 0) { acc.push({type, className: type, count}); diff --git a/styles/donut-chart.less b/styles/donut-chart.less index 156c1c044e..0a82bf2ae2 100644 --- a/styles/donut-chart.less +++ b/styles/donut-chart.less @@ -4,10 +4,10 @@ stroke: @gh-background-color-yellow; } -.donut-ring-succeeded { +.donut-ring-success { stroke: @gh-background-color-green; } -.donut-ring-failed { +.donut-ring-failure { stroke: @gh-background-color-red; } From 7b8b5d6e5a111b59ffd9fe6085badd74dba6e837 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 08:17:49 -0400 Subject: [PATCH 0224/4847] Match PropTypes to the GraphQL query --- lib/controllers/issueish-list-controller.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index 94f91af7a4..ad7c08f674 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -30,10 +30,8 @@ export class BareIssueishListController extends React.Component { nodes: PropTypes.arrayOf(PropTypes.shape({ commit: PropTypes.shape({ status: PropTypes.shape({ - state: StatePropType.isRequired, contexts: PropTypes.arrayOf( PropTypes.shape({ - id: PropTypes.string.isRequired, state: StatePropType.isRequired, }).isRequired, ).isRequired, From 411fc99da8009a06d91c93c098ab4feb70614bd3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 08:34:58 -0400 Subject: [PATCH 0225/4847] Render a dash when no status checks are present --- lib/views/issueish-list-view.js | 4 ++++ styles/issuesish-list-view.less | 3 +++ test/views/issueish-list-view.test.js | 29 +++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 26d153460b..1e3ab52876 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -71,6 +71,10 @@ export default class IssueishListView extends React.Component { } renderStatusSummary(statusCounts) { + if (['success', 'failure', 'pending'].every(kind => statusCounts[kind] === 0)) { + return ; + } + if (statusCounts.success > 0 && statusCounts.failure === 0 && statusCounts.pending === 0) { return ; } diff --git a/styles/issuesish-list-view.less b/styles/issuesish-list-view.less index d5c7561749..f176a17998 100644 --- a/styles/issuesish-list-view.less +++ b/styles/issuesish-list-view.less @@ -33,6 +33,9 @@ &.icon-x { color: @text-color-error; } + &.icon-dash { + color: @text-color-subtle; + } svg& { height: 16px; width: 16px; diff --git a/test/views/issueish-list-view.test.js b/test/views/issueish-list-view.test.js index 95d4b73340..9ed031dbfb 100644 --- a/test/views/issueish-list-view.test.js +++ b/test/views/issueish-list-view.test.js @@ -70,6 +70,30 @@ const allRed = new Issueish({ commits: makeCommit('FAILURE', 'ERROR', 'FAILURE'), }); +const noStatus = new Issueish({ + number: 4, + title: 'Four', + url: 'https://github.com/atom/github/pulls/4', + author: { + login: 'me', + avatarUrl: 'https://avatars.githubusercontent.com/u/100?v=24', + }, + createdAt: '2018-06-12T14:50:08Z', + headRefName: 'head-ref', + headRepository: { + nameWithOwner: 'me/github', + }, + commits: { + nodes: [ + { + commit: { + status: null, + }, + }, + ], + }, +}); + describe('IssueishListView', function() { let origin, branch, branchSet; @@ -158,5 +182,10 @@ describe('IssueishListView', function() { assert.strictEqual(chart.prop('failure'), 1); assert.strictEqual(chart.prop('success'), 1); }); + + it('renders nothing with no status checks are present', function() { + const wrapper = mount(buildApp({isLoading: false, total: 1, issueishes: [noStatus]})); + assert.isTrue(wrapper.find('span.github-IssueishList-item--status').hasClass('icon-dash')); + }); }); }); From 5673bd1b0268390fc65bbd3606d754adcbb98a76 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 08:38:47 -0400 Subject: [PATCH 0226/4847] Update mock GraphQL responses --- test/containers/issueish-list-container.test.js | 12 ++++++++++++ test/controllers/issueish-list-controller.test.js | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/test/containers/issueish-list-container.test.js b/test/containers/issueish-list-container.test.js index c65ad2da28..ffd95c8fb0 100644 --- a/test/containers/issueish-list-container.test.js +++ b/test/containers/issueish-list-container.test.js @@ -54,6 +54,18 @@ describe('IssueishListContainer', function() { id: 'r0', nameWithOwner: 'atom/github', }, + commits: { + id: 'cs0', + nodes: [ + { + id: 'n0', + commit: { + id: 'c0', + status: null, + }, + }, + ], + }, }; } diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index 449253ebcf..a2ac8170f3 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -55,6 +55,15 @@ describe('IssueishListController', function() { headRepository: { nameWithOwner: 'atom/github', }, + commits: { + nodes: [ + { + commit: { + status: null, + }, + }, + ], + }, }; const wrapper = shallow(buildApp({ From a1b1f775f5924878627943fb417e20f8cf90b418 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 09:10:13 -0400 Subject: [PATCH 0227/4847] Set an explicit pathLength on the donut chart circle --- lib/views/donut-chart.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/views/donut-chart.js b/lib/views/donut-chart.js index 3f3e7783a2..a92b8f2a71 100644 --- a/lib/views/donut-chart.js +++ b/lib/views/donut-chart.js @@ -59,6 +59,7 @@ export default class DonutChart extends React.Component { r="15.91549430918954" fill="transparent" className={`donut-ring-${type}`} + pathLength="100" strokeWidth="3" strokeDasharray={`${length} ${100 - length}`} strokeDashoffset={`${100 - position + this.props.baseOffset}`} From 981faf40851c9eaf188019921ce2fb9e9b88173a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 09:11:20 -0400 Subject: [PATCH 0228/4847] :shirt: Remove unused import --- lib/controllers/issueish-search-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controllers/issueish-search-controller.js b/lib/controllers/issueish-search-controller.js index 6b95b886ee..cfc38c5689 100644 --- a/lib/controllers/issueish-search-controller.js +++ b/lib/controllers/issueish-search-controller.js @@ -1,4 +1,4 @@ -import React, {Fragment} from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import {RemotePropType, BranchSetPropType} from '../prop-types'; From 90fdf200a39b1a25014b5828a552d069c7c45a18 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 09:27:42 -0400 Subject: [PATCH 0229/4847] Wire up the createdAt date --- lib/models/issueish.js | 4 +++- lib/views/issueish-list-view.js | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/models/issueish.js b/lib/models/issueish.js index 8691d806ca..b974037a1a 100644 --- a/lib/models/issueish.js +++ b/lib/models/issueish.js @@ -1,4 +1,6 @@ import {URL} from 'url'; +import moment from 'moment'; + import {category} from '../containers/pr-statuses-container'; export default class Issueish { @@ -8,7 +10,7 @@ export default class Issueish { this.url = new URL(data.url); this.authorLogin = data.author.login; this.authorAvatarURL = new URL(data.author.avatarUrl); - this.createdAt = data.createdAt; + this.createdAt = moment(data.createdAt, moment.ISO_8601); this.headRefName = data.headRefName; this.headRepositoryName = data.headRepository.nameWithOwner; this.statusContexts = data.commits.nodes.reduce((acc, node) => { diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 1e3ab52876..a7b60add43 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import {SearchPropType, RemotePropType, BranchSetPropType} from '../prop-types'; import {autobind} from '../helpers'; import Accordion from './accordion'; +import Timeago from './timeago'; import StatusDonutChart from './status-donut-chart'; import CreatePullRequestTile from './create-pull-request-tile'; import Octicon from '../atom/octicon'; @@ -63,9 +64,11 @@ export default class IssueishListView extends React.Component { #{issueish.getNumber()} {this.renderStatusSummary(issueish.getStatusCounts())} - - 1d {/* TODO: wire up */} - +
    ); } From f3704c1ab9e73ad99c594071ac4587df3a7c29f5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 10:12:18 -0400 Subject: [PATCH 0230/4847] Pass a Workspace through GithubTabController --- lib/containers/remote-container.js | 2 ++ lib/controllers/github-tab-controller.js | 3 ++- lib/controllers/issueish-search-controller.js | 17 +++++++++++++++++ lib/controllers/remote-controller.js | 2 ++ lib/controllers/root-controller.js | 1 + test/containers/remote-container.test.js | 8 +++++++- .../issueish-list-controller.test.js | 11 +++++++++++ .../issueish-search-controller.test.js | 10 ++++++++++ test/controllers/remote-controller.test.js | 9 ++++++++- 9 files changed, 60 insertions(+), 3 deletions(-) diff --git a/lib/containers/remote-container.js b/lib/containers/remote-container.js index a1755dbe84..7d6cfbb87c 100644 --- a/lib/containers/remote-container.js +++ b/lib/containers/remote-container.js @@ -17,6 +17,7 @@ export default class RemoteContainer extends React.Component { host: PropTypes.string.isRequired, + workspace: PropTypes.object.isRequired, remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, @@ -101,6 +102,7 @@ export default class RemoteContainer extends React.Component { repository={props.repository} + workspace={this.props.workspace} remote={this.props.remote} branches={this.props.branches} diff --git a/lib/controllers/github-tab-controller.js b/lib/controllers/github-tab-controller.js index a95ccb9154..2eed2ac43d 100644 --- a/lib/controllers/github-tab-controller.js +++ b/lib/controllers/github-tab-controller.js @@ -10,6 +10,7 @@ import {autobind} from '../helpers'; export default class GithubTabController extends React.Component { static propTypes = { + workspace: PropTypes.object.isRequired, repository: PropTypes.object, loginModel: PropTypes.instanceOf(GithubLoginModel), } @@ -81,7 +82,7 @@ export default class GithubTabController extends React.Component { this.handlePushBranch(currentBranch, remote)} remote={remote} branches={branches} diff --git a/lib/controllers/issueish-search-controller.js b/lib/controllers/issueish-search-controller.js index cfc38c5689..7d45dd9b3b 100644 --- a/lib/controllers/issueish-search-controller.js +++ b/lib/controllers/issueish-search-controller.js @@ -1,14 +1,17 @@ import React from 'react'; import PropTypes from 'prop-types'; +import {autobind} from '../helpers'; import {RemotePropType, BranchSetPropType} from '../prop-types'; import Search from '../models/search'; import IssueishListContainer from '../containers/issueish-list-container'; +import IssueishPaneItem from '../items/issueish-pane-item'; export default class IssueishSearchController extends React.Component { static propTypes = { host: PropTypes.string.isRequired, token: PropTypes.string.isRequired, + workspace: PropTypes.object.isRequired, repository: PropTypes.shape({ defaultBranchRef: PropTypes.shape({ @@ -27,6 +30,7 @@ export default class IssueishSearchController extends React.Component { constructor(props) { super(props); + autobind(this, 'onOpenIssueish'); this.state = {}; } @@ -58,10 +62,23 @@ export default class IssueishSearchController extends React.Component { aheadCount={this.props.aheadCount} pushInProgress={this.props.pushInProgress} + onOpenIssueish={this.onOpenIssueish} onCreatePr={this.props.onCreatePr} /> ))}
    ); } + + onOpenIssueish(issueish) { + return this.props.workspace.open( + IssueishPaneItem.buildURI( + this.props.host, + this.props.remote.getOwner(), + this.props.remote.getRepo(), + issueish.getNumber(), + ), + {pending: true, searchAllPanes: true}, + ); + } } diff --git a/lib/controllers/remote-controller.js b/lib/controllers/remote-controller.js index 2819abff41..3b710caea4 100644 --- a/lib/controllers/remote-controller.js +++ b/lib/controllers/remote-controller.js @@ -18,6 +18,7 @@ export default class RemoteController extends React.Component { }), }), + workspace: PropTypes.object.isRequired, remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, @@ -40,6 +41,7 @@ export default class RemoteController extends React.Component { repository={this.props.repository} + workspace={this.props.workspace} remote={this.props.remote} branches={this.props.branches} aheadCount={this.props.aheadCount} diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index a10a28980f..ab41c31706 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -212,6 +212,7 @@ export default class RootController extends React.Component { itemHolder={this.refGitHubTabController}> diff --git a/test/containers/remote-container.test.js b/test/containers/remote-container.test.js index 4c4f0515a9..61b04c3844 100644 --- a/test/containers/remote-container.test.js +++ b/test/containers/remote-container.test.js @@ -10,12 +10,17 @@ import RemoteContainer from '../../lib/containers/remote-container'; import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; describe('RemoteContainer', function() { - let model; + let atomEnv, model; beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); model = new GithubLoginModel(InMemoryStrategy); }); + afterEach(function() { + atomEnv.destroy(); + }); + function buildApp(overrideProps = {}) { const origin = new Remote('origin', 'git@github.com:atom/github.git'); const branch = new Branch('master', nullBranch, nullBranch, true); @@ -28,6 +33,7 @@ describe('RemoteContainer', function() { host="https://api.github.com" + workspace={atomEnv.workspace} remote={origin} branches={branchSet} diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index a2ac8170f3..f50a881944 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -9,6 +9,16 @@ import Branch, {nullBranch} from '../../lib/models/branch'; import {BareIssueishListController} from '../../lib/controllers/issueish-list-controller'; describe('IssueishListController', function() { + let atomEnv; + + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + function buildApp(overrideProps = {}) { const branches = new BranchSet(); branches.add(new Branch('master', nullBranch, nullBranch, true)); @@ -19,6 +29,7 @@ describe('IssueishListController', function() { repository={null} search={new Search('aaa', 'bbb')} + workspace={atomEnv.workspace} remote={new Remote('origin', 'git@github.com:atom/github.git')} branches={branches} aheadCount={0} diff --git a/test/controllers/issueish-search-controller.test.js b/test/controllers/issueish-search-controller.test.js index 9a58e43191..c5f6a5cb06 100644 --- a/test/controllers/issueish-search-controller.test.js +++ b/test/controllers/issueish-search-controller.test.js @@ -7,10 +7,19 @@ import Branch from '../../lib/models/branch'; import BranchSet from '../../lib/models/branch-set'; describe('IssueishSearchController', function() { + let atomEnv; const origin = new Remote('origin', 'git@github.com:atom/github.git'); const upstreamMaster = Branch.createRemoteTracking('origin/master', 'origin', 'refs/heads/master'); const master = new Branch('master', upstreamMaster); + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + function buildApp(overloadProps = {}) { const branches = new BranchSet(); branches.add(master); @@ -21,6 +30,7 @@ describe('IssueishSearchController', function() { host="https://api.github.com" repository={null} + workspace={atomEnv.workspace} remote={origin} branches={branches} aheadCount={0} diff --git a/test/controllers/remote-controller.test.js b/test/controllers/remote-controller.test.js index 1f5d41faf6..56c763b6ce 100644 --- a/test/controllers/remote-controller.test.js +++ b/test/controllers/remote-controller.test.js @@ -7,15 +7,21 @@ import Remote from '../../lib/models/remote'; import RemoteController from '../../lib/controllers/remote-controller'; describe('RemoteController', function() { - let remote, branchSet, currentBranch; + let atomEnv, remote, branchSet, currentBranch; beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + remote = new Remote('origin', 'git@github.com:atom/github'); currentBranch = new Branch('master', nullBranch, nullBranch, true); branchSet = new BranchSet(); branchSet.add(currentBranch); }); + afterEach(function() { + atomEnv.destroy(); + }); + function createApp(props = {}) { const noop = () => {}; @@ -26,6 +32,7 @@ describe('RemoteController', function() { repository={null} + workspace={atomEnv.workspace} remote={remote} branches={branchSet} From 5add63690c78fa623420f91b13b2dafedbac6917 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 10:12:39 -0400 Subject: [PATCH 0231/4847] Support a click handler on an Accordion list item --- lib/views/accordion.js | 8 +++++++- test/views/accordion.test.js | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/views/accordion.js b/lib/views/accordion.js index 3b7bb794d9..680a2bae17 100644 --- a/lib/views/accordion.js +++ b/lib/views/accordion.js @@ -11,12 +11,14 @@ export default class Accordion extends React.Component { isLoading: PropTypes.bool.isRequired, loadingComponent: PropTypes.func, emptyComponent: PropTypes.func, + onClickItem: PropTypes.func, children: PropTypes.func.isRequired, }; static defaultProps = { loadingComponent: () => null, emptyComponent: () => null, + onClickItem: () => {}, }; constructor(props) { @@ -75,7 +77,11 @@ export default class Accordion extends React.Component {
      {this.props.results.map((item, index) => { const key = item.key !== undefined ? item.key : index; - return
    • {this.props.children(item)}
    • ; + return ( +
    • this.props.onClickItem(item)}> + {this.props.children(item)} +
    • + ); })}
    ); diff --git a/test/views/accordion.test.js b/test/views/accordion.test.js index 58328ce08a..498b642af6 100644 --- a/test/views/accordion.test.js +++ b/test/views/accordion.test.js @@ -107,5 +107,23 @@ describe('Accordion', function() { assert.isTrue(wrapper.find('CustomChild').someWhere(c => c.prop('item') === i)); } }); + + it('passes an onClick handler to each item', function() { + const results = [1, 2, 3]; + const handler = sinon.stub(); + const wrapper = shallow(buildApp({ + results, + loadingComponent: WrongChild, + emptyComponent: WrongChild, + onClickItem: handler, + children: each => , + })); + + wrapper.find('.github-Accordion-listItem').at(1).simulate('click'); + assert.isTrue(handler.calledWith(2)); + + wrapper.find('.github-Accordion-listItem').at(2).simulate('click'); + assert.isTrue(handler.calledWith(3)); + }); }); }); From 4d78ee1ec29670a988a236d0c4aa278ee31a9a4d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 10:13:09 -0400 Subject: [PATCH 0232/4847] Support an onIssueishClick handler --- lib/views/issueish-list-view.js | 8 +++++++- test/views/issueish-list-view.test.js | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index a7b60add43..8c787efa21 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -28,9 +28,14 @@ export default class IssueishListView extends React.Component { aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, + onIssueishClick: PropTypes.func, onCreatePr: PropTypes.func.isRequired, } + static defaultProps = { + onIssueishClick: () => {}, + } + constructor(props) { super(props); @@ -43,7 +48,8 @@ export default class IssueishListView extends React.Component { leftTitle={this.props.search.getName()} isLoading={this.props.isLoading} results={this.props.issueishes} - emptyComponent={this.renderEmptyTile}> + emptyComponent={this.renderEmptyTile} + onClickItem={this.props.onIssueishClick}> {this.renderIssueish} ); diff --git a/test/views/issueish-list-view.test.js b/test/views/issueish-list-view.test.js index 9ed031dbfb..4cec0c8d56 100644 --- a/test/views/issueish-list-view.test.js +++ b/test/views/issueish-list-view.test.js @@ -187,5 +187,19 @@ describe('IssueishListView', function() { const wrapper = mount(buildApp({isLoading: false, total: 1, issueishes: [noStatus]})); assert.isTrue(wrapper.find('span.github-IssueishList-item--status').hasClass('icon-dash')); }); + + it('calls its onIssueishClick handler when an item is clicked', function() { + const issueishes = [allGreen, mixed, allRed]; + const onIssueishClick = sinon.stub(); + const wrapper = mount(buildApp({ + isLoading: false, + total: 3, + issueishes, + onIssueishClick, + })); + + wrapper.find('.github-Accordion-listItem').at(1).simulate('click'); + assert.isTrue(onIssueishClick.calledWith(mixed)); + }); }); }); From 5c3797ae9f8ae51c49d74ed646bee4d2c583951d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 10:18:39 -0400 Subject: [PATCH 0233/4847] Open an issueish pane on click --- lib/controllers/issueish-list-controller.js | 2 ++ .../issueish-search-controller.test.js | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index ad7c08f674..f4023ab076 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -56,6 +56,7 @@ export class BareIssueishListController extends React.Component { pushInProgress: PropTypes.bool.isRequired, isLoading: PropTypes.bool.isRequired, + onOpenIssueish: PropTypes.func.isRequired, onCreatePr: PropTypes.func.isRequired, }; @@ -101,6 +102,7 @@ export class BareIssueishListController extends React.Component { aheadCount={this.props.aheadCount} pushInProgress={this.props.pushInProgress} + onIssueishClick={this.props.onOpenIssueish} onCreatePr={this.props.onCreatePr} /> ); diff --git a/test/controllers/issueish-search-controller.test.js b/test/controllers/issueish-search-controller.test.js index c5f6a5cb06..d9d937b690 100644 --- a/test/controllers/issueish-search-controller.test.js +++ b/test/controllers/issueish-search-controller.test.js @@ -5,6 +5,7 @@ import IssueishSearchController from '../../lib/controllers/issueish-search-cont import Remote from '../../lib/models/remote'; import Branch from '../../lib/models/branch'; import BranchSet from '../../lib/models/branch-set'; +import Issueish from '../../lib/models/issueish'; describe('IssueishSearchController', function() { let atomEnv; @@ -54,4 +55,28 @@ describe('IssueishSearchController', function() { assert.strictEqual(list.prop('host'), 'https://api.github.com'); } }); + + it('passes a handler to open an issueish pane', async function() { + const wrapper = shallow(buildApp()); + const container = wrapper.find('IssueishListContainer').at(0); + + const issueish = new Issueish({ + number: 123, + title: 'This is the title', + url: 'https://github.com/atom/github/pulls/123', + author: { + login: 'me', + avatarUrl: 'https://avatars2.githubusercontent.com/u/1234?v=6', + }, + createdAt: '2018-06-12T14:50:08Z', + refHeadName: 'feature', + headRepository: { + nameWithOwner: 'smashwilson/github', + }, + commits: {nodes: []}, + }); + + const item = await container.prop('onOpenIssueish')(issueish); + assert.strictEqual(item.getURI(), 'atom-github:/issueish/https%3A%2F%2Fapi.github.com/atom/github/123'); + }); }); From 6318d932a97841123afa63f045edd09dd6c3dad6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 10:33:04 -0400 Subject: [PATCH 0234/4847] Pass onOpenIssueish through IssueishListContainer --- lib/containers/issueish-list-container.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index a8b8e54730..216688939f 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -25,6 +25,7 @@ export default class IssueishListContainer extends React.Component { aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, + onOpenIssueish: PropTypes.func.isRequired, onCreatePr: PropTypes.func.isRequired, } @@ -49,6 +50,7 @@ export default class IssueishListContainer extends React.Component { pushInProgress={this.props.pushInProgress} isLoading={false} + onOpenIssueish={this.props.onOpenIssueish} onCreatePr={this.props.onCreatePr} /> ); @@ -92,6 +94,7 @@ export default class IssueishListContainer extends React.Component { pushInProgress={this.props.pushInProgress} isLoading={true} + onOpenIssueish={this.props.onOpenIssueish} onCreatePr={this.props.onCreatePr} /> ); @@ -109,6 +112,7 @@ export default class IssueishListContainer extends React.Component { pushInProgress={this.props.pushInProgress} isLoading={false} + onOpenIssueish={this.props.onOpenIssueish} onCreatePr={this.props.onCreatePr} /> ); From faa0db930ab8ee432518f73f5e3472867d38a440 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 10:55:32 -0400 Subject: [PATCH 0235/4847] Render a moreComponent if an Accordion is truncated --- lib/views/accordion.js | 28 ++++++++++++++++++---------- lib/views/issueish-list-view.js | 1 + test/views/accordion.test.js | 16 ++++++++++++++++ 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/lib/views/accordion.js b/lib/views/accordion.js index 680a2bae17..dc35729400 100644 --- a/lib/views/accordion.js +++ b/lib/views/accordion.js @@ -8,9 +8,11 @@ export default class Accordion extends React.Component { leftTitle: PropTypes.string.isRequired, rightTitle: PropTypes.string, results: PropTypes.arrayOf(PropTypes.any).isRequired, + total: PropTypes.number.isRequired, isLoading: PropTypes.bool.isRequired, loadingComponent: PropTypes.func, emptyComponent: PropTypes.func, + moreComponent: PropTypes.func, onClickItem: PropTypes.func, children: PropTypes.func.isRequired, }; @@ -18,6 +20,7 @@ export default class Accordion extends React.Component { static defaultProps = { loadingComponent: () => null, emptyComponent: () => null, + moreComponent: () => null, onClickItem: () => {}, }; @@ -73,17 +76,22 @@ export default class Accordion extends React.Component { return null; } + const More = this.props.moreComponent; + return ( -
      - {this.props.results.map((item, index) => { - const key = item.key !== undefined ? item.key : index; - return ( -
    • this.props.onClickItem(item)}> - {this.props.children(item)} -
    • - ); - })} -
    + +
      + {this.props.results.map((item, index) => { + const key = item.key !== undefined ? item.key : index; + return ( +
    • this.props.onClickItem(item)}> + {this.props.children(item)} +
    • + ); + })} +
    + {this.props.results.length < this.props.total && } +
    ); } diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 8c787efa21..3729c3dcab 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -48,6 +48,7 @@ export default class IssueishListView extends React.Component { leftTitle={this.props.search.getName()} isLoading={this.props.isLoading} results={this.props.issueishes} + total={this.props.total} emptyComponent={this.renderEmptyTile} onClickItem={this.props.onIssueishClick}> {this.renderIssueish} diff --git a/test/views/accordion.test.js b/test/views/accordion.test.js index 498b642af6..51990b93d4 100644 --- a/test/views/accordion.test.js +++ b/test/views/accordion.test.js @@ -21,6 +21,7 @@ describe('Accordion', function() { null} {...overrideProps} @@ -125,5 +126,20 @@ describe('Accordion', function() { wrapper.find('.github-Accordion-listItem').at(2).simulate('click'); assert.isTrue(handler.calledWith(3)); }); + + it('renders a more tile when the results have been truncated', function() { + const results = [1, 2, 3]; + const wrapper = shallow(buildApp({ + results, + total: 3, + moreComponent: CustomChild, + })); + + assert.isFalse(wrapper.find('CustomChild').exists()); + + wrapper.setProps({total: 4}); + + assert.isTrue(wrapper.find('CustomChild').exists()); + }); }); }); From 0bfd93b72de85a74e8b4c4ff46fbe88ae5af6636 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 11:29:42 -0400 Subject: [PATCH 0236/4847] Generate search URLs --- lib/models/search.js | 8 ++++++++ test/models/search.test.js | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/models/search.js b/lib/models/search.js index aa2a8be919..ab206f7fc5 100644 --- a/lib/models/search.js +++ b/lib/models/search.js @@ -25,6 +25,14 @@ export default class Search { return this.attrs[CREATE_ON_EMPTY] || false; } + getWebURL(remote) { + if (!remote.isGithubRepo()) { + throw new Error(`Attempt to generate web URL for non-Github remote ${remote.getName()}`); + } + + return `https://${remote.getDomain()}/search?q=${encodeURIComponent(this.createQuery())}`; + } + static forCurrentPR(remote, branch) { const name = 'Current pull request'; const attrs = {[CREATE_ON_EMPTY]: true}; diff --git a/test/models/search.test.js b/test/models/search.test.js index 20def53cc5..1a427d0a84 100644 --- a/test/models/search.test.js +++ b/test/models/search.test.js @@ -10,6 +10,14 @@ describe('Search', function() { const local = new Branch('local'); const tracksLocal = new Branch('tracks-local', local); + it('generates a dotcom URL', function() { + const s = new Search('foo', 'repo:smashwilson/remote-repo type:pr something with spaces'); + assert.strictEqual( + s.getWebURL(origin), + 'https://github.com/search?q=repo%3Asmashwilson%2Fremote-repo%20type%3Apr%20something%20with%20spaces', + ); + }); + describe('for the current pull request', function() { it('is a null search when the Branch has no upstream', function() { const s = Search.forCurrentPR(origin, local); From c4a0be7d7742c61994e1a521379f4e087c203c61 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 11:29:51 -0400 Subject: [PATCH 0237/4847] Parse the domain out of a git remote --- lib/models/remote.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/models/remote.js b/lib/models/remote.js index d7002a3f13..ee44181f94 100644 --- a/lib/models/remote.js +++ b/lib/models/remote.js @@ -3,8 +3,9 @@ export default class Remote { this.name = name; this.url = url; - const {isGithubRepo, owner, repo} = githubInfoFromRemote(url); + const {isGithubRepo, owner, domain, repo} = githubInfoFromRemote(url); this.githubRepo = isGithubRepo; + this.domain = domain; this.owner = owner; this.repo = repo; } @@ -21,6 +22,10 @@ export default class Remote { return this.githubRepo; } + getDomain() { + return this.domain; + } + getOwner() { return this.owner; } @@ -46,23 +51,26 @@ function githubInfoFromRemote(remoteUrl) { if (!remoteUrl) { return { isGithubRepo: false, + domain: null, owner: null, repo: null, }; } // proto login domain owner repo - const regex = /(?:.+:\/\/)?(?:.+@)?github\.com[:/]([^/]+)\/(.+)/; + const regex = /(?:.+:\/\/)?(?:.+@)?(github\.com)[:/]([^/]+)\/(.+)/; const match = remoteUrl.match(regex); if (match) { return { isGithubRepo: true, - owner: match[1], - repo: match[2].replace(/\.git$/, ''), + domain: match[1], + owner: match[2], + repo: match[3].replace(/\.git$/, ''), }; } else { return { isGithubRepo: false, + domain: null, owner: null, repo: null, }; @@ -82,6 +90,10 @@ export const nullRemote = { return false; }, + getDomain() { + return null; + }, + getOwner() { return null; }, From bcfb4d7ef193ac2143099680bf8b6c4a943002c4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 11:31:03 -0400 Subject: [PATCH 0238/4847] Pass an openSearch handler --- lib/containers/issueish-list-container.js | 4 ++++ lib/controllers/issueish-list-controller.js | 2 ++ lib/controllers/issueish-search-controller.js | 14 +++++++++++++- lib/views/issueish-list-view.js | 9 +++------ test/containers/issueish-list-container.test.js | 2 ++ test/controllers/issueish-list-controller.test.js | 2 ++ test/views/issueish-list-view.test.js | 2 ++ 7 files changed, 28 insertions(+), 7 deletions(-) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index 216688939f..b8dec51c52 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -26,6 +26,7 @@ export default class IssueishListContainer extends React.Component { pushInProgress: PropTypes.bool.isRequired, onOpenIssueish: PropTypes.func.isRequired, + onOpenSearch: PropTypes.func.isRequired, onCreatePr: PropTypes.func.isRequired, } @@ -51,6 +52,7 @@ export default class IssueishListContainer extends React.Component { isLoading={false} onOpenIssueish={this.props.onOpenIssueish} + onOpenSearch={this.props.onOpenSearch} onCreatePr={this.props.onCreatePr} /> ); @@ -95,6 +97,7 @@ export default class IssueishListContainer extends React.Component { isLoading={true} onOpenIssueish={this.props.onOpenIssueish} + onOpenSearch={this.props.onOpenSearch} onCreatePr={this.props.onCreatePr} /> ); @@ -113,6 +116,7 @@ export default class IssueishListContainer extends React.Component { isLoading={false} onOpenIssueish={this.props.onOpenIssueish} + onOpenSearch={this.props.onOpenSearch} onCreatePr={this.props.onCreatePr} /> ); diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index f4023ab076..56fadca7db 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -57,6 +57,7 @@ export class BareIssueishListController extends React.Component { isLoading: PropTypes.bool.isRequired, onOpenIssueish: PropTypes.func.isRequired, + onOpenSearch: PropTypes.func.isRequired, onCreatePr: PropTypes.func.isRequired, }; @@ -103,6 +104,7 @@ export class BareIssueishListController extends React.Component { pushInProgress={this.props.pushInProgress} onIssueishClick={this.props.onOpenIssueish} + onMoreClick={this.props.onOpenSearch} onCreatePr={this.props.onCreatePr} /> ); diff --git a/lib/controllers/issueish-search-controller.js b/lib/controllers/issueish-search-controller.js index 7d45dd9b3b..1e7d9709f3 100644 --- a/lib/controllers/issueish-search-controller.js +++ b/lib/controllers/issueish-search-controller.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import {shell} from 'electron'; import {autobind} from '../helpers'; import {RemotePropType, BranchSetPropType} from '../prop-types'; @@ -30,7 +31,7 @@ export default class IssueishSearchController extends React.Component { constructor(props) { super(props); - autobind(this, 'onOpenIssueish'); + autobind(this, 'onOpenIssueish', 'onOpenSearch'); this.state = {}; } @@ -63,6 +64,7 @@ export default class IssueishSearchController extends React.Component { pushInProgress={this.props.pushInProgress} onOpenIssueish={this.onOpenIssueish} + onOpenSearch={this.onOpenSearch} onCreatePr={this.props.onCreatePr} /> ))} @@ -81,4 +83,14 @@ export default class IssueishSearchController extends React.Component { {pending: true, searchAllPanes: true}, ); } + + onOpenSearch(search) { + const searchURL = search.getWebURL(this.props.remote); + + return new Promise((resolve, reject) => { + shell.openExternal(searchURL, {}, err => { + if (err) { reject(err); } else { resolve(); } + }); + }); + } } diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 3729c3dcab..c46d510723 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -28,18 +28,15 @@ export default class IssueishListView extends React.Component { aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, - onIssueishClick: PropTypes.func, + onIssueishClick: PropTypes.func.isRequired, + onMoreClick: PropTypes.func.isRequired, onCreatePr: PropTypes.func.isRequired, } - static defaultProps = { - onIssueishClick: () => {}, - } - constructor(props) { super(props); - autobind(this, 'renderIssueish', 'renderEmptyTile'); + autobind(this, 'renderIssueish', 'renderEmptyTile', 'renderMoreTile'); } render() { diff --git a/test/containers/issueish-list-container.test.js b/test/containers/issueish-list-container.test.js index ffd95c8fb0..064037aca4 100644 --- a/test/containers/issueish-list-container.test.js +++ b/test/containers/issueish-list-container.test.js @@ -28,6 +28,8 @@ describe('IssueishListContainer', function() { aheadCount={0} pushInProgress={false} + onOpenIssueish={() => {}} + onOpenSearch={() => {}} onCreatePr={() => {}} {...overrideProps} diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index f50a881944..9d4ce3833d 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -37,6 +37,8 @@ describe('IssueishListController', function() { isLoading={false} onCreatePr={() => {}} + onOpenIssueish={() => {}} + onOpenSearch={() => {}} {...overrideProps} /> diff --git a/test/views/issueish-list-view.test.js b/test/views/issueish-list-view.test.js index 4cec0c8d56..e829b24ac8 100644 --- a/test/views/issueish-list-view.test.js +++ b/test/views/issueish-list-view.test.js @@ -119,6 +119,8 @@ describe('IssueishListView', function() { pushInProgress={false} onCreatePr={() => {}} + onIssueishClick={() => {}} + onMoreClick={() => {}} {...overrideProps} /> From edaad7078181cf3fb58f2e6c2fee4c9736a10a60 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 11:40:13 -0400 Subject: [PATCH 0239/4847] Render a "More..." link when a list is truncated --- lib/views/issueish-list-view.js | 9 +++++++++ test/views/issueish-list-view.test.js | 14 ++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index c46d510723..5eb842c0e9 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -47,6 +47,7 @@ export default class IssueishListView extends React.Component { results={this.props.issueishes} total={this.props.total} emptyComponent={this.renderEmptyTile} + moreComponent={this.renderMoreTile} onClickItem={this.props.onIssueishClick}> {this.renderIssueish} @@ -109,4 +110,12 @@ export default class IssueishListView extends React.Component { return null; } + + renderMoreTile() { + return ( + + More... + + ); + } } diff --git a/test/views/issueish-list-view.test.js b/test/views/issueish-list-view.test.js index e829b24ac8..3312d69d44 100644 --- a/test/views/issueish-list-view.test.js +++ b/test/views/issueish-list-view.test.js @@ -203,5 +203,19 @@ describe('IssueishListView', function() { wrapper.find('.github-Accordion-listItem').at(1).simulate('click'); assert.isTrue(onIssueishClick.calledWith(mixed)); }); + + it('calls its onMoreClick handler when a "more" component is clicked', function() { + const issueishes = [allGreen, mixed, allRed]; + const onMoreClick = sinon.stub(); + const wrapper = mount(buildApp({ + isLoading: false, + total: 4, + issueishes, + onMoreClick, + })); + + wrapper.find('a.github-IssueishList-more').simulate('click'); + assert.isTrue(onMoreClick.called); + }); }); }); From 3a24cfbf899135d9d79d832fff46c80f8c42404e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 11:40:36 -0400 Subject: [PATCH 0240/4847] Call onOpenSearch with the appropriate Search --- lib/controllers/issueish-list-controller.js | 2 +- test/controllers/issueish-list-controller.test.js | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index 56fadca7db..a217f54b6b 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -104,7 +104,7 @@ export class BareIssueishListController extends React.Component { pushInProgress={this.props.pushInProgress} onIssueishClick={this.props.onOpenIssueish} - onMoreClick={this.props.onOpenSearch} + onMoreClick={() => this.props.onOpenSearch(this.props.search)} onCreatePr={this.props.onCreatePr} /> ); diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index 9d4ce3833d..b053d99103 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -79,11 +79,18 @@ describe('IssueishListController', function() { }, }; + const search = new Search('aaa', 'zzz'); + const onOpenIssueish = sinon.stub(); + const onOpenSearch = sinon.stub(); + const wrapper = shallow(buildApp({ results: { issueCount: 1, nodes: [mockPullRequest], }, + search, + onOpenIssueish, + onOpenSearch, })); const view = wrapper.find('IssueishListView'); @@ -93,5 +100,12 @@ describe('IssueishListController', function() { assert.deepEqual(view.prop('issueishes'), [ new Issueish(mockPullRequest), ]); + + const payload = Symbol('payload'); + view.prop('onIssueishClick')(payload); + assert.isTrue(onOpenIssueish.calledWith(payload)); + + view.prop('onMoreClick')(); + assert.isTrue(onOpenSearch.calledWith(search)); }); }); From 4470838af3e1c031f11c15b75d714192646bd673 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 11:44:57 -0400 Subject: [PATCH 0241/4847] Make the query limit a prop --- .../issueishListContainerQuery.graphql.js | 22 +++++++++++++------ lib/containers/issueish-list-container.js | 10 +++++++-- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/containers/__generated__/issueishListContainerQuery.graphql.js b/lib/containers/__generated__/issueishListContainerQuery.graphql.js index da32bc00c5..a4f99d40ed 100644 --- a/lib/containers/__generated__/issueishListContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishListContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash b3e3bf197fd0e0eb104928d61effc8cb + * @relayHash ec5f922574bf14d6aac581ab40897b2d */ /* eslint-disable */ @@ -11,7 +11,8 @@ import type { ConcreteRequest } from 'relay-runtime'; type issueishListController_results$ref = any; export type issueishListContainerQueryVariables = {| - query: string + query: string, + first: number, |}; export type issueishListContainerQueryResponse = {| +search: {| @@ -24,8 +25,9 @@ export type issueishListContainerQueryResponse = {| /* query issueishListContainerQuery( $query: String! + $first: Int! ) { - search(first: 20, query: $query, type: ISSUE) { + search(first: $first, query: $query, type: ISSUE) { ...issueishListController_results } } @@ -82,13 +84,19 @@ var v0 = [ "name": "query", "type": "String!", "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "first", + "type": "Int!", + "defaultValue": null } ], v1 = [ { - "kind": "Literal", + "kind": "Variable", "name": "first", - "value": 20, + "variableName": "first", "type": "Int" }, { @@ -123,7 +131,7 @@ return { "operationKind": "query", "name": "issueishListContainerQuery", "id": null, - "text": "query issueishListContainerQuery(\n $query: String!\n) {\n search(first: 20, query: $query, type: ISSUE) {\n ...issueishListController_results\n }\n}\n\nfragment issueishListController_results on SearchResultItemConnection {\n issueCount\n nodes {\n __typename\n ... on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n headRepository {\n nameWithOwner\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n }\n ... on Node {\n id\n }\n }\n}\n", + "text": "query issueishListContainerQuery(\n $query: String!\n $first: Int!\n) {\n search(first: $first, query: $query, type: ISSUE) {\n ...issueishListController_results\n }\n}\n\nfragment issueishListController_results on SearchResultItemConnection {\n issueCount\n nodes {\n __typename\n ... on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n headRepository {\n nameWithOwner\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n }\n ... on Node {\n id\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -351,5 +359,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'ef13a7f2814860cf84f1c0da2d44d7ee'; +(node/*: any*/).hash = '0d4aa0d6130c16b2f95b7ef64820f9a2'; module.exports = node; diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index b8dec51c52..c5a9be766b 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -11,6 +11,7 @@ export default class IssueishListContainer extends React.Component { static propTypes = { token: PropTypes.string.isRequired, host: PropTypes.string.isRequired, + limit: PropTypes.number, repository: PropTypes.shape({ defaultBranchRef: PropTypes.shape({ @@ -30,6 +31,10 @@ export default class IssueishListContainer extends React.Component { onCreatePr: PropTypes.func.isRequired, } + static defaultProps = { + limit: 20, + } + constructor(props) { super(props); @@ -59,14 +64,15 @@ export default class IssueishListContainer extends React.Component { } const query = graphql` - query issueishListContainerQuery($query: String!) { - search(first: 20, query: $query, type: ISSUE) { + query issueishListContainerQuery($query: String!, $first: Int!) { + search(first: $first, query: $query, type: ISSUE) { ...issueishListController_results } } `; const variables = { query: this.props.search.createQuery(), + first: this.props.limit, }; return ( From 616060f9cf242d53b48963fd23baf3aee2656359 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 11:53:04 -0400 Subject: [PATCH 0242/4847] Style the "More..." link --- lib/views/issueish-list-view.js | 8 +++++--- styles/issuesish-list-view.less | 11 +++++++++++ test/views/issueish-list-view.test.js | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 5eb842c0e9..54d64314ac 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -113,9 +113,11 @@ export default class IssueishListView extends React.Component { renderMoreTile() { return ( - - More... - + ); } } diff --git a/styles/issuesish-list-view.less b/styles/issuesish-list-view.less index f176a17998..f13df27f9b 100644 --- a/styles/issuesish-list-view.less +++ b/styles/issuesish-list-view.less @@ -55,6 +55,17 @@ } } + + &-more { + margin: @component-padding / 4; + display: flex; + flex-direction: row; + justify-content: center; + a { + font-style: italic; + color: @text-color-subtle; + } + } } .github-CreatePullRequestTile { diff --git a/test/views/issueish-list-view.test.js b/test/views/issueish-list-view.test.js index 3312d69d44..f5859f181c 100644 --- a/test/views/issueish-list-view.test.js +++ b/test/views/issueish-list-view.test.js @@ -214,7 +214,7 @@ describe('IssueishListView', function() { onMoreClick, })); - wrapper.find('a.github-IssueishList-more').simulate('click'); + wrapper.find('.github-IssueishList-more a').simulate('click'); assert.isTrue(onMoreClick.called); }); }); From 21fe36413b50473f547e0e800438de9cf4ca9d92 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 11:54:44 -0400 Subject: [PATCH 0243/4847] Expect the first: query parameter --- test/containers/issueish-list-container.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/containers/issueish-list-container.test.js b/test/containers/issueish-list-container.test.js index 064037aca4..341b7ed454 100644 --- a/test/containers/issueish-list-container.test.js +++ b/test/containers/issueish-list-container.test.js @@ -105,6 +105,7 @@ describe('IssueishListContainer', function() { name: 'issueishListContainerQuery', variables: { query: 'type:pr author:me', + first: 20, }, }, { search: {issueCount: 0, nodes: []}, @@ -124,6 +125,7 @@ describe('IssueishListContainer', function() { name: 'issueishListContainerQuery', variables: { query: 'type:pr author:me', + first: 20, }, }, { search: { From 257306d595679fcad15b08a2fe04eac7ee6f3f14 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 12:48:59 -0400 Subject: [PATCH 0244/4847] :shirt: unused parameter --- lib/controllers/github-tab-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controllers/github-tab-controller.js b/lib/controllers/github-tab-controller.js index 2eed2ac43d..e82d5fa618 100644 --- a/lib/controllers/github-tab-controller.js +++ b/lib/controllers/github-tab-controller.js @@ -56,7 +56,7 @@ export default class GithubTabController extends React.Component { renderWithData(data) { const { - remotes, branches, selectedRemoteName, selectedPrUrl, aheadCount, + remotes, branches, selectedRemoteName, aheadCount, } = data; if (!this.props.repository.isPresent() || !remotes) { return null; From 511b71f4d6777fc2a9b66033f0ccf2d68b628b3b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Jun 2018 12:51:19 -0400 Subject: [PATCH 0245/4847] Assert against the arguments to workspace.open --- test/controllers/issueish-search-controller.test.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/controllers/issueish-search-controller.test.js b/test/controllers/issueish-search-controller.test.js index d9d937b690..5376724bcd 100644 --- a/test/controllers/issueish-search-controller.test.js +++ b/test/controllers/issueish-search-controller.test.js @@ -57,6 +57,8 @@ describe('IssueishSearchController', function() { }); it('passes a handler to open an issueish pane', async function() { + sinon.spy(atomEnv.workspace, 'open'); + const wrapper = shallow(buildApp()); const container = wrapper.find('IssueishListContainer').at(0); @@ -76,7 +78,12 @@ describe('IssueishSearchController', function() { commits: {nodes: []}, }); - const item = await container.prop('onOpenIssueish')(issueish); - assert.strictEqual(item.getURI(), 'atom-github:/issueish/https%3A%2F%2Fapi.github.com/atom/github/123'); + await container.prop('onOpenIssueish')(issueish); + assert.isTrue( + atomEnv.workspace.open.calledWith( + 'atom-github://issueish/https%3A%2F%2Fapi.github.com/atom/github/123', + {pending: true, searchAllPanes: true}, + ), + ); }); }); From 9b31cf3f21746732f5edf87036c3ad513a976423 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 15 Jun 2018 15:20:28 -0700 Subject: [PATCH 0246/4847] Render markdown flavored emojis in recent commits view. --- lib/views/recent-commits-view.js | 5 +- package-lock.json | 3087 ++++++++++++------------ package.json | 1 + test/views/recent-commits-view.test.js | 30 + 4 files changed, 1519 insertions(+), 1604 deletions(-) diff --git a/lib/views/recent-commits-view.js b/lib/views/recent-commits-view.js index 161af2f035..02b5590b87 100644 --- a/lib/views/recent-commits-view.js +++ b/lib/views/recent-commits-view.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import moment from 'moment'; import cx from 'classnames'; +import { emojify } from 'node-emoji'; import Timeago from './timeago'; @@ -21,8 +22,8 @@ class RecentCommitView extends React.Component { {this.renderAuthors()} - {this.props.commit.getMessageSubject()} + title={emojify(fullMessage)}> + {emojify(this.props.commit.getMessageSubject())} {this.props.isMostRecent && ( + )} + +
    +
+
+ ); + } + + renderDescription(description, key) { + if (this.props.preformatted) { + return ( +
+          {description}
+        
+ ); + } else { + return ( +

+ {description} +

+ ); + } + } +} From 53f8dae67dabda0cca80958f1c3ebb4bc5638395 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 18 Jun 2018 15:00:19 -0400 Subject: [PATCH 0254/4847] Extract a QueryErrorView to handle special case errors --- lib/views/query-error-view.js | 92 +++++++++++++++++++++++++++++ test/views/query-error-view.test.js | 58 ++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 lib/views/query-error-view.js create mode 100644 test/views/query-error-view.test.js diff --git a/lib/views/query-error-view.js b/lib/views/query-error-view.js new file mode 100644 index 0000000000..5fbd144424 --- /dev/null +++ b/lib/views/query-error-view.js @@ -0,0 +1,92 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import GithubLoginView from './github-login-view'; +import ErrorView from './error-view'; + +export default class QueryErrorView extends React.Component { + static propTypes = { + error: PropTypes.shape({ + name: PropTypes.string.isRequired, + message: PropTypes.string.isRequired, + stack: PropTypes.string.isRequired, + response: PropTypes.shape({ + status: PropTypes.number.isRequired, + text: PropTypes.func.isRequired, + }), + errors: PropTypes.arrayOf(PropTypes.shape({ + message: PropTypes.string.isRequired, + })), + }).isRequired, + login: PropTypes.func.isRequired, + retry: PropTypes.func, + logout: PropTypes.func, + } + + render() { + const e = this.props.error; + + if (e.response) { + switch (e.response.status) { + case 401: return this.render401(); + case 200: + // Do the default + break; + default: return this.renderUnknown(e.response); + } + } + + if (e.errors) { + return this.renderGraphQLErrors(e.errors); + } + + return ( + + ); + } + + renderGraphQLErrors(errors) { + return ( + e.message)} + {...this.errorViewProps()} + /> + ); + } + + render401() { + return ( +
+ +

+ The API endpoint returned a unauthorized error. Please try to re-authenticate with the endpoint. +

+
+
+ ); + } + + renderUnknown(response) { + return ( + + ); + } + + errorViewProps() { + return { + retry: this.props.retry, + logout: this.props.logout, + }; + } +} diff --git a/test/views/query-error-view.test.js b/test/views/query-error-view.test.js new file mode 100644 index 0000000000..e8d4e67362 --- /dev/null +++ b/test/views/query-error-view.test.js @@ -0,0 +1,58 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import QueryErrorView from '../../lib/views/query-error-view'; + +describe('QueryErrorView', function() { + function buildApp(overrideProps = {}) { + return ( + {}} + {...overrideProps} + /> + ); + } + + it('renders a GithubLoginView for a 401', function() { + const error = new Error('Unauthorized'); + error.response = {status: 401, text: () => ''}; + error.rawStack = error.stack; + const login = sinon.stub(); + + const wrapper = shallow(buildApp({error, login})); + assert.isTrue(wrapper.find('GithubLoginView').exists()); + assert.strictEqual(wrapper.find('GithubLoginView').prop('onLogin'), login); + }); + + it('renders GraphQL error messages', function() { + const error = new Error('GraphQL error'); + error.response = {status: 200, text: () => ''}; + error.errors = [ + {message: 'first error'}, + {message: 'second error'}, + ]; + error.rawStack = error.stack; + + const wrapper = shallow(buildApp({error})); + assert.isTrue(wrapper.find('ErrorView').someWhere(n => { + const ds = n.prop('descriptions'); + return ds.includes('first error') && ds.includes('second error'); + })); + }); + + it('renders the error response directly for an unrecognized error status', function() { + const error = new Error('GraphQL error'); + error.response = { + status: 500, + text: () => 'response text', + }; + error.rawStack = error.stack; + + const wrapper = shallow(buildApp({error})); + + assert.isTrue(wrapper.find('ErrorView').someWhere(n => { + return n.prop('descriptions').includes('response text') && n.prop('preformatted'); + })); + }); +}); From d519c6b48487ea195b90d50770126c993ff707c3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 18 Jun 2018 15:00:30 -0400 Subject: [PATCH 0255/4847] Render a QueryErrorView if a query fails --- lib/containers/remote-container.js | 14 +++++++++++++- test/containers/remote-container.test.js | 23 ++++++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/containers/remote-container.js b/lib/containers/remote-container.js index 7d6cfbb87c..ffb0a56337 100644 --- a/lib/containers/remote-container.js +++ b/lib/containers/remote-container.js @@ -9,6 +9,7 @@ import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; import RemoteController from '../controllers/remote-controller'; import ObserveModel from '../views/observe-model'; import LoadingView from '../views/loading-view'; +import QueryErrorView from '../views/query-error-view'; import GithubLoginView from '../views/github-login-view'; export default class RemoteContainer extends React.Component { @@ -90,7 +91,18 @@ export default class RemoteContainer extends React.Component { ); } - renderWithResult({error, props}, token) { + renderWithResult({error, props, retry}, token) { + if (error) { + return ( + + ); + } + if (props === null) { return ; } diff --git a/test/containers/remote-container.test.js b/test/containers/remote-container.test.js index 61b04c3844..7bea2ac113 100644 --- a/test/containers/remote-container.test.js +++ b/test/containers/remote-container.test.js @@ -33,6 +33,7 @@ describe('RemoteContainer', function() { host="https://api.github.com" + notifications={atomEnv.notifications} workspace={atomEnv.workspace} remote={origin} branches={branchSet} @@ -47,7 +48,7 @@ describe('RemoteContainer', function() { ); } - function expectSuccessfulQuery() { + function expectRepositoryQuery() { return expectRelayQuery({ name: 'remoteContainerQuery', variables: { @@ -71,6 +72,7 @@ describe('RemoteContainer', function() { name: 'issueishListContainerQuery', variables: { query: 'repo:atom/github type:pr state:open', + first: 20, }, }, { search: { @@ -86,7 +88,7 @@ describe('RemoteContainer', function() { }); it('renders a loading spinner while the GraphQL query is being performed', async function() { - expectSuccessfulQuery(); + expectRepositoryQuery(); model.setToken('https://api.github.com', '1234'); sinon.spy(model, 'getToken'); sinon.stub(model, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); @@ -117,8 +119,23 @@ describe('RemoteContainer', function() { assert.match(wrapper.update().find('GithubLoginView').find('p').text(), /sufficient/); }); + it('renders an error message if the GraphQL query fails', async function() { + const {reject} = expectRepositoryQuery(); + const e = new Error('oh shit!'); + e.rawStack = e.stack; + reject(e); + model.setToken('https://api.github.com', '1234'); + sinon.stub(model, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); + + const wrapper = mount(buildApp()); + await assert.async.isTrue(wrapper.update().find('QueryErrorView').exists()); + + const qev = wrapper.find('QueryErrorView'); + assert.strictEqual(qev.prop('error'), e); + }); + it('renders the controller once results have arrived', async function() { - const {resolve} = expectSuccessfulQuery(); + const {resolve} = expectRepositoryQuery(); expectEmptyIssueishQuery(); model.setToken('https://api.github.com', '1234'); sinon.stub(model, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); From 6decf552595f9cd3f88fb4fe85eb3cac6bd31acb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 18 Jun 2018 15:59:40 -0400 Subject: [PATCH 0256/4847] A tile to display if an error happened --- lib/views/query-error-tile.js | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 lib/views/query-error-tile.js diff --git a/lib/views/query-error-tile.js b/lib/views/query-error-tile.js new file mode 100644 index 0000000000..2a260fea9a --- /dev/null +++ b/lib/views/query-error-tile.js @@ -0,0 +1,49 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import Octicon from '../atom/octicon'; + +export default class QueryErrorTile extends React.Component { + static propTypes = { + error: PropTypes.shape({ + response: PropTypes.shape({ + status: PropTypes.number.isRequired, + }), + responseText: PropTypes.string, + errors: PropTypes.arrayOf(PropTypes.shape({ + message: PropTypes.string.isRequired, + })), + }).isRequired, + } + + render() { + return ( +
+ + {this.renderMessages()} +
+ ); + } + + renderMessages() { + if (this.props.error.errors) { + return this.props.error.errors.map((error, index) => { + return ( +

+ {error.message} +

+ ); + }); + } + + if (this.props.error.response) { + return ( +

+ {this.props.error.responseText} +

+ ); + } + + return

{this.props.error.toString()}

; + } +} From 6513455473c6df7b8815ffde9740354385262c15 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 18 Jun 2018 16:00:00 -0400 Subject: [PATCH 0257/4847] Pull out the response body asynchronously in the network layer --- lib/relay-network-layer-manager.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index cd0c6c4982..f8ba81a73f 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -96,6 +96,7 @@ function createFetchQuery(url) { if (response.status !== 200) { const e = new Error(`GraphQL API endpoint at ${url} returned ${response.status}`); e.response = response; + e.responseText = await response.text(); e.rawStack = e.stack; throw e; } From 16b64f84542e6b78bf01d913b0885af748bf636b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 18 Jun 2018 16:00:12 -0400 Subject: [PATCH 0258/4847] Parse and fail on GraphQL errors --- lib/relay-network-layer-manager.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index f8ba81a73f..31e5610bdd 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -101,7 +101,17 @@ function createFetchQuery(url) { throw e; } - return response.json(); + const payload = await response.json(); + + if (payload.data && payload.data.errors && payload.data.errors.length > 0) { + const e = new Error(`GraphQL API endpoint at ${url} returned an error for query ${operation.name}.`); + e.response = response; + e.errors = payload.data.errors; + e.rawStack = e.stack; + throw e; + } + + return payload; }; } From 6ffbc508afc8d96a66e4ac30c8641da2aed8416c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 18 Jun 2018 16:00:32 -0400 Subject: [PATCH 0259/4847] Pass and render query errors --- lib/containers/issueish-list-container.js | 60 ++++++++----------- lib/controllers/issueish-list-controller.js | 3 + lib/views/issueish-list-view.js | 7 +++ lib/views/query-error-view.js | 2 +- .../issueish-list-container.test.js | 25 ++++++++ test/views/issueish-list-view.test.js | 8 +++ 6 files changed, 70 insertions(+), 35 deletions(-) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index c5a9be766b..4fdde0382e 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -47,18 +47,8 @@ export default class IssueishListContainer extends React.Component { if (this.props.search.isNull()) { return ( ); } @@ -87,24 +77,20 @@ export default class IssueishListContainer extends React.Component { renderQueryResult({error, props}) { if (error) { - return null; + return ( + + ); } if (props === null) { return ( ); } @@ -112,19 +98,25 @@ export default class IssueishListContainer extends React.Component { return ( ); } + + controllerProps() { + return { + repository: this.props.repository, + + search: this.props.search, + remote: this.props.remote, + branches: this.props.branches, + aheadCount: this.props.aheadCount, + pushInProgress: this.props.pushInProgress, + + onOpenIssueish: this.props.onOpenIssueish, + onOpenSearch: this.props.onOpenSearch, + onCreatePr: this.props.onCreatePr, + }; + } } diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index a217f54b6b..97f3895bba 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -59,6 +59,8 @@ export class BareIssueishListController extends React.Component { onOpenIssueish: PropTypes.func.isRequired, onOpenSearch: PropTypes.func.isRequired, onCreatePr: PropTypes.func.isRequired, + + error: PropTypes.object, }; static defaultProps = { @@ -97,6 +99,7 @@ export class BareIssueishListController extends React.Component { issueishes={this.state.issueishes} repository={this.props.repository} + error={this.props.error} remote={this.props.remote} branches={this.props.branches} diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index 54d64314ac..4c6797e26b 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -7,6 +7,7 @@ import Accordion from './accordion'; import Timeago from './timeago'; import StatusDonutChart from './status-donut-chart'; import CreatePullRequestTile from './create-pull-request-tile'; +import QueryErrorTile from './query-error-tile'; import Octicon from '../atom/octicon'; export default class IssueishListView extends React.Component { @@ -31,6 +32,8 @@ export default class IssueishListView extends React.Component { onIssueishClick: PropTypes.func.isRequired, onMoreClick: PropTypes.func.isRequired, onCreatePr: PropTypes.func.isRequired, + + error: PropTypes.object, } constructor(props) { @@ -95,6 +98,10 @@ export default class IssueishListView extends React.Component { } renderEmptyTile() { + if (this.props.error) { + return ; + } + if (this.props.search.showCreateOnEmpty()) { return ( !n.prop('isLoading')).exists(), + ); + const controller = wrapper.find('BareIssueishListController'); + assert.strictEqual(controller.prop('error'), e); + assert.deepEqual(controller.prop('results'), { + issueCount: 0, + nodes: [], + }); + }); + it('passes results to the controller', async function() { const {promise, resolve} = expectRelayQuery({ name: 'issueishListContainerQuery', diff --git a/test/views/issueish-list-view.test.js b/test/views/issueish-list-view.test.js index f5859f181c..39aceea69c 100644 --- a/test/views/issueish-list-view.test.js +++ b/test/views/issueish-list-view.test.js @@ -153,6 +153,14 @@ describe('IssueishListView', function() { assert.isTrue(wrapper.find('CreatePullRequestTile').exists()); }); + + it('renders an error tile if an error is present', function() { + const error = new Error('error'); + error.rawStack = error.stack; + const wrapper = mount(buildApp({isLoading: false, error})); + + assert.isTrue(wrapper.find('QueryErrorTile').exists()); + }); }); describe('with nonempty results', function() { From 4519a1217313591aae9b672ee3451bebe6c7ed1a Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 18 Jun 2018 15:52:33 -0700 Subject: [PATCH 0260/4847] Make entire component for push/pull tile in status bar clickable. --- styles/push-pull-view.less | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/styles/push-pull-view.less b/styles/push-pull-view.less index 47687925d2..9888b64687 100644 --- a/styles/push-pull-view.less +++ b/styles/push-pull-view.less @@ -2,6 +2,11 @@ // Used in the status-bar +// click target should take up the width of the container +.push-pull-target { + display: inline-block; +} + .github-PushPull { &-icon.icon.icon.icon { margin-right: 0; From 5b06736c618062ca30f8f7a3b415e6cb8a0f6e7d Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 19 Jun 2018 17:02:50 +0900 Subject: [PATCH 0261/4847] Remove top border for UnstagedChanges --- styles/staging-view.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styles/staging-view.less b/styles/staging-view.less index 4452f038bc..7f429f1078 100644 --- a/styles/staging-view.less +++ b/styles/staging-view.less @@ -19,7 +19,7 @@ border-top: 1px solid @panel-heading-border-color; border-bottom: 1px solid @panel-heading-border-color; - .github-StagingView-group:first-child & { + .github-UnstagedChanges > & { border-top: none; } From bbd3f6fc468d935009a7b54590c547aba5294100 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 19 Jun 2018 09:50:59 -0400 Subject: [PATCH 0262/4847] Remove unused empty file --- lib/models/repository-operations.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lib/models/repository-operations.js diff --git a/lib/models/repository-operations.js b/lib/models/repository-operations.js deleted file mode 100644 index e69de29bb2..0000000000 From c7c1f5e73c80684490f8e387c16b1c67ed040c62 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 19 Jun 2018 09:51:16 -0400 Subject: [PATCH 0263/4847] OperationStateObserver to observe changes in operation state --- lib/models/operation-state-observer.js | 60 ++++++++++++++++++ test/models/operation-state-observer.test.js | 66 ++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 lib/models/operation-state-observer.js create mode 100644 test/models/operation-state-observer.test.js diff --git a/lib/models/operation-state-observer.js b/lib/models/operation-state-observer.js new file mode 100644 index 0000000000..ee39a80a55 --- /dev/null +++ b/lib/models/operation-state-observer.js @@ -0,0 +1,60 @@ +import {Emitter} from 'event-kit'; + +export const PUSH = { + getter(o) { + return o.isPushInProgress(); + }, +}; + +export const PULL = { + getter(o) { + return o.isPullInProgress(); + }, +}; + +export const FETCH = { + getter(o) { + return o.isFetchInProgress(); + }, +}; + +// Notify subscibers when a repository completes one or more operations of interest, as observed by its OperationState +// transitioning from `true` to `false`. For exampe, use this to perform actions when a push completes. +export default class OperationStateObserver { + constructor(repository, ...operations) { + this.repository = repository; + this.operations = new Set(operations); + this.emitter = new Emitter(); + + this.lastStates = new Map(); + for (const operation of this.operations) { + this.lastStates.set(operation, operation.getter(this.repository.getOperationStates())); + } + + this.sub = this.repository.onDidUpdate(this.handleUpdate.bind(this)); + } + + onDidComplete(handler) { + return this.emitter.on('did-complete', handler); + } + + handleUpdate() { + let fire = false; + for (const operation of this.operations) { + const last = this.lastStates.get(operation); + const current = operation.getter(this.repository.getOperationStates()); + if (last && !current) { + fire = true; + } + this.lastStates.set(operation, current); + } + if (fire) { + this.emitter.emit('did-complete'); + } + } + + dispose() { + this.emitter.dispose(); + this.sub.dispose(); + } +} diff --git a/test/models/operation-state-observer.test.js b/test/models/operation-state-observer.test.js new file mode 100644 index 0000000000..ea8cb4a60a --- /dev/null +++ b/test/models/operation-state-observer.test.js @@ -0,0 +1,66 @@ +import {CompositeDisposable} from 'event-kit'; + +import {setUpLocalAndRemoteRepositories} from '../helpers'; +import Repository from '../../lib/models/repository'; +import getRepoPipelineManager from '../../lib/get-repo-pipeline-manager'; +import OperationStateObserver, {PUSH, FETCH} from '../../lib/models/operation-state-observer'; + +describe('OperationStateObserver', function() { + let atomEnv, repository, observer, subs, handler; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + + handler = sinon.stub(); + + const {localRepoPath} = await setUpLocalAndRemoteRepositories('multiple-commits'); + repository = new Repository(localRepoPath, null, { + pipelineManager: getRepoPipelineManager({ + confirm: () => true, + notificationManager: atomEnv.notifications, + workspace: atomEnv.workspace, + }), + }); + await repository.getLoadPromise(); + + subs = new CompositeDisposable(); + }); + + afterEach(function() { + observer && observer.dispose(); + subs.dispose(); + atomEnv.destroy(); + }); + + it('triggers an update event when the observed repository completes an operation', async function() { + observer = new OperationStateObserver(repository, PUSH); + subs.add(observer.onDidComplete(handler)); + + const operation = repository.push('master'); + assert.isFalse(handler.called); + await operation; + assert.isTrue(handler.called); + }); + + it('does not trigger an update event when the observed repository is unchanged', async function() { + observer = new OperationStateObserver(repository, FETCH); + subs.add(observer.onDidComplete(handler)); + + await repository.push('master'); + assert.isFalse(handler.called); + }); + + it('subscribes to multiple events', async function() { + observer = new OperationStateObserver(repository, FETCH, PUSH); + subs.add(observer.onDidComplete(handler)); + + await repository.push('master'); + assert.strictEqual(handler.callCount, 1); + + await repository.fetch('master'); + assert.strictEqual(handler.callCount, 2); + + await repository.pull('origin', 'master'); + assert.strictEqual(handler.callCount, 2); + }); +}); From f66ed4611482f0eb0400276aed69331ec0730cdd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 19 Jun 2018 11:55:58 -0400 Subject: [PATCH 0264/4847] PropType for an OperationStateObserver --- lib/prop-types.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/prop-types.js b/lib/prop-types.js index 8855db50a6..b34e868bd2 100644 --- a/lib/prop-types.js +++ b/lib/prop-types.js @@ -70,6 +70,11 @@ export const RefHolderPropType = PropTypes.shape({ observe: PropTypes.func.isRequired, }); +export const OperationStateObserverPropType = PropTypes.shape({ + onDidComplete: PropTypes.func.isRequired, + dispose: PropTypes.func.isRequired, +}); + export const FilePatchItemPropType = PropTypes.shape({ filePath: PropTypes.string.isRequired, status: PropTypes.string.isRequired, From 0f3922ed687b4a6b5f863bc0cb1eeadb46d268de Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 19 Jun 2018 11:57:33 -0400 Subject: [PATCH 0265/4847] Derive an observer to trigger events when a remote operation completes --- lib/controllers/github-tab-controller.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/controllers/github-tab-controller.js b/lib/controllers/github-tab-controller.js index e82d5fa618..a777033c0a 100644 --- a/lib/controllers/github-tab-controller.js +++ b/lib/controllers/github-tab-controller.js @@ -5,6 +5,7 @@ import yubikiri from 'yubikiri'; import RemoteSelectorView from '../views/remote-selector-view'; import RemoteContainer from '../containers/remote-container'; import GithubLoginModel from '../models/github-login-model'; +import OperationStateObserver, {PUSH, PULL, FETCH} from '../models/operation-state-observer'; import ObserveModel from '../views/observe-model'; import {autobind} from '../helpers'; @@ -18,6 +19,19 @@ export default class GithubTabController extends React.Component { constructor(props) { super(props); autobind(this, 'handleRemoteSelect'); + + this.state = {}; + } + + static getDerivedStateFromProps(props, state) { + if (props.repository !== state.lastRepository) { + return { + lastRepository: props.repository, + remoteOperationObserver: new OperationStateObserver(props.repository, PUSH, PULL, FETCH), + }; + } + + return null; } fetchModelData(repo) { From 18e2da6b126a6e0f8c1fe2ea5ec27f670f8aee1e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 19 Jun 2018 11:58:25 -0400 Subject: [PATCH 0266/4847] Brrm brrm, prop drilling --- lib/containers/issueish-list-container.js | 3 ++- lib/containers/remote-container.js | 4 +++- lib/controllers/github-tab-controller.js | 1 + lib/controllers/issueish-search-controller.js | 4 +++- lib/controllers/remote-controller.js | 4 +++- lib/models/operation-state-observer.js | 5 +++++ test/containers/remote-container.test.js | 2 ++ test/controllers/issueish-search-controller.test.js | 2 ++ test/controllers/remote-controller.test.js | 2 ++ 9 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index 4fdde0382e..e6c9afbbb2 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {QueryRenderer, graphql} from 'react-relay'; import {autobind} from '../helpers'; -import {SearchPropType, RemotePropType, BranchSetPropType} from '../prop-types'; +import {SearchPropType, RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; import IssueishListController, {BareIssueishListController} from '../controllers/issueish-list-controller'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; @@ -20,6 +20,7 @@ export default class IssueishListContainer extends React.Component { }), }), + remoteOperationObserver: OperationStateObserverPropType.isRequired, search: SearchPropType.isRequired, remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, diff --git a/lib/containers/remote-container.js b/lib/containers/remote-container.js index ffb0a56337..6c81584cc0 100644 --- a/lib/containers/remote-container.js +++ b/lib/containers/remote-container.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {QueryRenderer, graphql} from 'react-relay'; import {autobind} from '../helpers'; -import {RemotePropType, BranchSetPropType} from '../prop-types'; +import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; import RemoteController from '../controllers/remote-controller'; @@ -18,6 +18,7 @@ export default class RemoteContainer extends React.Component { host: PropTypes.string.isRequired, + remoteOperationObserver: OperationStateObserverPropType.isRequired, workspace: PropTypes.object.isRequired, remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, @@ -114,6 +115,7 @@ export default class RemoteContainer extends React.Component { repository={props.repository} + remoteOperationObserver={this.props.remoteOperationObserver} workspace={this.props.workspace} remote={this.props.remote} branches={this.props.branches} diff --git a/lib/controllers/github-tab-controller.js b/lib/controllers/github-tab-controller.js index a777033c0a..f63ac293e3 100644 --- a/lib/controllers/github-tab-controller.js +++ b/lib/controllers/github-tab-controller.js @@ -96,6 +96,7 @@ export default class GithubTabController extends React.Component { this.handlePushBranch(currentBranch, remote)} remote={remote} diff --git a/lib/controllers/issueish-search-controller.js b/lib/controllers/issueish-search-controller.js index 1e7d9709f3..6d0b390922 100644 --- a/lib/controllers/issueish-search-controller.js +++ b/lib/controllers/issueish-search-controller.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {shell} from 'electron'; import {autobind} from '../helpers'; -import {RemotePropType, BranchSetPropType} from '../prop-types'; +import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; import Search from '../models/search'; import IssueishListContainer from '../containers/issueish-list-container'; import IssueishPaneItem from '../items/issueish-pane-item'; @@ -21,6 +21,7 @@ export default class IssueishSearchController extends React.Component { }), }), + remoteOperationObserver: OperationStateObserverPropType.isRequired, remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, aheadCount: PropTypes.number, @@ -57,6 +58,7 @@ export default class IssueishSearchController extends React.Component { repository={this.props.repository} + remoteOperationObserver={this.props.remoteOperationObserver} search={search} remote={this.props.remote} branches={this.props.branches} diff --git a/lib/controllers/remote-controller.js b/lib/controllers/remote-controller.js index 3b710caea4..a6fc299ce2 100644 --- a/lib/controllers/remote-controller.js +++ b/lib/controllers/remote-controller.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {shell} from 'electron'; import {autobind} from '../helpers'; -import {RemotePropType, BranchSetPropType} from '../prop-types'; +import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; import IssueishSearchController from './issueish-search-controller'; export default class RemoteController extends React.Component { @@ -18,6 +18,7 @@ export default class RemoteController extends React.Component { }), }), + remoteOperationObserver: OperationStateObserverPropType.isRequired, workspace: PropTypes.object.isRequired, remote: RemotePropType.isRequired, branches: BranchSetPropType.isRequired, @@ -39,6 +40,7 @@ export default class RemoteController extends React.Component { host={this.props.host} token={this.props.token} + remoteOperationObserver={this.props.remoteOperationObserver} repository={this.props.repository} workspace={this.props.workspace} diff --git a/lib/models/operation-state-observer.js b/lib/models/operation-state-observer.js index ee39a80a55..df63767347 100644 --- a/lib/models/operation-state-observer.js +++ b/lib/models/operation-state-observer.js @@ -58,3 +58,8 @@ export default class OperationStateObserver { this.sub.dispose(); } } + +export const nullOperationStateObserver = { + onDidComplete() {}, + dispose() {}, +}; diff --git a/test/containers/remote-container.test.js b/test/containers/remote-container.test.js index 7bea2ac113..c8da959a91 100644 --- a/test/containers/remote-container.test.js +++ b/test/containers/remote-container.test.js @@ -5,6 +5,7 @@ import Remote from '../../lib/models/remote'; import Branch, {nullBranch} from '../../lib/models/branch'; import BranchSet from '../../lib/models/branch-set'; import GithubLoginModel from '../../lib/models/github-login-model'; +import {nullOperationStateObserver} from '../../lib/models/operation-state-observer'; import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; import RemoteContainer from '../../lib/containers/remote-container'; import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; @@ -33,6 +34,7 @@ describe('RemoteContainer', function() { host="https://api.github.com" + remoteOperationObserver={nullOperationStateObserver} notifications={atomEnv.notifications} workspace={atomEnv.workspace} remote={origin} diff --git a/test/controllers/issueish-search-controller.test.js b/test/controllers/issueish-search-controller.test.js index 5376724bcd..6a533a6615 100644 --- a/test/controllers/issueish-search-controller.test.js +++ b/test/controllers/issueish-search-controller.test.js @@ -6,6 +6,7 @@ import Remote from '../../lib/models/remote'; import Branch from '../../lib/models/branch'; import BranchSet from '../../lib/models/branch-set'; import Issueish from '../../lib/models/issueish'; +import {nullOperationStateObserver} from '../../lib/models/operation-state-observer'; describe('IssueishSearchController', function() { let atomEnv; @@ -31,6 +32,7 @@ describe('IssueishSearchController', function() { host="https://api.github.com" repository={null} + remoteOperationObserver={nullOperationStateObserver} workspace={atomEnv.workspace} remote={origin} branches={branches} diff --git a/test/controllers/remote-controller.test.js b/test/controllers/remote-controller.test.js index 56c763b6ce..e4736f7ce5 100644 --- a/test/controllers/remote-controller.test.js +++ b/test/controllers/remote-controller.test.js @@ -4,6 +4,7 @@ import {shallow} from 'enzyme'; import BranchSet from '../../lib/models/branch-set'; import Branch, {nullBranch} from '../../lib/models/branch'; import Remote from '../../lib/models/remote'; +import {nullOperationStateObserver} from '../../lib/models/operation-state-observer'; import RemoteController from '../../lib/controllers/remote-controller'; describe('RemoteController', function() { @@ -32,6 +33,7 @@ describe('RemoteController', function() { repository={null} + remoteOperationObserver={nullOperationStateObserver} workspace={atomEnv.workspace} remote={remote} branches={branchSet} From f32ef297e1ed4b61e66c823d04375e73ffe3db05 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 19 Jun 2018 11:58:51 -0400 Subject: [PATCH 0267/4847] Retry issueish searches on remote operation completion --- lib/containers/issueish-list-container.js | 15 +++- .../issueish-list-container.test.js | 77 +++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-list-container.js index e6c9afbbb2..d5eff3cd9a 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-list-container.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {QueryRenderer, graphql} from 'react-relay'; +import {Disposable} from 'event-kit'; import {autobind} from '../helpers'; import {SearchPropType, RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; @@ -38,8 +39,9 @@ export default class IssueishListContainer extends React.Component { constructor(props) { super(props); - autobind(this, 'renderQueryResult'); + + this.sub = new Disposable(); } render() { @@ -76,7 +78,12 @@ export default class IssueishListContainer extends React.Component { ); } - renderQueryResult({error, props}) { + renderQueryResult({error, props, retry}) { + if (retry) { + this.sub.dispose(); + this.sub = this.props.remoteOperationObserver.onDidComplete(retry); + } + if (error) { return ( node.number === 1), + ); + + disable0(); + const {promise: promise1, resolve: resolve1} = expectRelayQuery({ + name: 'issueishListContainerQuery', + variables: { + query: 'type:pr author:me', + first: 20, + }, + }, { + search: { + issueCount: 1, + nodes: [createPullRequest(2)], + }, + }); + + resolve1(); + await promise1; + + assert.isTrue( + wrapper.update().find('BareIssueishListController').prop('results').nodes.some(node => node.number === 1), + ); + + observer.trigger(); + + await assert.async.isTrue( + wrapper.update().find('BareIssueishListController').prop('results').nodes.some(node => node.number === 2), + ); + }); }); From ba578be610da0dd6418d4f2e6dd78826ca4c1990 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Tue, 19 Jun 2018 16:25:39 +0000 Subject: [PATCH 0268/4847] fix(package): update prop-types to version 15.6.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3917389843..e5624d73d4 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "lodash.memoize": "4.1.2", "moment": "2.22.2", "node-emoji": "^1.8.1", - "prop-types": "15.6.1", + "prop-types": "15.6.2", "react": "16.4.1", "react-dom": "16.4.1", "react-relay": "1.6.0", From 2f9d62763be29e6dbdf1b19fbdba1cee0fe7a416 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 19 Jun 2018 13:48:49 -0400 Subject: [PATCH 0269/4847] No need to fetch headRepository info --- .../issueishListContainerQuery.graphql.js | 27 ++----------------- .../issueishListController_results.graphql.js | 23 +--------------- lib/controllers/issueish-list-controller.js | 7 ----- lib/models/issueish.js | 5 ---- 4 files changed, 3 insertions(+), 59 deletions(-) diff --git a/lib/containers/__generated__/issueishListContainerQuery.graphql.js b/lib/containers/__generated__/issueishListContainerQuery.graphql.js index a4f99d40ed..9500092c29 100644 --- a/lib/containers/__generated__/issueishListContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishListContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash ec5f922574bf14d6aac581ab40897b2d + * @relayHash 9fb1454ccb490273b6c71aeaa13487fe */ /* eslint-disable */ @@ -50,10 +50,6 @@ fragment issueishListController_results on SearchResultItemConnection { } createdAt headRefName - headRepository { - nameWithOwner - id - } commits(last: 1) { nodes { commit { @@ -131,7 +127,7 @@ return { "operationKind": "query", "name": "issueishListContainerQuery", "id": null, - "text": "query issueishListContainerQuery(\n $query: String!\n $first: Int!\n) {\n search(first: $first, query: $query, type: ISSUE) {\n ...issueishListController_results\n }\n}\n\nfragment issueishListController_results on SearchResultItemConnection {\n issueCount\n nodes {\n __typename\n ... on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n headRepository {\n nameWithOwner\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n }\n ... on Node {\n id\n }\n }\n}\n", + "text": "query issueishListContainerQuery(\n $query: String!\n $first: Int!\n) {\n search(first: $first, query: $query, type: ISSUE) {\n ...issueishListController_results\n }\n}\n\nfragment issueishListController_results on SearchResultItemConnection {\n issueCount\n nodes {\n __typename\n ... on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n }\n ... on Node {\n id\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -256,25 +252,6 @@ return { "args": null, "storageKey": null }, - { - "kind": "LinkedField", - "alias": null, - "name": "headRepository", - "storageKey": null, - "args": null, - "concreteType": "Repository", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "nameWithOwner", - "args": null, - "storageKey": null - }, - v3 - ] - }, { "kind": "LinkedField", "alias": null, diff --git a/lib/controllers/__generated__/issueishListController_results.graphql.js b/lib/controllers/__generated__/issueishListController_results.graphql.js index 1a88e6b10f..4783fe1827 100644 --- a/lib/controllers/__generated__/issueishListController_results.graphql.js +++ b/lib/controllers/__generated__/issueishListController_results.graphql.js @@ -23,9 +23,6 @@ export type issueishListController_results = {| |}, +createdAt?: any, +headRefName?: string, - +headRepository?: ?{| - +nameWithOwner: string - |}, +commits?: {| +nodes: ?$ReadOnlyArray { const status = node.commit.status; if (status !== null) { @@ -52,10 +51,6 @@ export default class Issueish { return this.headRefName; } - getHeadRepositoryName() { - return this.headRepositoryName; - } - getStatusCounts() { return this.statusContexts.reduce((acc, context) => { acc[category(context.state).toLowerCase()]++; From af2942f992ae73bac0a17d0eb27106b721588f2c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 19 Jun 2018 15:32:17 -0400 Subject: [PATCH 0270/4847] Refactor component hierarchy --- ...> issueishSearchContainerQuery.graphql.js} | 130 +++++----- ...tainer.js => issueish-search-container.js} | 40 +-- .../issueishListController_results.graphql.js | 239 ++++++++---------- lib/controllers/issueish-list-controller.js | 145 +++++------ ...ler.js => issueish-searches-controller.js} | 6 +- lib/controllers/remote-controller.js | 4 +- lib/views/issueish-list-view.js | 27 +- ...t.js => issueish-search-container.test.js} | 88 ++----- .../issueish-list-controller.test.js | 33 +-- ...s => issueish-searches-controller.test.js} | 12 +- test/controllers/remote-controller.test.js | 2 +- test/helpers.js | 19 ++ test/views/issueish-list-view.test.js | 26 +- 13 files changed, 335 insertions(+), 436 deletions(-) rename lib/containers/__generated__/{issueishListContainerQuery.graphql.js => issueishSearchContainerQuery.graphql.js} (77%) rename lib/containers/{issueish-list-container.js => issueish-search-container.js} (69%) rename lib/controllers/{issueish-search-controller.js => issueish-searches-controller.js} (93%) rename test/containers/{issueish-list-container.test.js => issueish-search-container.test.js} (72%) rename test/controllers/{issueish-search-controller.test.js => issueish-searches-controller.test.js} (84%) diff --git a/lib/containers/__generated__/issueishListContainerQuery.graphql.js b/lib/containers/__generated__/issueishSearchContainerQuery.graphql.js similarity index 77% rename from lib/containers/__generated__/issueishListContainerQuery.graphql.js rename to lib/containers/__generated__/issueishSearchContainerQuery.graphql.js index 9500092c29..938e2f2365 100644 --- a/lib/containers/__generated__/issueishListContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishSearchContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 9fb1454ccb490273b6c71aeaa13487fe + * @relayHash 094129e5934b60cf04cd1ba9494cdfb5 */ /* eslint-disable */ @@ -10,63 +10,64 @@ /*:: import type { ConcreteRequest } from 'relay-runtime'; type issueishListController_results$ref = any; -export type issueishListContainerQueryVariables = {| +export type issueishSearchContainerQueryVariables = {| query: string, first: number, |}; -export type issueishListContainerQueryResponse = {| +export type issueishSearchContainerQueryResponse = {| +search: {| - +$fragmentRefs: issueishListController_results$ref + +issueCount: number, + +nodes: ?$ReadOnlyArray, |} |}; */ /* -query issueishListContainerQuery( +query issueishSearchContainerQuery( $query: String! $first: Int! ) { search(first: $first, query: $query, type: ISSUE) { - ...issueishListController_results + issueCount + nodes { + __typename + ...issueishListController_results + ... on Node { + id + } + } } } -fragment issueishListController_results on SearchResultItemConnection { - issueCount - nodes { +fragment issueishListController_results on PullRequest { + number + title + url + author { __typename - ... on PullRequest { - number - title - url - author { - __typename - login - avatarUrl - ... on Node { - id - } - } - createdAt - headRefName - commits(last: 1) { - nodes { - commit { - status { - contexts { - state - id - } - id - } + login + avatarUrl + ... on Node { + id + } + } + createdAt + headRefName + commits(last: 1) { + nodes { + commit { + status { + contexts { + state id } id } + id } - } - ... on Node { id } } @@ -111,11 +112,18 @@ v1 = [ v2 = { "kind": "ScalarField", "alias": null, - "name": "__typename", + "name": "issueCount", "args": null, "storageKey": null }, v3 = { + "kind": "ScalarField", + "alias": null, + "name": "__typename", + "args": null, + "storageKey": null +}, +v4 = { "kind": "ScalarField", "alias": null, "name": "id", @@ -125,13 +133,13 @@ v3 = { return { "kind": "Request", "operationKind": "query", - "name": "issueishListContainerQuery", + "name": "issueishSearchContainerQuery", "id": null, - "text": "query issueishListContainerQuery(\n $query: String!\n $first: Int!\n) {\n search(first: $first, query: $query, type: ISSUE) {\n ...issueishListController_results\n }\n}\n\nfragment issueishListController_results on SearchResultItemConnection {\n issueCount\n nodes {\n __typename\n ... on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n }\n ... on Node {\n id\n }\n }\n}\n", + "text": "query issueishSearchContainerQuery(\n $query: String!\n $first: Int!\n) {\n search(first: $first, query: $query, type: ISSUE) {\n issueCount\n nodes {\n __typename\n ...issueishListController_results\n ... on Node {\n id\n }\n }\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", - "name": "issueishListContainerQuery", + "name": "issueishSearchContainerQuery", "type": "Query", "metadata": null, "argumentDefinitions": v0, @@ -145,10 +153,22 @@ return { "concreteType": "SearchResultItemConnection", "plural": false, "selections": [ + v2, { - "kind": "FragmentSpread", - "name": "issueishListController_results", - "args": null + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": true, + "selections": [ + { + "kind": "FragmentSpread", + "name": "issueishListController_results", + "args": null + } + ] } ] } @@ -156,7 +176,7 @@ return { }, "operation": { "kind": "Operation", - "name": "issueishListContainerQuery", + "name": "issueishSearchContainerQuery", "argumentDefinitions": v0, "selections": [ { @@ -168,13 +188,7 @@ return { "concreteType": "SearchResultItemConnection", "plural": false, "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "issueCount", - "args": null, - "storageKey": null - }, + v2, { "kind": "LinkedField", "alias": null, @@ -184,8 +198,8 @@ return { "concreteType": null, "plural": true, "selections": [ - v2, v3, + v4, { "kind": "InlineFragment", "type": "PullRequest", @@ -220,7 +234,7 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, + v3, { "kind": "ScalarField", "alias": null, @@ -235,7 +249,7 @@ return { "args": null, "storageKey": null }, - v3 + v4 ] }, { @@ -311,16 +325,16 @@ return { "args": null, "storageKey": null }, - v3 + v4 ] }, - v3 + v4 ] }, - v3 + v4 ] }, - v3 + v4 ] } ] @@ -336,5 +350,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '0d4aa0d6130c16b2f95b7ef64820f9a2'; +(node/*: any*/).hash = 'fc553ba742c51417ea1a857b96038345'; module.exports = node; diff --git a/lib/containers/issueish-list-container.js b/lib/containers/issueish-search-container.js similarity index 69% rename from lib/containers/issueish-list-container.js rename to lib/containers/issueish-search-container.js index d5eff3cd9a..a937113658 100644 --- a/lib/containers/issueish-list-container.js +++ b/lib/containers/issueish-search-container.js @@ -4,33 +4,20 @@ import {QueryRenderer, graphql} from 'react-relay'; import {Disposable} from 'event-kit'; import {autobind} from '../helpers'; -import {SearchPropType, RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; +import {SearchPropType, OperationStateObserverPropType} from '../prop-types'; import IssueishListController, {BareIssueishListController} from '../controllers/issueish-list-controller'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; -export default class IssueishListContainer extends React.Component { +export default class IssueishSearchContainer extends React.Component { static propTypes = { token: PropTypes.string.isRequired, host: PropTypes.string.isRequired, limit: PropTypes.number, - - repository: PropTypes.shape({ - defaultBranchRef: PropTypes.shape({ - prefix: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - }), - }), - - remoteOperationObserver: OperationStateObserverPropType.isRequired, search: SearchPropType.isRequired, - remote: RemotePropType.isRequired, - branches: BranchSetPropType.isRequired, - aheadCount: PropTypes.number, - pushInProgress: PropTypes.bool.isRequired, + remoteOperationObserver: OperationStateObserverPropType.isRequired, onOpenIssueish: PropTypes.func.isRequired, onOpenSearch: PropTypes.func.isRequired, - onCreatePr: PropTypes.func.isRequired, } static defaultProps = { @@ -57,9 +44,12 @@ export default class IssueishListContainer extends React.Component { } const query = graphql` - query issueishListContainerQuery($query: String!, $first: Int!) { + query issueishSearchContainerQuery($query: String!, $first: Int!) { search(first: $first, query: $query, type: ISSUE) { - ...issueishListController_results + issueCount + nodes { + ...issueishListController_results + } } } `; @@ -105,7 +95,8 @@ export default class IssueishListContainer extends React.Component { return ( @@ -118,17 +109,10 @@ export default class IssueishListContainer extends React.Component { controllerProps() { return { - repository: this.props.repository, - - search: this.props.search, - remote: this.props.remote, - branches: this.props.branches, - aheadCount: this.props.aheadCount, - pushInProgress: this.props.pushInProgress, + title: this.props.search.getName(), onOpenIssueish: this.props.onOpenIssueish, - onOpenSearch: this.props.onOpenSearch, - onCreatePr: this.props.onCreatePr, + onOpenMore: () => this.props.onOpenSearch(this.props.search), }; } } diff --git a/lib/controllers/__generated__/issueishListController_results.graphql.js b/lib/controllers/__generated__/issueishListController_results.graphql.js index 4783fe1827..ed982c63ec 100644 --- a/lib/controllers/__generated__/issueishListController_results.graphql.js +++ b/lib/controllers/__generated__/issueishListController_results.graphql.js @@ -11,184 +11,159 @@ import type { ConcreteFragment } from 'relay-runtime'; export type StatusState = "ERROR" | "EXPECTED" | "FAILURE" | "PENDING" | "SUCCESS" | "%future added value"; import type { FragmentReference } from "relay-runtime"; declare export opaque type issueishListController_results$ref: FragmentReference; -export type issueishListController_results = {| - +issueCount: number, - +nodes: ?$ReadOnlyArray - |} +export type issueishListController_results = $ReadOnlyArray<{| + +number: number, + +title: string, + +url: any, + +author: ?{| + +login: string, + +avatarUrl: any, + |}, + +createdAt: any, + +headRefName: string, + +commits: {| + +nodes: ?$ReadOnlyArray |} - |}> - |}, - |}>, + |} + |}> + |}, +$refType: issueishListController_results$ref, -|}; +|}>; */ const node/*: ConcreteFragment*/ = { "kind": "Fragment", "name": "issueishListController_results", - "type": "SearchResultItemConnection", - "metadata": null, + "type": "PullRequest", + "metadata": { + "plural": true + }, "argumentDefinitions": [], "selections": [ { "kind": "ScalarField", "alias": null, - "name": "issueCount", + "name": "number", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "title", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "url", "args": null, "storageKey": null }, { "kind": "LinkedField", "alias": null, - "name": "nodes", + "name": "author", "storageKey": null, "args": null, "concreteType": null, - "plural": true, + "plural": false, "selections": [ { - "kind": "InlineFragment", - "type": "PullRequest", + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "headRefName", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "commits", + "storageKey": "commits(last:1)", + "args": [ + { + "kind": "Literal", + "name": "last", + "value": 1, + "type": "Int" + } + ], + "concreteType": "PullRequestCommitConnection", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestCommit", + "plural": true, "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "number", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "title", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "url", - "args": null, - "storageKey": null - }, { "kind": "LinkedField", "alias": null, - "name": "author", + "name": "commit", "storageKey": null, "args": null, - "concreteType": null, - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - } - ] - }, - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "headRefName", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "commits", - "storageKey": "commits(last:1)", - "args": [ - { - "kind": "Literal", - "name": "last", - "value": 1, - "type": "Int" - } - ], - "concreteType": "PullRequestCommitConnection", + "concreteType": "Commit", "plural": false, "selections": [ { "kind": "LinkedField", "alias": null, - "name": "nodes", + "name": "status", "storageKey": null, "args": null, - "concreteType": "PullRequestCommit", - "plural": true, + "concreteType": "Status", + "plural": false, "selections": [ { "kind": "LinkedField", "alias": null, - "name": "commit", + "name": "contexts", "storageKey": null, "args": null, - "concreteType": "Commit", - "plural": false, + "concreteType": "StatusContext", + "plural": true, "selections": [ { - "kind": "LinkedField", + "kind": "ScalarField", "alias": null, - "name": "status", - "storageKey": null, + "name": "state", "args": null, - "concreteType": "Status", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "contexts", - "storageKey": null, - "args": null, - "concreteType": "StatusContext", - "plural": true, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "state", - "args": null, - "storageKey": null - } - ] - } - ] + "storageKey": null } ] } @@ -203,5 +178,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = 'e277ef6e6a231561917cc594183abcc9'; +(node/*: any*/).hash = '62daf941cfeb69f21418ceee8c3282c0'; module.exports = node; diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index 24501709c1..e27ff583a6 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -2,7 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import {graphql, createFragmentContainer} from 'react-relay'; -import {SearchPropType, RemotePropType, BranchSetPropType} from '../prop-types'; import IssueishListView from '../views/issueish-list-view'; import Issueish from '../models/issueish'; @@ -10,61 +9,44 @@ const StatePropType = PropTypes.oneOf(['EXPECTED', 'PENDING', 'SUCCESS', 'ERROR' export class BareIssueishListController extends React.Component { static propTypes = { - results: PropTypes.shape({ - issueCount: PropTypes.number.isRequired, - nodes: PropTypes.arrayOf( - PropTypes.shape({ - number: PropTypes.number.isRequired, - title: PropTypes.string.isRequired, - url: PropTypes.string.isRequired, - author: PropTypes.shape({ - login: PropTypes.string.isRequired, - avatarUrl: PropTypes.string.isRequired, - }).isRequired, - createdAt: PropTypes.string.isRequired, - headRefName: PropTypes.string.isRequired, - commits: PropTypes.shape({ - nodes: PropTypes.arrayOf(PropTypes.shape({ - commit: PropTypes.shape({ - status: PropTypes.shape({ - contexts: PropTypes.arrayOf( - PropTypes.shape({ - state: StatePropType.isRequired, - }).isRequired, - ).isRequired, - }), + results: PropTypes.arrayOf( + PropTypes.shape({ + number: PropTypes.number.isRequired, + title: PropTypes.string.isRequired, + url: PropTypes.string.isRequired, + author: PropTypes.shape({ + login: PropTypes.string.isRequired, + avatarUrl: PropTypes.string.isRequired, + }).isRequired, + createdAt: PropTypes.string.isRequired, + headRefName: PropTypes.string.isRequired, + commits: PropTypes.shape({ + nodes: PropTypes.arrayOf(PropTypes.shape({ + commit: PropTypes.shape({ + status: PropTypes.shape({ + contexts: PropTypes.arrayOf( + PropTypes.shape({ + state: StatePropType.isRequired, + }).isRequired, + ).isRequired, }), - })), - }), + }), + })), }), - ), - }), - repository: PropTypes.shape({ - defaultBranchRef: PropTypes.shape({ - prefix: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, }), - }), - - search: SearchPropType.isRequired, - remote: RemotePropType.isRequired, - branches: BranchSetPropType.isRequired, - aheadCount: PropTypes.number, - pushInProgress: PropTypes.bool.isRequired, + ), + total: PropTypes.number.isRequired, isLoading: PropTypes.bool.isRequired, + title: PropTypes.string.isRequired, + error: PropTypes.object, onOpenIssueish: PropTypes.func.isRequired, - onOpenSearch: PropTypes.func.isRequired, - onCreatePr: PropTypes.func.isRequired, - - error: PropTypes.object, + onOpenMore: PropTypes.func.isRequired, }; static defaultProps = { - results: { - issueCount: 0, - nodes: [], - }, + results: [], + total: 0, } constructor(props) { @@ -76,36 +58,32 @@ export class BareIssueishListController extends React.Component { static getDerivedStateFromProps(props, state) { if (props.results === null) { return { - total: 0, + lastResults: null, issueishes: [], }; } - return { - total: props.results.issueCount, - issueishes: props.results.nodes.map(node => new Issueish(node)), - }; + if (props.results !== state.lastResults) { + return { + lastResults: props.results, + issueishes: props.results.map(node => new Issueish(node)), + }; + } + + return null; } render() { return ( this.props.onOpenSearch(this.props.search)} - onCreatePr={this.props.onCreatePr} + onMoreClick={this.props.onOpenMore} /> ); } @@ -113,28 +91,25 @@ export class BareIssueishListController extends React.Component { export default createFragmentContainer(BareIssueishListController, { results: graphql` - fragment issueishListController_results on SearchResultItemConnection { - issueCount - nodes { - ... on PullRequest { - number - title - url - author { - login - avatarUrl - } - createdAt - headRefName - - commits(last:1) { - nodes { - commit { - status { - contexts { - state - } - } + fragment issueishListController_results on PullRequest + @relay(plural: true) + { + number + title + url + author { + login + avatarUrl + } + createdAt + headRefName + + commits(last:1) { + nodes { + commit { + status { + contexts { + state } } } diff --git a/lib/controllers/issueish-search-controller.js b/lib/controllers/issueish-searches-controller.js similarity index 93% rename from lib/controllers/issueish-search-controller.js rename to lib/controllers/issueish-searches-controller.js index 6d0b390922..99fd6beb81 100644 --- a/lib/controllers/issueish-search-controller.js +++ b/lib/controllers/issueish-searches-controller.js @@ -5,10 +5,10 @@ import {shell} from 'electron'; import {autobind} from '../helpers'; import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; import Search from '../models/search'; -import IssueishListContainer from '../containers/issueish-list-container'; +import IssueishSearchContainer from '../containers/issueish-search-container'; import IssueishPaneItem from '../items/issueish-pane-item'; -export default class IssueishSearchController extends React.Component { +export default class IssueishSearchesController extends React.Component { static propTypes = { host: PropTypes.string.isRequired, token: PropTypes.string.isRequired, @@ -50,7 +50,7 @@ export default class IssueishSearchController extends React.Component { return (
{this.state.searches.map(search => ( - ; } - if (this.props.search.showCreateOnEmpty()) { - return ( - - ); + if (this.props.emptyComponent) { + const EmptyComponent = this.props.emptyComponent; + return ; } return null; diff --git a/test/containers/issueish-list-container.test.js b/test/containers/issueish-search-container.test.js similarity index 72% rename from test/containers/issueish-list-container.test.js rename to test/containers/issueish-search-container.test.js index 6092f629c3..190e03db2a 100644 --- a/test/containers/issueish-list-container.test.js +++ b/test/containers/issueish-search-container.test.js @@ -1,62 +1,28 @@ import React from 'react'; import {shallow, mount} from 'enzyme'; -import {Emitter} from 'event-kit'; import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import Search, {nullSearch} from '../../lib/models/search'; -import Remote from '../../lib/models/remote'; -import Branch, {nullBranch} from '../../lib/models/branch'; -import BranchSet from '../../lib/models/branch-set'; -import IssueishListContainer from '../../lib/containers/issueish-list-container'; +import IssueishSearchContainer from '../../lib/containers/issueish-search-container'; +import {ManualStateObserver} from '../helpers'; -describe('IssueishListContainer', function() { +describe('IssueishSearchContainer', function() { let observer; beforeEach(function() { - observer = { - emitter: new Emitter(), - - onDidComplete(callback) { - return this.emitter.on('did-complete', callback); - }, - - trigger() { - this.emitter.emit('did-complete'); - }, - - dispose() { - this.emitter.dispose(); - }, - }; - }); - - afterEach(function() { - observer.dispose(); + observer = new ManualStateObserver(); }); function buildApp(overrideProps = {}) { - const origin = new Remote('origin', 'git@github.com:atom/github.git'); - const branch = new Branch('master', nullBranch, nullBranch, true); - const branchSet = new BranchSet(); - branchSet.add(branch); - return ( - {}} onOpenSearch={() => {}} - onCreatePr={() => {}} {...overrideProps} /> @@ -104,15 +70,13 @@ describe('IssueishListContainer', function() { const list = wrapper.find('BareIssueishListController'); assert.isTrue(list.exists()); assert.isFalse(list.prop('isLoading')); - assert.deepEqual(list.prop('results'), { - issueCount: 0, - nodes: [], - }); + assert.strictEqual(list.prop('total'), 0); + assert.lengthOf(list.prop('results'), 0); }); - it('renders a query for the Search', function() { - const {resolve} = expectRelayQuery({ - name: 'issueishListContainerQuery', + it('renders a query for the Search', async function() { + const {resolve, promise} = expectRelayQuery({ + name: 'issueishSearchContainerQuery', variables: { query: 'type:pr author:me', }, @@ -124,11 +88,12 @@ describe('IssueishListContainer', function() { const wrapper = shallow(buildApp({search})); assert.strictEqual(wrapper.find('ReactRelayQueryRenderer').prop('variables').query, 'type:pr author:me'); resolve(); + await promise; }); - it('passes an empty result list and an isLoading prop to the controller while loading', function() { - const {resolve} = expectRelayQuery({ - name: 'issueishListContainerQuery', + it('passes an empty result list and an isLoading prop to the controller while loading', async function() { + const {resolve, promise} = expectRelayQuery({ + name: 'issueishSearchContainerQuery', variables: { query: 'type:pr author:me', first: 20, @@ -144,11 +109,12 @@ describe('IssueishListContainer', function() { assert.isTrue(controller.prop('isLoading')); resolve(); + await promise; }); it('passes an empty result list and an error prop to the controller when errored', async function() { const {reject} = expectRelayQuery({ - name: 'issueishListContainerQuery', + name: 'issueishSearchContainerQuery', variables: { query: 'type:pr', first: 20, @@ -165,15 +131,12 @@ describe('IssueishListContainer', function() { ); const controller = wrapper.find('BareIssueishListController'); assert.strictEqual(controller.prop('error'), e); - assert.deepEqual(controller.prop('results'), { - issueCount: 0, - nodes: [], - }); + assert.lengthOf(controller.prop('results'), 0); }); it('passes results to the controller', async function() { const {promise, resolve} = expectRelayQuery({ - name: 'issueishListContainerQuery', + name: 'issueishSearchContainerQuery', variables: { query: 'type:pr author:me', first: 20, @@ -196,11 +159,14 @@ describe('IssueishListContainer', function() { const controller = wrapper.update().find('BareIssueishListController'); assert.isFalse(controller.prop('isLoading')); + assert.strictEqual(controller.prop('total'), 2); + assert.isTrue(controller.prop('results').some(node => node.number === 1)); + assert.isTrue(controller.prop('results').some(node => node.number === 2)); }); it('performs the query again when a remote operation completes', async function() { const {promise: promise0, resolve: resolve0, disable: disable0} = expectRelayQuery({ - name: 'issueishListContainerQuery', + name: 'issueishSearchContainerQuery', variables: { query: 'type:pr author:me', first: 20, @@ -218,12 +184,12 @@ describe('IssueishListContainer', function() { await promise0; assert.isTrue( - wrapper.update().find('BareIssueishListController').prop('results').nodes.some(node => node.number === 1), + wrapper.update().find('BareIssueishListController').prop('results').some(node => node.number === 1), ); disable0(); const {promise: promise1, resolve: resolve1} = expectRelayQuery({ - name: 'issueishListContainerQuery', + name: 'issueishSearchContainerQuery', variables: { query: 'type:pr author:me', first: 20, @@ -239,13 +205,13 @@ describe('IssueishListContainer', function() { await promise1; assert.isTrue( - wrapper.update().find('BareIssueishListController').prop('results').nodes.some(node => node.number === 1), + wrapper.update().find('BareIssueishListController').prop('results').some(node => node.number === 1), ); observer.trigger(); await assert.async.isTrue( - wrapper.update().find('BareIssueishListController').prop('results').nodes.some(node => node.number === 2), + wrapper.update().find('BareIssueishListController').prop('results').some(node => node.number === 2), ); }); }); diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index b053d99103..df5adaaf38 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -2,10 +2,6 @@ import React from 'react'; import {shallow} from 'enzyme'; import Issueish from '../../lib/models/issueish'; -import Search from '../../lib/models/search'; -import Remote from '../../lib/models/remote'; -import BranchSet from '../../lib/models/branch-set'; -import Branch, {nullBranch} from '../../lib/models/branch'; import {BareIssueishListController} from '../../lib/controllers/issueish-list-controller'; describe('IssueishListController', function() { @@ -20,25 +16,16 @@ describe('IssueishListController', function() { }); function buildApp(overrideProps = {}) { - const branches = new BranchSet(); - branches.add(new Branch('master', nullBranch, nullBranch, true)); - return ( {}} onOpenIssueish={() => {}} - onOpenSearch={() => {}} + onOpenMore={() => {}} {...overrideProps} /> @@ -79,18 +66,14 @@ describe('IssueishListController', function() { }, }; - const search = new Search('aaa', 'zzz'); const onOpenIssueish = sinon.stub(); - const onOpenSearch = sinon.stub(); + const onOpenMore = sinon.stub(); const wrapper = shallow(buildApp({ - results: { - issueCount: 1, - nodes: [mockPullRequest], - }, - search, + results: [mockPullRequest], + total: 1, onOpenIssueish, - onOpenSearch, + onOpenMore, })); const view = wrapper.find('IssueishListView'); @@ -105,7 +88,7 @@ describe('IssueishListController', function() { view.prop('onIssueishClick')(payload); assert.isTrue(onOpenIssueish.calledWith(payload)); - view.prop('onMoreClick')(); - assert.isTrue(onOpenSearch.calledWith(search)); + view.prop('onMoreClick')(payload); + assert.isTrue(onOpenMore.calledWith(payload)); }); }); diff --git a/test/controllers/issueish-search-controller.test.js b/test/controllers/issueish-searches-controller.test.js similarity index 84% rename from test/controllers/issueish-search-controller.test.js rename to test/controllers/issueish-searches-controller.test.js index 6a533a6615..e49868e6c6 100644 --- a/test/controllers/issueish-search-controller.test.js +++ b/test/controllers/issueish-searches-controller.test.js @@ -1,14 +1,14 @@ import React from 'react'; import {shallow} from 'enzyme'; -import IssueishSearchController from '../../lib/controllers/issueish-search-controller'; +import IssueishSearchesController from '../../lib/controllers/issueish-searches-controller'; import Remote from '../../lib/models/remote'; import Branch from '../../lib/models/branch'; import BranchSet from '../../lib/models/branch-set'; import Issueish from '../../lib/models/issueish'; import {nullOperationStateObserver} from '../../lib/models/operation-state-observer'; -describe('IssueishSearchController', function() { +describe('IssueishSearchesController', function() { let atomEnv; const origin = new Remote('origin', 'git@github.com:atom/github.git'); const upstreamMaster = Branch.createRemoteTracking('origin/master', 'origin', 'refs/heads/master'); @@ -27,7 +27,7 @@ describe('IssueishSearchController', function() { branches.add(master); return ( - 0); for (const search of wrapper.state('searches')) { - const list = wrapper.find('IssueishListContainer').filterWhere(w => w.prop('search') === search); + const list = wrapper.find('IssueishSearchContainer').filterWhere(w => w.prop('search') === search); assert.isTrue(list.exists()); assert.strictEqual(list.prop('token'), '1234'); assert.strictEqual(list.prop('host'), 'https://api.github.com'); @@ -62,7 +62,7 @@ describe('IssueishSearchController', function() { sinon.spy(atomEnv.workspace, 'open'); const wrapper = shallow(buildApp()); - const container = wrapper.find('IssueishListContainer').at(0); + const container = wrapper.find('IssueishSearchContainer').at(0); const issueish = new Issueish({ number: 123, diff --git a/test/controllers/remote-controller.test.js b/test/controllers/remote-controller.test.js index e4736f7ce5..586bec63ee 100644 --- a/test/controllers/remote-controller.test.js +++ b/test/controllers/remote-controller.test.js @@ -51,7 +51,7 @@ describe('RemoteController', function() { it('renders issueish searches', function() { const wrapper = shallow(createApp()); - const controller = wrapper.update().find('IssueishSearchController'); + const controller = wrapper.update().find('IssueishSearchesController'); assert.strictEqual(controller.prop('token'), '1234'); assert.strictEqual(controller.prop('host'), 'https://api.github.com'); assert.strictEqual(controller.prop('remote'), remote); diff --git a/test/helpers.js b/test/helpers.js index eedbeae74c..03d6e9fce1 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -8,6 +8,7 @@ import React from 'react'; import ReactDom from 'react-dom'; import sinon from 'sinon'; import {Directory} from 'atom'; +import {Emitter} from 'event-kit'; import Repository from '../lib/models/repository'; import GitShellOutStrategy from '../lib/git-shell-out-strategy'; @@ -259,3 +260,21 @@ after(() => { WorkerManager.reset(true); } }); + +export class ManualStateObserver { + constructor() { + this.emitter = new Emitter(); + } + + onDidComplete(callback) { + return this.emitter.on('did-complete', callback); + } + + trigger() { + this.emitter.emit('did-complete'); + } + + dispose() { + this.emitter.dispose(); + } +} diff --git a/test/views/issueish-list-view.test.js b/test/views/issueish-list-view.test.js index 39aceea69c..844467c7ba 100644 --- a/test/views/issueish-list-view.test.js +++ b/test/views/issueish-list-view.test.js @@ -4,7 +4,6 @@ import {shallow, mount} from 'enzyme'; import Remote from '../../lib/models/remote'; import Branch, {nullBranch} from '../../lib/models/branch'; import BranchSet from '../../lib/models/branch-set'; -import Search from '../../lib/models/search'; import Issueish from '../../lib/models/issueish'; import IssueishListView from '../../lib/views/issueish-list-view'; @@ -94,6 +93,12 @@ const noStatus = new Issueish({ }, }); +class CustomComponent extends React.Component { + render() { + return
; + } +} + describe('IssueishListView', function() { let origin, branch, branchSet; @@ -107,17 +112,11 @@ describe('IssueishListView', function() { function buildApp(overrideProps = {}) { return ( {}} onIssueishClick={() => {}} onMoreClick={() => {}} @@ -127,9 +126,9 @@ describe('IssueishListView', function() { ); } - it('sets the accordion title to the Search name', function() { + it('sets the accordion title to the search name', function() { const wrapper = shallow(buildApp({ - search: new Search('the search name', ''), + title: 'the search name', })); assert.strictEqual(wrapper.find('Accordion').prop('leftTitle'), 'the search name'); }); @@ -147,11 +146,10 @@ describe('IssueishListView', function() { }); describe('with empty results', function() { - it('uses a custom EmptyComponent if the search requests one', function() { - const search = Search.forCurrentPR(origin, branch); - const wrapper = mount(buildApp({isLoading: false, search})); + it('uses a custom EmptyComponent if one is provided', function() { + const wrapper = mount(buildApp({isLoading: false, emptyComponent: CustomComponent})); - assert.isTrue(wrapper.find('CreatePullRequestTile').exists()); + assert.isTrue(wrapper.find('CustomComponent').exists()); }); it('renders an error tile if an error is present', function() { From efafb538bc531a48091166d0071c4fe514c13242 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 19 Jun 2018 15:38:52 -0400 Subject: [PATCH 0271/4847] Back out "current PR" Searches --- .../issueish-searches-controller.js | 1 - lib/models/search.js | 12 ------- test/models/search.test.js | 32 ------------------- 3 files changed, 45 deletions(-) diff --git a/lib/controllers/issueish-searches-controller.js b/lib/controllers/issueish-searches-controller.js index 99fd6beb81..e2f6c41f3c 100644 --- a/lib/controllers/issueish-searches-controller.js +++ b/lib/controllers/issueish-searches-controller.js @@ -40,7 +40,6 @@ export default class IssueishSearchesController extends React.Component { static getDerivedStateFromProps(props) { return { searches: [ - Search.forCurrentPR(props.remote, props.branches.getHeadBranch()), Search.inRemote(props.remote, 'Open pull requests', 'type:pr state:open'), ], }; diff --git a/lib/models/search.js b/lib/models/search.js index ab206f7fc5..7e23cc4ef7 100644 --- a/lib/models/search.js +++ b/lib/models/search.js @@ -33,18 +33,6 @@ export default class Search { return `https://${remote.getDomain()}/search?q=${encodeURIComponent(this.createQuery())}`; } - static forCurrentPR(remote, branch) { - const name = 'Current pull request'; - const attrs = {[CREATE_ON_EMPTY]: true}; - - const upstream = branch.getUpstream(); - if (!upstream.isRemoteTracking()) { - return new this(name, '', {[NULL]: true, ...attrs}); - } - - return this.inRemote(remote, name, `type:pr head:${upstream.getShortRemoteRef()}`, attrs); - } - static inRemote(remote, name, query, attrs = {}) { if (!remote.isGithubRepo()) { return new this(name, '', {...attrs, [NULL]: true}); diff --git a/test/models/search.test.js b/test/models/search.test.js index 1a427d0a84..7afe94dd7d 100644 --- a/test/models/search.test.js +++ b/test/models/search.test.js @@ -1,14 +1,9 @@ import Remote, {nullRemote} from '../../lib/models/remote'; -import Branch from '../../lib/models/branch'; import Search from '../../lib/models/search'; describe('Search', function() { const origin = new Remote('origin', 'git@github.com:atom/github.git'); - const originMaster = Branch.createRemoteTracking('origin/master', 'origin', 'refs/heads/master'); - const master = new Branch('master', originMaster); - const local = new Branch('local'); - const tracksLocal = new Branch('tracks-local', local); it('generates a dotcom URL', function() { const s = new Search('foo', 'repo:smashwilson/remote-repo type:pr something with spaces'); @@ -18,33 +13,6 @@ describe('Search', function() { ); }); - describe('for the current pull request', function() { - it('is a null search when the Branch has no upstream', function() { - const s = Search.forCurrentPR(origin, local); - assert.isTrue(s.isNull()); - }); - - it("is a null search when the Branch's upstream is not a remote tracking branch", function() { - const s = Search.forCurrentPR(origin, tracksLocal); - assert.isTrue(s.isNull()); - }); - - it('is a null search when no Remote is available', function() { - const s = Search.forCurrentPR(nullRemote, master); - assert.isTrue(s.isNull()); - }); - - it('creates a templated search query for a remote and branch', function() { - const s = Search.forCurrentPR(origin, master); - assert.isFalse(s.isNull()); - assert.strictEqual(s.createQuery(), 'repo:atom/github type:pr head:master'); - }); - - it('uses a PR creation empty list tile when the Branch has no upstream', function() { - assert.isTrue(Search.forCurrentPR(origin, local).showCreateOnEmpty()); - }); - }); - describe('when scoped to a remote', function() { it('is a null search when the remote is not present', function() { const s = Search.inRemote(nullRemote, 'name', 'query'); From 838b1a049586cd5bb9353ad34917b9467d32f620 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 19 Jun 2018 12:39:11 -0700 Subject: [PATCH 0272/4847] use atom hoverDefault values for tooltip show/hide --- lib/views/push-pull-view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/views/push-pull-view.js b/lib/views/push-pull-view.js index d41d545aa2..06d146b42e 100644 --- a/lib/views/push-pull-view.js +++ b/lib/views/push-pull-view.js @@ -221,8 +221,8 @@ export default class PushPullView extends React.Component { manager={this.props.tooltipManager} target={this.refTileNode} title={`
${tileState.tooltip}
`} - showDelay={200} - hideDelay={100} + showDelay={atom.tooltips.hoverDefaults.delay.show} + hideDelay={atom.tooltips.hoverDefaults.delay.hide} /> )} From 9c279aebfbb7d492593226d732b17dc0dba73346 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 19 Jun 2018 12:56:14 -0700 Subject: [PATCH 0273/4847] move click handling from the `push-pull-target` to the parent element. --- lib/views/push-pull-view.js | 14 +++++--------- styles/push-pull-view.less | 5 ----- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/lib/views/push-pull-view.js b/lib/views/push-pull-view.js index 06d146b42e..14798bd503 100644 --- a/lib/views/push-pull-view.js +++ b/lib/views/push-pull-view.js @@ -195,18 +195,14 @@ export default class PushPullView extends React.Component { tileState = tileStates.detached; } - const Tag = tileState.onClick ? 'a' : 'span'; - return (
{tileState && ( - + {tileState.secondaryText && ( @@ -215,14 +211,14 @@ export default class PushPullView extends React.Component { )} {tileState.text} - + ${tileState.tooltip}
`} - showDelay={atom.tooltips.hoverDefaults.delay.show} - hideDelay={atom.tooltips.hoverDefaults.delay.hide} + showDelay={200} + hideDelay={100} /> )} diff --git a/styles/push-pull-view.less b/styles/push-pull-view.less index 9888b64687..47687925d2 100644 --- a/styles/push-pull-view.less +++ b/styles/push-pull-view.less @@ -2,11 +2,6 @@ // Used in the status-bar -// click target should take up the width of the container -.push-pull-target { - display: inline-block; -} - .github-PushPull { &-icon.icon.icon.icon { margin-right: 0; From d9b1385ae7d1d5fdf5c3ea13c83f23485e8ac0eb Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 19 Jun 2018 12:58:51 -0700 Subject: [PATCH 0274/4847] use Atom hoverDefault values for tooltip show/hide delay --- lib/views/push-pull-view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/views/push-pull-view.js b/lib/views/push-pull-view.js index 14798bd503..8ba813d127 100644 --- a/lib/views/push-pull-view.js +++ b/lib/views/push-pull-view.js @@ -217,8 +217,8 @@ export default class PushPullView extends React.Component { manager={this.props.tooltipManager} target={this.refTileNode} title={`
${tileState.tooltip}
`} - showDelay={200} - hideDelay={100} + showDelay={atom.tooltips.hoverDefaults.delay.show} + hideDelay={atom.tooltips.hoverDefaults.delay.hide} /> )} From 99ba5505d739e17fb0d642b6e9d02b147ac21ef0 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 19 Jun 2018 13:21:09 -0700 Subject: [PATCH 0275/4847] change class name to fix unit tests --- .../status-bar-tile-controller.test.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/controllers/status-bar-tile-controller.test.js b/test/controllers/status-bar-tile-controller.test.js index 436ea22e70..6a0ec33049 100644 --- a/test/controllers/status-bar-tile-controller.test.js +++ b/test/controllers/status-bar-tile-controller.test.js @@ -321,7 +321,7 @@ describe('StatusBarTileController', function() { }); it('pushes the current branch when clicked', function() { - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.isTrue(repository.push.called); }); @@ -329,7 +329,7 @@ describe('StatusBarTileController', function() { repository.getOperationStates().setPushInProgress(true); await assert.async.strictEqual(statusBarTile.update().find('.github-PushPull').text().trim(), 'Pushing'); - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.isFalse(repository.fetch.called); assert.isFalse(repository.push.called); assert.isFalse(repository.pull.called); @@ -356,7 +356,7 @@ describe('StatusBarTileController', function() { }); it('fetches from remote when clicked', function() { - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.isTrue(repository.fetch.called); }); @@ -364,7 +364,7 @@ describe('StatusBarTileController', function() { repository.getOperationStates().setFetchInProgress(true); await assert.async.strictEqual(statusBarTile.update().find('.github-PushPull').text().trim(), 'Fetching'); - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.isFalse(repository.fetch.called); assert.isFalse(repository.push.called); assert.isFalse(repository.pull.called); @@ -392,7 +392,7 @@ describe('StatusBarTileController', function() { }); it('pushes when clicked', function() { - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.isTrue(repository.push.called); }); @@ -400,7 +400,7 @@ describe('StatusBarTileController', function() { repository.getOperationStates().setPushInProgress(true); await assert.async.strictEqual(statusBarTile.find('.github-PushPull').text().trim(), 'Pushing'); - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.isFalse(repository.fetch.called); assert.isFalse(repository.push.called); assert.isFalse(repository.pull.called); @@ -428,7 +428,7 @@ describe('StatusBarTileController', function() { }); it('pulls when clicked', function() { - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.isTrue(repository.pull.called); }); @@ -436,7 +436,7 @@ describe('StatusBarTileController', function() { repository.getOperationStates().setPullInProgress(true); await assert.async.strictEqual(statusBarTile.update().find('.github-PushPull').text().trim(), 'Pulling'); - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.isFalse(repository.fetch.called); assert.isFalse(repository.push.called); assert.isFalse(repository.pull.called); @@ -465,7 +465,7 @@ describe('StatusBarTileController', function() { }); it('pulls when clicked', function() { - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.isTrue(repository.pull.called); assert.isFalse(repository.fetch.called); assert.isFalse(repository.push.called); @@ -475,7 +475,7 @@ describe('StatusBarTileController', function() { repository.getOperationStates().setPullInProgress(true); await assert.async.strictEqual(statusBarTile.update().find('.github-PushPull').text().trim(), 'Pulling'); - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.isFalse(repository.fetch.called); assert.isFalse(repository.push.called); assert.isFalse(repository.pull.called); @@ -503,7 +503,7 @@ describe('StatusBarTileController', function() { }); it('does nothing when clicked', function() { - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.equal(statusBarTile.find('.github-PushPull').text().trim(), 'Not on branch'); assert.isFalse(repository.fetch.called); assert.isFalse(repository.push.called); @@ -532,7 +532,7 @@ describe('StatusBarTileController', function() { }); it('does nothing when clicked', function() { - statusBarTile.find('.push-pull-target').simulate('click'); + statusBarTile.find('.github-PushPull').simulate('click'); assert.equal(statusBarTile.find('.github-PushPull').text().trim(), 'No remote'); assert.isFalse(repository.fetch.called); assert.isFalse(repository.push.called); From 3f2ceb2ab6b73b68e1be3bc61181d1346dabfd66 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 19 Jun 2018 16:18:32 -0700 Subject: [PATCH 0276/4847] Make CommitView use the Command component --- lib/views/commit-view.js | 41 +++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/lib/views/commit-view.js b/lib/views/commit-view.js index fd75fa813a..536c0415a3 100644 --- a/lib/views/commit-view.js +++ b/lib/views/commit-view.js @@ -7,6 +7,7 @@ import Select from 'react-select'; import Tooltip from '../atom/tooltip'; import AtomTextEditor from '../atom/atom-text-editor'; import CoAuthorForm from './co-author-form'; +import Commands, {Command} from '../atom/commands'; import RefHolder from '../models/ref-holder'; import Author from '../models/author'; import ObserveModel from './observe-model'; @@ -116,25 +117,6 @@ export default class CommitView extends React.Component { this.scheduleShowWorking(this.props); this.subscriptions = new CompositeDisposable( - this.props.commandRegistry.add('atom-workspace', { - 'github:commit': this.commit, - 'github:amend-last-commit': this.amendLastCommit, - 'github:toggle-expanded-commit-message-editor': this.toggleExpandedCommitMessageEditor, - }), - this.props.commandRegistry.add('.github-CommitView-coAuthorEditor', { - 'github:co-author:down': this.proxyKeyCode(40), - 'github:co-author:up': this.proxyKeyCode(38), - 'github:co-author:enter': this.proxyKeyCode(13), - 'github:co-author:tab': this.proxyKeyCode(9), - 'github:co-author:backspace': this.proxyKeyCode(8), - 'github:co-author:pageup': this.proxyKeyCode(33), - 'github:co-author:pagedown': this.proxyKeyCode(34), - 'github:co-author:end': this.proxyKeyCode(35), - 'github:co-author:home': this.proxyKeyCode(36), - 'github:co-author:delete': this.proxyKeyCode(46), - 'github:co-author:escape': this.proxyKeyCode(27), - 'github:co-author-exclude': this.excludeCoAuthor, - }), this.props.config.onDidChange('github.automaticCommitMessageWrapping', () => this.forceUpdate()), ); } @@ -154,6 +136,27 @@ export default class CommitView extends React.Component { return (
+ + + + + + + + + + + + + + + + + + +
Date: Wed, 20 Jun 2018 08:57:54 -0400 Subject: [PATCH 0277/4847] Run eslint for fixtures --- .eslintignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 7cbd6dafbc..552b0483bf 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,3 @@ -test/fixtures/**/* +/test/fixtures/**/* +!/test/fixtures/factories/** +!/test/fixtures/props/** From 8ad030660c2828944cac7adf90ea5974cc659692 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 08:58:57 -0400 Subject: [PATCH 0278/4847] Pass a remotesByName map down to the IssueishSearchesController --- lib/containers/remote-container.js | 2 ++ lib/controllers/github-tab-controller.js | 5 +++++ lib/controllers/issueish-searches-controller.js | 1 + lib/controllers/remote-controller.js | 2 ++ test/containers/remote-container.test.js | 1 + test/controllers/issueish-searches-controller.test.js | 1 + test/controllers/remote-controller.test.js | 1 + 7 files changed, 13 insertions(+) diff --git a/lib/containers/remote-container.js b/lib/containers/remote-container.js index 6c81584cc0..d036a7085a 100644 --- a/lib/containers/remote-container.js +++ b/lib/containers/remote-container.js @@ -21,6 +21,7 @@ export default class RemoteContainer extends React.Component { remoteOperationObserver: OperationStateObserverPropType.isRequired, workspace: PropTypes.object.isRequired, remote: RemotePropType.isRequired, + remotesByName: PropTypes.shape({get: PropTypes.func}).isRequired, branches: BranchSetPropType.isRequired, aheadCount: PropTypes.number, @@ -118,6 +119,7 @@ export default class RemoteContainer extends React.Component { remoteOperationObserver={this.props.remoteOperationObserver} workspace={this.props.workspace} remote={this.props.remote} + remotesByName={this.props.remotesByName} branches={this.props.branches} aheadCount={this.props.aheadCount} diff --git a/lib/controllers/github-tab-controller.js b/lib/controllers/github-tab-controller.js index f63ac293e3..c09720789a 100644 --- a/lib/controllers/github-tab-controller.js +++ b/lib/controllers/github-tab-controller.js @@ -86,6 +86,10 @@ export default class GithubTabController extends React.Component { manyRemotesAvailable = true; } + const remotesByName = new Map( + remotes.map(r => [r.getName(), remote]), + ); + const pushInProgress = this.props.repository.getOperationStates().isPushInProgress(); return ( @@ -100,6 +104,7 @@ export default class GithubTabController extends React.Component { workspace={this.props.workspace} onPushBranch={() => this.handlePushBranch(currentBranch, remote)} remote={remote} + remotesByName={remotesByName} branches={branches} aheadCount={aheadCount} pushInProgress={pushInProgress} diff --git a/lib/controllers/issueish-searches-controller.js b/lib/controllers/issueish-searches-controller.js index e2f6c41f3c..91bea19286 100644 --- a/lib/controllers/issueish-searches-controller.js +++ b/lib/controllers/issueish-searches-controller.js @@ -23,6 +23,7 @@ export default class IssueishSearchesController extends React.Component { remoteOperationObserver: OperationStateObserverPropType.isRequired, remote: RemotePropType.isRequired, + remotesByName: PropTypes.shape({get: PropTypes.func}).isRequired, branches: BranchSetPropType.isRequired, aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, diff --git a/lib/controllers/remote-controller.js b/lib/controllers/remote-controller.js index bae072db49..6012dd9d9a 100644 --- a/lib/controllers/remote-controller.js +++ b/lib/controllers/remote-controller.js @@ -21,6 +21,7 @@ export default class RemoteController extends React.Component { remoteOperationObserver: OperationStateObserverPropType.isRequired, workspace: PropTypes.object.isRequired, remote: RemotePropType.isRequired, + remotesByName: PropTypes.shape({get: PropTypes.func}).isRequired, branches: BranchSetPropType.isRequired, aheadCount: PropTypes.number, @@ -45,6 +46,7 @@ export default class RemoteController extends React.Component { workspace={this.props.workspace} remote={this.props.remote} + remotesByName={this.props.remotesByName} branches={this.props.branches} aheadCount={this.props.aheadCount} pushInProgress={this.props.pushInProgress} diff --git a/test/containers/remote-container.test.js b/test/containers/remote-container.test.js index c8da959a91..29076ea3c9 100644 --- a/test/containers/remote-container.test.js +++ b/test/containers/remote-container.test.js @@ -38,6 +38,7 @@ describe('RemoteContainer', function() { notifications={atomEnv.notifications} workspace={atomEnv.workspace} remote={origin} + remotesByName={new Map()} branches={branchSet} aheadCount={0} diff --git a/test/controllers/issueish-searches-controller.test.js b/test/controllers/issueish-searches-controller.test.js index e49868e6c6..931c6d43aa 100644 --- a/test/controllers/issueish-searches-controller.test.js +++ b/test/controllers/issueish-searches-controller.test.js @@ -35,6 +35,7 @@ describe('IssueishSearchesController', function() { remoteOperationObserver={nullOperationStateObserver} workspace={atomEnv.workspace} remote={origin} + remotesByName={new Map()} branches={branches} aheadCount={0} pushInProgress={false} diff --git a/test/controllers/remote-controller.test.js b/test/controllers/remote-controller.test.js index 586bec63ee..fcc324e66d 100644 --- a/test/controllers/remote-controller.test.js +++ b/test/controllers/remote-controller.test.js @@ -36,6 +36,7 @@ describe('RemoteController', function() { remoteOperationObserver={nullOperationStateObserver} workspace={atomEnv.workspace} remote={remote} + remotesByName={new Map()} branches={branchSet} aheadCount={0} From 4ae963aeb07cf9877b3326ffec462378ed2081a5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 08:59:13 -0400 Subject: [PATCH 0279/4847] Factory to stamp out GraphQL PR results --- .../fixtures/factories/pull-request-result.js | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 test/fixtures/factories/pull-request-result.js diff --git a/test/fixtures/factories/pull-request-result.js b/test/fixtures/factories/pull-request-result.js new file mode 100644 index 0000000000..6d76484d47 --- /dev/null +++ b/test/fixtures/factories/pull-request-result.js @@ -0,0 +1,43 @@ +function createCommitResult(attrs) { + return { + commit: { + status: { + contexts: [ {state: 'PASSED'} ] + } + } + }; +} + +export function createPullRequestResult(attrs) { + const o = { + number: 0, + states: [], + headRefName: 'master', + ...attrs, + } + + const commit = { + status: { + contexts: o.states.map((state, id) => ({state, id: `state${id}`})), + id: 'status0', + }, + id: 'commit0' + } + + return { + id: `pullrequest${o.number}`, + number: o.number, + title: `Pull Request ${o.number}`, + url: `https://github.com/owner/repo/pulls/${o.number}`, + author: { + __typename: 'User', + login: 'me', + avatarUrl: 'https://avatars3.githubusercontent.com/u/000?v=4', + id: 'user0' + }, + createdAt: '2018-06-12T14:50:08Z', + headRefName: o.headRefName, + + commits: {nodes: [{commit, id: 'node0'}]}, + } +} From 8b5b2c9859063ad7976e2d72495cd3fe67b91728 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 08:59:30 -0400 Subject: [PATCH 0280/4847] Implement a CurrentPullRequestContainer --- ...urrentPullRequestContainerQuery.graphql.js | 425 ++++++++++++++++++ .../current-pull-request-container.js | 154 +++++++ .../current-pull-request-container.test.js | 189 ++++++++ 3 files changed, 768 insertions(+) create mode 100644 lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js create mode 100644 lib/containers/current-pull-request-container.js create mode 100644 test/containers/current-pull-request-container.test.js diff --git a/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js b/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js new file mode 100644 index 0000000000..93740b09e0 --- /dev/null +++ b/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js @@ -0,0 +1,425 @@ +/** + * @flow + * @relayHash 99a222802beb669e6710d3f1b5ebbaf4 + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest } from 'relay-runtime'; +type issueishListController_results$ref = any; +export type currentPullRequestContainerQueryVariables = {| + headOwner: string, + headName: string, + headRef: string, + first: number, +|}; +export type currentPullRequestContainerQueryResponse = {| + +repository: ?{| + +ref: ?{| + +associatedPullRequests: {| + +totalCount: number, + +nodes: ?$ReadOnlyArray, + |} + |} + |} +|}; +*/ + + +/* +query currentPullRequestContainerQuery( + $headOwner: String! + $headName: String! + $headRef: String! + $first: Int! +) { + repository(owner: $headOwner, name: $headName) { + ref(qualifiedName: $headRef) { + associatedPullRequests(first: $first) { + totalCount + nodes { + ...issueishListController_results + id + } + } + id + } + id + } +} + +fragment issueishListController_results on PullRequest { + number + title + url + author { + __typename + login + avatarUrl + ... on Node { + id + } + } + createdAt + headRefName + commits(last: 1) { + nodes { + commit { + status { + contexts { + state + id + } + id + } + id + } + id + } + } +} +*/ + +const node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "LocalArgument", + "name": "headOwner", + "type": "String!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "headName", + "type": "String!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "headRef", + "type": "String!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "first", + "type": "Int!", + "defaultValue": null + } +], +v1 = [ + { + "kind": "Variable", + "name": "name", + "variableName": "headName", + "type": "String!" + }, + { + "kind": "Variable", + "name": "owner", + "variableName": "headOwner", + "type": "String!" + } +], +v2 = [ + { + "kind": "Variable", + "name": "qualifiedName", + "variableName": "headRef", + "type": "String!" + } +], +v3 = [ + { + "kind": "Variable", + "name": "first", + "variableName": "first", + "type": "Int" + } +], +v4 = { + "kind": "ScalarField", + "alias": null, + "name": "totalCount", + "args": null, + "storageKey": null +}, +v5 = { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null +}; +return { + "kind": "Request", + "operationKind": "query", + "name": "currentPullRequestContainerQuery", + "id": null, + "text": "query currentPullRequestContainerQuery(\n $headOwner: String!\n $headName: String!\n $headRef: String!\n $first: Int!\n) {\n repository(owner: $headOwner, name: $headName) {\n ref(qualifiedName: $headRef) {\n associatedPullRequests(first: $first) {\n totalCount\n nodes {\n ...issueishListController_results\n id\n }\n }\n id\n }\n id\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", + "metadata": {}, + "fragment": { + "kind": "Fragment", + "name": "currentPullRequestContainerQuery", + "type": "Query", + "metadata": null, + "argumentDefinitions": v0, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": v1, + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "ref", + "storageKey": null, + "args": v2, + "concreteType": "Ref", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "associatedPullRequests", + "storageKey": null, + "args": v3, + "concreteType": "PullRequestConnection", + "plural": false, + "selections": [ + v4, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequest", + "plural": true, + "selections": [ + { + "kind": "FragmentSpread", + "name": "issueishListController_results", + "args": null + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "operation": { + "kind": "Operation", + "name": "currentPullRequestContainerQuery", + "argumentDefinitions": v0, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": v1, + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "ref", + "storageKey": null, + "args": v2, + "concreteType": "Ref", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "associatedPullRequests", + "storageKey": null, + "args": v3, + "concreteType": "PullRequestConnection", + "plural": false, + "selections": [ + v4, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequest", + "plural": true, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "number", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "title", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "__typename", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + }, + v5 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "headRefName", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "commits", + "storageKey": "commits(last:1)", + "args": [ + { + "kind": "Literal", + "name": "last", + "value": 1, + "type": "Int" + } + ], + "concreteType": "PullRequestCommitConnection", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestCommit", + "plural": true, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "status", + "storageKey": null, + "args": null, + "concreteType": "Status", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "contexts", + "storageKey": null, + "args": null, + "concreteType": "StatusContext", + "plural": true, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "state", + "args": null, + "storageKey": null + }, + v5 + ] + }, + v5 + ] + }, + v5 + ] + }, + v5 + ] + } + ] + }, + v5 + ] + } + ] + }, + v5 + ] + }, + v5 + ] + } + ] + } +}; +})(); +// prettier-ignore +(node/*: any*/).hash = '40401b5915fbceb317cc0fb6dc78460a'; +module.exports = node; diff --git a/lib/containers/current-pull-request-container.js b/lib/containers/current-pull-request-container.js new file mode 100644 index 0000000000..2c7ee3a963 --- /dev/null +++ b/lib/containers/current-pull-request-container.js @@ -0,0 +1,154 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {QueryRenderer, graphql} from 'react-relay'; +import {Disposable} from 'event-kit'; + +import {autobind} from '../helpers'; +import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; +import IssueishListController, {BareIssueishListController} from '../controllers/issueish-list-controller'; +import CreatePullRequestTile from '../views/create-pull-request-tile'; +import RelayNetworkLayerManager from '../relay-network-layer-manager'; + +export default class CurrentPullRequestContainer extends React.Component { + static propTypes = { + repository: PropTypes.shape({ + defaultBranchRef: PropTypes.shape({ + prefix: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + }), + }), + + token: PropTypes.string.isRequired, + host: PropTypes.string.isRequired, + limit: PropTypes.number, + remoteOperationObserver: OperationStateObserverPropType.isRequired, + remote: RemotePropType.isRequired, + remotesByName: PropTypes.shape({get: PropTypes.func}).isRequired, + branches: BranchSetPropType.isRequired, + aheadCount: PropTypes.number, + pushInProgress: PropTypes.bool.isRequired, + + onOpenIssueish: PropTypes.func.isRequired, + onCreatePr: PropTypes.func.isRequired, + } + + static defaultProps = { + limit: 5, + } + + constructor(props) { + super(props); + autobind(this, 'renderQueryResult', 'renderEmptyTile'); + + this.sub = new Disposable(); + } + + render() { + const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, this.props.token); + + const head = this.props.branches.getHeadBranch(); + if (!head.isPresent()) { + return ; + } + const push = head.getPush(); + if (!push.isPresent() || !push.isRemoteTracking()) { + return ; + } + const pushRemote = this.props.remotesByName.get(push.getRemoteName()); + if (!pushRemote || !pushRemote.isPresent() || !pushRemote.isGithubRepo()) { + return ; + } + + const query = graphql` + query currentPullRequestContainerQuery($headOwner: String!, $headName: String!, $headRef: String!, $first: Int!) { + repository(owner: $headOwner, name: $headName) { + ref(qualifiedName: $headRef) { + associatedPullRequests(first: $first) { + totalCount + nodes { + ...issueishListController_results + } + } + } + } + } + `; + const variables = { + headOwner: pushRemote.getOwner(), + headName: pushRemote.getRepo(), + headRef: push.getRemoteRef(), + first: this.props.limit, + }; + + return ( + + ); + } + + renderQueryResult({error, props, retry}) { + if (retry) { + this.sub.dispose(); + this.sub = this.props.remoteOperationObserver.onDidComplete(retry); + } + + if (error) { + return ( + + ); + } + + if (props === null) { + return ( + + ); + } + + if (!props.repository || !props.repository.ref) { + return ; + } + + const associatedPullRequests = props.repository.ref.associatedPullRequests; + + return ( + + ); + } + + renderEmptyTile() { + return ( + + ); + } + + controllerProps() { + return { + title: 'Current pull request', + onOpenIssueish: this.props.onOpenIssueish, + emptyComponent: this.renderEmptyTile, + }; + } +} diff --git a/test/containers/current-pull-request-container.test.js b/test/containers/current-pull-request-container.test.js new file mode 100644 index 0000000000..9e5f96aef8 --- /dev/null +++ b/test/containers/current-pull-request-container.test.js @@ -0,0 +1,189 @@ +import React from 'react'; +import {mount} from 'enzyme'; + +import {ManualStateObserver} from '../helpers'; +import {createPullRequestResult} from '../fixtures/factories/pull-request-result'; +import Remote from '../../lib/models/remote'; +import Branch, {nullBranch} from '../../lib/models/branch'; +import BranchSet from '../../lib/models/branch-set'; +import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; +import CurrentPullRequestContainer from '../../lib/containers/current-pull-request-container'; + +describe('CurrentPullRequestContainer', function() { + let observer; + + beforeEach(function() { + observer = new ManualStateObserver(); + }); + + function useEmptyResult() { + return expectRelayQuery({ + name: 'currentPullRequestContainerQuery', + variables: { + headOwner: 'atom', + headName: 'github', + headRef: 'refs/heads/master', + first: 5, + }, + }, { + repository: { + ref: { + associatedPullRequests: { + totalCount: 0, + nodes: [], + }, + id: 'ref0', + }, + id: 'repository0', + }, + }); + } + + function useResults(...attrs) { + return expectRelayQuery({ + name: 'currentPullRequestContainerQuery', + variables: { + headOwner: 'atom', + headName: 'github', + headRef: 'refs/heads/master', + first: 5, + }, + }, { + repository: { + ref: { + associatedPullRequests: { + totalCount: attrs.length, + nodes: attrs.map(createPullRequestResult), + }, + id: 'ref0', + }, + id: 'repository0', + }, + }); + } + + function buildApp(overrideProps = {}) { + const origin = new Remote('origin', 'git@github.com:atom/github.git'); + const upstreamBranch = Branch.createRemoteTracking('refs/remotes/origin/master', 'origin', 'refs/heads/master'); + const branch = new Branch('master', upstreamBranch, upstreamBranch, true); + const branchSet = new BranchSet(); + branchSet.add(branch); + + const remotesByName = new Map([['origin', origin]]); + + return ( + {}} + onCreatePr={() => {}} + + {...overrideProps} + /> + ); + } + + it('performs no query without an upstream remote', function() { + const branch = new Branch('local', nullBranch, nullBranch, true); + const branchSet = new BranchSet(); + branchSet.add(branch); + + const wrapper = mount(buildApp({branches: branchSet})); + + assert.isFalse(wrapper.find('ReactRelayQueryRenderer').exists()); + const list = wrapper.find('BareIssueishListController'); + assert.isTrue(list.exists()); + assert.isFalse(list.prop('isLoading')); + assert.strictEqual(list.prop('total'), 0); + assert.lengthOf(list.prop('results'), 0); + }); + + it('passes an empty result list and an isLoading prop to the controller while loading', async function() { + const {resolve, promise} = useEmptyResult(); + + const wrapper = mount(buildApp()); + assert.isTrue(wrapper.find('BareIssueishListController').prop('isLoading')); + + resolve(); + await promise; + + assert.isFalse(wrapper.update().find('BareIssueishListController').prop('isLoading')); + }); + + it('passes an empty result list and an error prop to the controller when errored', async function() { + const {reject, promise} = useEmptyResult(); + + const e = new Error('oh no'); + e.rawStack = e.stack; + reject(e); + await promise.catch(() => null); + + const wrapper = mount(buildApp()); + await assert.async.isFalse(wrapper.update().find('BareIssueishListController').prop('isLoading')); + + assert.strictEqual(wrapper.find('BareIssueishListController').prop('error'), e); + }); + + it('passes a configured pull request creation tile to the controller', async function() { + const {resolve, promise} = useEmptyResult(); + + resolve(); + await promise; + + const wrapper = mount(buildApp()); + await assert.async.isFalse(wrapper.update().find('BareIssueishListController').prop('isLoading')); + + assert.isTrue(wrapper.find('CreatePullRequestTile').exists()); + }); + + it('passes results to the controller', async function() { + const {resolve, promise} = useResults({number: 10}); + + const wrapper = mount(buildApp()); + + resolve(); + await promise; + + const controller = wrapper.update().find('BareIssueishListController'); + assert.strictEqual(controller.prop('total'), 1); + assert.deepEqual(controller.prop('results').map(result => result.number), [10]); + }); + + it('performs the query again when a remote operation completes', async function() { + const {resolve: resolve0, promise: promise0, disable: disable0} = useResults({number: 0}); + + const wrapper = mount(buildApp()); + + resolve0(); + await promise0; + + wrapper.update(); + const controller = wrapper.find('BareIssueishListController'); + assert.deepEqual(controller.prop('results').map(result => result.number), [0]); + + disable0(); + const {resolve: resolve1, promise: promise1} = useResults({number: 1}); + + resolve1(); + await promise1; + + wrapper.update(); + assert.deepEqual(controller.prop('results').map(result => result.number), [0]); + + observer.trigger(); + + await assert.async.deepEqual( + wrapper.update().find('BareIssueishListController').prop('results').map(result => result.number), + [1], + ); + }); +}); From 8b4abfa9d3c90ec6483beae81bb59f390d14cfbd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 08:59:48 -0400 Subject: [PATCH 0281/4847] Make onOpenMore optional --- lib/controllers/issueish-list-controller.js | 2 +- lib/views/issueish-list-view.js | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index e27ff583a6..bb92bb3d16 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -41,7 +41,7 @@ export class BareIssueishListController extends React.Component { error: PropTypes.object, onOpenIssueish: PropTypes.func.isRequired, - onOpenMore: PropTypes.func.isRequired, + onOpenMore: PropTypes.func, }; static defaultProps = { diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index ea07661d19..c60bfc3216 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -23,7 +23,7 @@ export default class IssueishListView extends React.Component { }), onIssueishClick: PropTypes.func.isRequired, - onMoreClick: PropTypes.func.isRequired, + onMoreClick: PropTypes.func, emptyComponent: PropTypes.func, error: PropTypes.object, @@ -104,12 +104,16 @@ export default class IssueishListView extends React.Component { } renderMoreTile() { - return ( - - ); + if (this.props.onMoreClick) { + return ( + + ); + } + + return null; } } From a3f9b6b33b7fb5259b0f703affb185bc1d48304a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 09:00:06 -0400 Subject: [PATCH 0282/4847] Pass emptyComponent through the IssueishListController --- lib/controllers/issueish-list-controller.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index bb92bb3d16..8157fc256b 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -42,6 +42,8 @@ export class BareIssueishListController extends React.Component { onOpenIssueish: PropTypes.func.isRequired, onOpenMore: PropTypes.func, + + emptyComponent: PropTypes.func, }; static defaultProps = { @@ -84,6 +86,8 @@ export class BareIssueishListController extends React.Component { onIssueishClick={this.props.onOpenIssueish} onMoreClick={this.props.onOpenMore} + + emptyComponent={this.props.emptyComponent} /> ); } From c86db41673a5f6641188e749385554814419e44d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 09:00:41 -0400 Subject: [PATCH 0283/4847] Only pass the props we actually need to IssueishSearchContainers --- lib/controllers/issueish-searches-controller.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/controllers/issueish-searches-controller.js b/lib/controllers/issueish-searches-controller.js index 91bea19286..539dc771a4 100644 --- a/lib/controllers/issueish-searches-controller.js +++ b/lib/controllers/issueish-searches-controller.js @@ -55,19 +55,11 @@ export default class IssueishSearchesController extends React.Component { token={this.props.token} host={this.props.host} - - repository={this.props.repository} - - remoteOperationObserver={this.props.remoteOperationObserver} search={search} - remote={this.props.remote} - branches={this.props.branches} - aheadCount={this.props.aheadCount} - pushInProgress={this.props.pushInProgress} + remoteOperationObserver={this.props.remoteOperationObserver} onOpenIssueish={this.onOpenIssueish} onOpenSearch={this.onOpenSearch} - onCreatePr={this.props.onCreatePr} /> ))}
From e837a0115210a71a2f892bd40bc4463ff1d183cd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 09:16:13 -0400 Subject: [PATCH 0284/4847] Default arguments for factories --- test/fixtures/factories/pull-request-result.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/fixtures/factories/pull-request-result.js b/test/fixtures/factories/pull-request-result.js index 6d76484d47..ae9d876423 100644 --- a/test/fixtures/factories/pull-request-result.js +++ b/test/fixtures/factories/pull-request-result.js @@ -1,4 +1,4 @@ -function createCommitResult(attrs) { +function createCommitResult(attrs = {}) { return { commit: { status: { @@ -8,7 +8,7 @@ function createCommitResult(attrs) { }; } -export function createPullRequestResult(attrs) { +export function createPullRequestResult(attrs = {}) { const o = { number: 0, states: [], From 595a26ccf379ab0432b5c0ea9a34590ca6132f2b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 09:16:21 -0400 Subject: [PATCH 0285/4847] Repository result factory --- test/fixtures/factories/repository-result.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 test/fixtures/factories/repository-result.js diff --git a/test/fixtures/factories/repository-result.js b/test/fixtures/factories/repository-result.js new file mode 100644 index 0000000000..bec284827d --- /dev/null +++ b/test/fixtures/factories/repository-result.js @@ -0,0 +1,18 @@ +export function createRepositoryResult(attrs = {}) { + const o = { + id: 'repository0', + defaultRefPrefix: 'refs/heads/', + defaultRefName: 'master', + defaultRefID: 'ref0', + ...attrs, + } + + return { + defaultBranchRef: { + prefix: o.defaultRefPrefix, + name: o.defaultRefName, + id: o.defaultRefID, + }, + id: o.id, + } +} From f6a33b436a175002952eaa22c761a1f5f4f1a89b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 09:16:46 -0400 Subject: [PATCH 0286/4847] Render a CurrentPullRequestContainer beside the active Searches --- .../issueish-searches-controller.js | 15 ++++++++++ .../issueish-searches-controller.test.js | 29 +++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/controllers/issueish-searches-controller.js b/lib/controllers/issueish-searches-controller.js index 539dc771a4..d2702bd957 100644 --- a/lib/controllers/issueish-searches-controller.js +++ b/lib/controllers/issueish-searches-controller.js @@ -6,6 +6,7 @@ import {autobind} from '../helpers'; import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; import Search from '../models/search'; import IssueishSearchContainer from '../containers/issueish-search-container'; +import CurrentPullRequestContainer from '../containers/current-pull-request-container'; import IssueishPaneItem from '../items/issueish-pane-item'; export default class IssueishSearchesController extends React.Component { @@ -49,6 +50,20 @@ export default class IssueishSearchesController extends React.Component { render() { return (
+ {this.state.searches.map(search => ( 0); From b111e60a91be961ad6b33a86006b8b6bed1d0626 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 10:05:25 -0400 Subject: [PATCH 0287/4847] Use the createPullRequestResult factory in IssueishListView tests --- test/views/issueish-list-view.test.js | 94 ++------------------------- 1 file changed, 6 insertions(+), 88 deletions(-) diff --git a/test/views/issueish-list-view.test.js b/test/views/issueish-list-view.test.js index 844467c7ba..3851273828 100644 --- a/test/views/issueish-list-view.test.js +++ b/test/views/issueish-list-view.test.js @@ -1,97 +1,16 @@ import React from 'react'; import {shallow, mount} from 'enzyme'; -import Remote from '../../lib/models/remote'; +import {createPullRequestResult} from '../fixtures/factories/pull-request-result'; import Branch, {nullBranch} from '../../lib/models/branch'; import BranchSet from '../../lib/models/branch-set'; import Issueish from '../../lib/models/issueish'; import IssueishListView from '../../lib/views/issueish-list-view'; -function makeCommit(...states) { - return { - nodes: [ - { - commit: { - status: { - contexts: states.map(state => ({state})), - }, - }, - }, - ], - }; -} - -const allGreen = new Issueish({ - number: 1, - title: 'One', - url: 'https://github.com/atom/github/pulls/1', - author: { - login: 'me', - avatarUrl: 'https://avatars.githubusercontent.com/u/100?v=24', - }, - createdAt: '2018-06-12T14:50:08Z', - headRefName: 'head-ref', - headRepository: { - nameWithOwner: 'me/github', - }, - commits: makeCommit('SUCCESS', 'SUCCESS', 'SUCCESS'), -}); - -const mixed = new Issueish({ - number: 2, - title: 'Two', - url: 'https://github.com/atom/github/pulls/2', - author: { - login: 'me', - avatarUrl: 'https://avatars.githubusercontent.com/u/100?v=24', - }, - createdAt: '2018-06-12T14:50:08Z', - headRefName: 'head-ref', - headRepository: { - nameWithOwner: 'me/github', - }, - commits: makeCommit('SUCCESS', 'PENDING', 'FAILURE'), -}); - -const allRed = new Issueish({ - number: 3, - title: 'Three', - url: 'https://github.com/atom/github/pulls/3', - author: { - login: 'me', - avatarUrl: 'https://avatars.githubusercontent.com/u/100?v=24', - }, - createdAt: '2018-06-12T14:50:08Z', - headRefName: 'head-ref', - headRepository: { - nameWithOwner: 'me/github', - }, - commits: makeCommit('FAILURE', 'ERROR', 'FAILURE'), -}); - -const noStatus = new Issueish({ - number: 4, - title: 'Four', - url: 'https://github.com/atom/github/pulls/4', - author: { - login: 'me', - avatarUrl: 'https://avatars.githubusercontent.com/u/100?v=24', - }, - createdAt: '2018-06-12T14:50:08Z', - headRefName: 'head-ref', - headRepository: { - nameWithOwner: 'me/github', - }, - commits: { - nodes: [ - { - commit: { - status: null, - }, - }, - ], - }, -}); +const allGreen = new Issueish(createPullRequestResult({number: 1, states: ['SUCCESS', 'SUCCESS', 'SUCCESS']})); +const mixed = new Issueish(createPullRequestResult({number: 2, states: ['SUCCESS', 'PENDING', 'FAILURE']})); +const allRed = new Issueish(createPullRequestResult({number: 3, states: ['FAILURE', 'ERROR', 'FAILURE']})); +const noStatus = new Issueish(createPullRequestResult({number: 4, states: null})); class CustomComponent extends React.Component { render() { @@ -100,10 +19,9 @@ class CustomComponent extends React.Component { } describe('IssueishListView', function() { - let origin, branch, branchSet; + let branch, branchSet; beforeEach(function() { - origin = new Remote('origin', 'git@github.com:atom/github.git'); branch = new Branch('master', nullBranch, nullBranch, true); branchSet = new BranchSet(); branchSet.add(branch); From b26515ea751010045a7e353eee1ea237dfddc30d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 10:18:26 -0400 Subject: [PATCH 0288/4847] Generate pull requests with a null status --- test/fixtures/factories/pull-request-result.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/fixtures/factories/pull-request-result.js b/test/fixtures/factories/pull-request-result.js index ae9d876423..efbd120fb4 100644 --- a/test/fixtures/factories/pull-request-result.js +++ b/test/fixtures/factories/pull-request-result.js @@ -17,11 +17,15 @@ export function createPullRequestResult(attrs = {}) { } const commit = { - status: { + id: 'commit0', + }; + + if (o.states === null) { + commit.status = null; + } else { + commit.status = { contexts: o.states.map((state, id) => ({state, id: `state${id}`})), - id: 'status0', - }, - id: 'commit0' + }; } return { From 5920e8324b7c3e35dec951ef8feab7aa01f22c4f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 10:18:43 -0400 Subject: [PATCH 0289/4847] Remove unused atomEnv --- test/controllers/issueish-list-controller.test.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index df5adaaf38..cf42fb0688 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -5,16 +5,6 @@ import Issueish from '../../lib/models/issueish'; import {BareIssueishListController} from '../../lib/controllers/issueish-list-controller'; describe('IssueishListController', function() { - let atomEnv; - - beforeEach(function() { - atomEnv = global.buildAtomEnvironment(); - }); - - afterEach(function() { - atomEnv.destroy(); - }); - function buildApp(overrideProps = {}) { return ( Date: Wed, 20 Jun 2018 10:20:39 -0400 Subject: [PATCH 0290/4847] Query for Repository IDs for the chosen remote and pull requests --- ...urrentPullRequestContainerQuery.graphql.js | 19 ++++++++++-- .../issueishSearchContainerQuery.graphql.js | 19 ++++++++++-- .../remoteContainerQuery.graphql.js | 30 ++++++++++--------- .../current-pull-request-container.js | 3 +- lib/containers/remote-container.js | 1 + .../issueishListController_results.graphql.js | 23 +++++++++++++- lib/controllers/issueish-list-controller.js | 7 +++++ .../issueish-searches-controller.js | 1 + lib/controllers/remote-controller.js | 1 + .../fixtures/factories/pull-request-result.js | 9 ++++-- 10 files changed, 91 insertions(+), 22 deletions(-) diff --git a/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js b/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js index 93740b09e0..1a371a46bb 100644 --- a/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js +++ b/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 99a222802beb669e6710d3f1b5ebbaf4 + * @relayHash 72621b88fba5e23ed2d19f4a6845af3d */ /* eslint-disable */ @@ -67,6 +67,9 @@ fragment issueishListController_results on PullRequest { } createdAt headRefName + repository { + id + } commits(last: 1) { nodes { commit { @@ -161,7 +164,7 @@ return { "operationKind": "query", "name": "currentPullRequestContainerQuery", "id": null, - "text": "query currentPullRequestContainerQuery(\n $headOwner: String!\n $headName: String!\n $headRef: String!\n $first: Int!\n) {\n repository(owner: $headOwner, name: $headName) {\n ref(qualifiedName: $headRef) {\n associatedPullRequests(first: $first) {\n totalCount\n nodes {\n ...issueishListController_results\n id\n }\n }\n id\n }\n id\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", + "text": "query currentPullRequestContainerQuery(\n $headOwner: String!\n $headName: String!\n $headRef: String!\n $first: Int!\n) {\n repository(owner: $headOwner, name: $headName) {\n ref(qualifiedName: $headRef) {\n associatedPullRequests(first: $first) {\n totalCount\n nodes {\n ...issueishListController_results\n id\n }\n }\n id\n }\n id\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n repository {\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -332,6 +335,18 @@ return { "args": null, "storageKey": null }, + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": null, + "concreteType": "Repository", + "plural": false, + "selections": [ + v5 + ] + }, { "kind": "LinkedField", "alias": null, diff --git a/lib/containers/__generated__/issueishSearchContainerQuery.graphql.js b/lib/containers/__generated__/issueishSearchContainerQuery.graphql.js index 938e2f2365..b1b78a6de8 100644 --- a/lib/containers/__generated__/issueishSearchContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishSearchContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 094129e5934b60cf04cd1ba9494cdfb5 + * @relayHash 39c0b6593d96d2f8436bff9ca0d239c4 */ /* eslint-disable */ @@ -56,6 +56,9 @@ fragment issueishListController_results on PullRequest { } createdAt headRefName + repository { + id + } commits(last: 1) { nodes { commit { @@ -135,7 +138,7 @@ return { "operationKind": "query", "name": "issueishSearchContainerQuery", "id": null, - "text": "query issueishSearchContainerQuery(\n $query: String!\n $first: Int!\n) {\n search(first: $first, query: $query, type: ISSUE) {\n issueCount\n nodes {\n __typename\n ...issueishListController_results\n ... on Node {\n id\n }\n }\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", + "text": "query issueishSearchContainerQuery(\n $query: String!\n $first: Int!\n) {\n search(first: $first, query: $query, type: ISSUE) {\n issueCount\n nodes {\n __typename\n ...issueishListController_results\n ... on Node {\n id\n }\n }\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n repository {\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -266,6 +269,18 @@ return { "args": null, "storageKey": null }, + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": null, + "concreteType": "Repository", + "plural": false, + "selections": [ + v4 + ] + }, { "kind": "LinkedField", "alias": null, diff --git a/lib/containers/__generated__/remoteContainerQuery.graphql.js b/lib/containers/__generated__/remoteContainerQuery.graphql.js index ebae27e2e1..f1fd34d3b6 100644 --- a/lib/containers/__generated__/remoteContainerQuery.graphql.js +++ b/lib/containers/__generated__/remoteContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 31f49e2054e5af61819d6f3ca8228979 + * @relayHash 7fbd7496eff90270ea34a304108aa100 */ /* eslint-disable */ @@ -15,10 +15,11 @@ export type remoteContainerQueryVariables = {| |}; export type remoteContainerQueryResponse = {| +repository: ?{| + +id: string, +defaultBranchRef: ?{| +prefix: string, +name: string, - |} + |}, |} |}; */ @@ -30,12 +31,12 @@ query remoteContainerQuery( $name: String! ) { repository(owner: $owner, name: $name) { + id defaultBranchRef { prefix name id } - id } } */ @@ -72,21 +73,21 @@ v1 = [ v2 = { "kind": "ScalarField", "alias": null, - "name": "prefix", + "name": "id", "args": null, "storageKey": null }, v3 = { "kind": "ScalarField", "alias": null, - "name": "name", + "name": "prefix", "args": null, "storageKey": null }, v4 = { "kind": "ScalarField", "alias": null, - "name": "id", + "name": "name", "args": null, "storageKey": null }; @@ -95,7 +96,7 @@ return { "operationKind": "query", "name": "remoteContainerQuery", "id": null, - "text": "query remoteContainerQuery(\n $owner: String!\n $name: String!\n) {\n repository(owner: $owner, name: $name) {\n defaultBranchRef {\n prefix\n name\n id\n }\n id\n }\n}\n", + "text": "query remoteContainerQuery(\n $owner: String!\n $name: String!\n) {\n repository(owner: $owner, name: $name) {\n id\n defaultBranchRef {\n prefix\n name\n id\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -113,6 +114,7 @@ return { "concreteType": "Repository", "plural": false, "selections": [ + v2, { "kind": "LinkedField", "alias": null, @@ -122,8 +124,8 @@ return { "concreteType": "Ref", "plural": false, "selections": [ - v2, - v3 + v3, + v4 ] } ] @@ -144,6 +146,7 @@ return { "concreteType": "Repository", "plural": false, "selections": [ + v2, { "kind": "LinkedField", "alias": null, @@ -153,12 +156,11 @@ return { "concreteType": "Ref", "plural": false, "selections": [ - v2, v3, - v4 + v4, + v2 ] - }, - v4 + } ] } ] @@ -166,5 +168,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '491900781f0ba3de667b2d5262aa5ab4'; +(node/*: any*/).hash = 'b83aa6c27c5d7e1c499badf2e6bfab6b'; module.exports = node; diff --git a/lib/containers/current-pull-request-container.js b/lib/containers/current-pull-request-container.js index 2c7ee3a963..73fe360db7 100644 --- a/lib/containers/current-pull-request-container.js +++ b/lib/containers/current-pull-request-container.js @@ -12,11 +12,12 @@ import RelayNetworkLayerManager from '../relay-network-layer-manager'; export default class CurrentPullRequestContainer extends React.Component { static propTypes = { repository: PropTypes.shape({ + id: PropTypes.string.isRequired, defaultBranchRef: PropTypes.shape({ prefix: PropTypes.string.isRequired, name: PropTypes.string.isRequired, }), - }), + }).isRequired, token: PropTypes.string.isRequired, host: PropTypes.string.isRequired, diff --git a/lib/containers/remote-container.js b/lib/containers/remote-container.js index d036a7085a..74dc9d4619 100644 --- a/lib/containers/remote-container.js +++ b/lib/containers/remote-container.js @@ -71,6 +71,7 @@ export default class RemoteContainer extends React.Component { const query = graphql` query remoteContainerQuery($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { + id defaultBranchRef { prefix name diff --git a/lib/controllers/__generated__/issueishListController_results.graphql.js b/lib/controllers/__generated__/issueishListController_results.graphql.js index ed982c63ec..9349b1b393 100644 --- a/lib/controllers/__generated__/issueishListController_results.graphql.js +++ b/lib/controllers/__generated__/issueishListController_results.graphql.js @@ -21,6 +21,9 @@ export type issueishListController_results = $ReadOnlyArray<{| |}, +createdAt: any, +headRefName: string, + +repository: {| + +id: string + |}, +commits: {| +nodes: ?$ReadOnlyArray Date: Wed, 20 Jun 2018 10:21:32 -0400 Subject: [PATCH 0291/4847] Include headRepositoryID in the Issueish model --- lib/models/issueish.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/models/issueish.js b/lib/models/issueish.js index fade6d6d81..6acac64dc2 100644 --- a/lib/models/issueish.js +++ b/lib/models/issueish.js @@ -12,6 +12,7 @@ export default class Issueish { this.authorAvatarURL = new URL(data.author.avatarUrl); this.createdAt = moment(data.createdAt, moment.ISO_8601); this.headRefName = data.headRefName; + this.headRepositoryID = data.repository.id; this.statusContexts = data.commits.nodes.reduce((acc, node) => { const status = node.commit.status; if (status !== null) { @@ -51,6 +52,10 @@ export default class Issueish { return this.headRefName; } + getHeadRepositoryID() { + return this.headRepositoryID; + } + getStatusCounts() { return this.statusContexts.reduce((acc, context) => { acc[category(context.state).toLowerCase()]++; From aa2937b7c370c51b60c97082d231d7240b57f9a7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 10:22:23 -0400 Subject: [PATCH 0292/4847] Use the pull request factory in IssueishListController tests --- .../issueish-list-controller.test.js | 25 ++----------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index cf42fb0688..a207e5eb57 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -1,6 +1,7 @@ import React from 'react'; import {shallow} from 'enzyme'; +import {createPullRequestResult} from '../fixtures/factories/pull-request-result'; import Issueish from '../../lib/models/issueish'; import {BareIssueishListController} from '../../lib/controllers/issueish-list-controller'; @@ -32,29 +33,7 @@ describe('IssueishListController', function() { }); it('renders an IssueishListView with issueish results', function() { - const mockPullRequest = { - number: 1, - title: 'One', - url: 'https://github.com/atom/github/pulls/1', - author: { - login: 'smashwilson', - avatarUrl: 'https://avatars2.githubusercontent.com/u/17565?v=4', - }, - createdAt: '2018-06-12T14:50:08Z', - headRefName: 'aw/accordion-solo', - headRepository: { - nameWithOwner: 'atom/github', - }, - commits: { - nodes: [ - { - commit: { - status: null, - }, - }, - ], - }, - }; + const mockPullRequest = createPullRequestResult({number: 1}); const onOpenIssueish = sinon.stub(); const onOpenMore = sinon.stub(); From 0dbacd2ba926e43c6a7a24a5a8231087cf5792f4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 10:22:41 -0400 Subject: [PATCH 0293/4847] Support a result filter in IssueishListController --- lib/controllers/issueish-list-controller.js | 4 +++- test/controllers/issueish-list-controller.test.js | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/controllers/issueish-list-controller.js b/lib/controllers/issueish-list-controller.js index 0adefb336d..d4d96244cd 100644 --- a/lib/controllers/issueish-list-controller.js +++ b/lib/controllers/issueish-list-controller.js @@ -43,6 +43,7 @@ export class BareIssueishListController extends React.Component { title: PropTypes.string.isRequired, error: PropTypes.object, + resultFilter: PropTypes.func, onOpenIssueish: PropTypes.func.isRequired, onOpenMore: PropTypes.func, @@ -52,6 +53,7 @@ export class BareIssueishListController extends React.Component { static defaultProps = { results: [], total: 0, + resultFilter: () => true, } constructor(props) { @@ -71,7 +73,7 @@ export class BareIssueishListController extends React.Component { if (props.results !== state.lastResults) { return { lastResults: props.results, - issueishes: props.results.map(node => new Issueish(node)), + issueishes: props.results.map(node => new Issueish(node)).filter(props.resultFilter), }; } diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index a207e5eb57..fc9eb4dc72 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -60,4 +60,16 @@ describe('IssueishListController', function() { view.prop('onMoreClick')(payload); assert.isTrue(onOpenMore.calledWith(payload)); }); + + it('applies a resultFilter to limit its results', function() { + const wrapper = shallow(buildApp({ + resultFilter: issueish => issueish.getNumber() > 10, + results: [0, 11, 13, 5, 12].map(number => createPullRequestResult({number})), + total: 5, + })); + + const view = wrapper.find('IssueishListView'); + assert.strictEqual(view.prop('total'), 5); + assert.deepEqual(view.prop('issueishes').map(issueish => issueish.getNumber()), [11, 13, 12]); + }); }); From 65b000705e02e9dcabb23972415b3502870ab626 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 10:22:59 -0400 Subject: [PATCH 0294/4847] Filter out pull requests with a different head repository --- .../current-pull-request-container.js | 1 + .../current-pull-request-container.test.js | 22 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/containers/current-pull-request-container.js b/lib/containers/current-pull-request-container.js index 73fe360db7..635f58cd7d 100644 --- a/lib/containers/current-pull-request-container.js +++ b/lib/containers/current-pull-request-container.js @@ -127,6 +127,7 @@ export default class CurrentPullRequestContainer extends React.Component { total={associatedPullRequests.totalCount} results={associatedPullRequests.nodes} isLoading={false} + resultFilter={issueish => issueish.getHeadRepositoryID() === this.props.repository.id} {...this.controllerProps()} /> ); diff --git a/test/containers/current-pull-request-container.test.js b/test/containers/current-pull-request-container.test.js index 9e5f96aef8..ddc8420361 100644 --- a/test/containers/current-pull-request-container.test.js +++ b/test/containers/current-pull-request-container.test.js @@ -3,6 +3,7 @@ import {mount} from 'enzyme'; import {ManualStateObserver} from '../helpers'; import {createPullRequestResult} from '../fixtures/factories/pull-request-result'; +import {createRepositoryResult} from '../fixtures/factories/repository-result'; import Remote from '../../lib/models/remote'; import Branch, {nullBranch} from '../../lib/models/branch'; import BranchSet from '../../lib/models/branch-set'; @@ -73,11 +74,11 @@ describe('CurrentPullRequestContainer', function() { return ( result.number), [10]); }); + it('filters out pull requests opened on different repositories', async function() { + const repository = createRepositoryResult({id: 'upstream-repo'}); + + const {resolve, promise} = useResults( + {number: 11, repositoryID: 'upstream-repo'}, + {number: 22, repositoryID: 'someones-fork'}, + ); + + const wrapper = mount(buildApp({repository})); + resolve(); + await promise; + wrapper.update(); + + const numbers = wrapper.find('.github-IssueishList-item--number').map(n => n.text()); + assert.deepEqual(numbers, ['#11']); + }); + it('performs the query again when a remote operation completes', async function() { const {resolve: resolve0, promise: promise0, disable: disable0} = useResults({number: 0}); From d53983e9973ce5b80a907994c28ae4b83caa2b7c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 10:25:45 -0400 Subject: [PATCH 0295/4847] Only show open pull requests as "Current" --- .../currentPullRequestContainerQuery.graphql.js | 16 ++++++++++++---- lib/containers/current-pull-request-container.js | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js b/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js index 1a371a46bb..3bc8e25975 100644 --- a/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js +++ b/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 72621b88fba5e23ed2d19f4a6845af3d + * @relayHash 40b7bc7d6c17a665a1fe95116c6f6719 */ /* eslint-disable */ @@ -40,7 +40,7 @@ query currentPullRequestContainerQuery( ) { repository(owner: $headOwner, name: $headName) { ref(qualifiedName: $headRef) { - associatedPullRequests(first: $first) { + associatedPullRequests(first: $first, states: [OPEN]) { totalCount nodes { ...issueishListController_results @@ -143,6 +143,14 @@ v3 = [ "name": "first", "variableName": "first", "type": "Int" + }, + { + "kind": "Literal", + "name": "states", + "value": [ + "OPEN" + ], + "type": "[PullRequestState!]" } ], v4 = { @@ -164,7 +172,7 @@ return { "operationKind": "query", "name": "currentPullRequestContainerQuery", "id": null, - "text": "query currentPullRequestContainerQuery(\n $headOwner: String!\n $headName: String!\n $headRef: String!\n $first: Int!\n) {\n repository(owner: $headOwner, name: $headName) {\n ref(qualifiedName: $headRef) {\n associatedPullRequests(first: $first) {\n totalCount\n nodes {\n ...issueishListController_results\n id\n }\n }\n id\n }\n id\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n repository {\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", + "text": "query currentPullRequestContainerQuery(\n $headOwner: String!\n $headName: String!\n $headRef: String!\n $first: Int!\n) {\n repository(owner: $headOwner, name: $headName) {\n ref(qualifiedName: $headRef) {\n associatedPullRequests(first: $first, states: [OPEN]) {\n totalCount\n nodes {\n ...issueishListController_results\n id\n }\n }\n id\n }\n id\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n repository {\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -436,5 +444,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '40401b5915fbceb317cc0fb6dc78460a'; +(node/*: any*/).hash = 'ade50c0777277f2032b27dfced670a2d'; module.exports = node; diff --git a/lib/containers/current-pull-request-container.js b/lib/containers/current-pull-request-container.js index 635f58cd7d..eceb1fa853 100644 --- a/lib/containers/current-pull-request-container.js +++ b/lib/containers/current-pull-request-container.js @@ -64,7 +64,7 @@ export default class CurrentPullRequestContainer extends React.Component { query currentPullRequestContainerQuery($headOwner: String!, $headName: String!, $headRef: String!, $first: Int!) { repository(owner: $headOwner, name: $headName) { ref(qualifiedName: $headRef) { - associatedPullRequests(first: $first) { + associatedPullRequests(first: $first, states: [OPEN]) { totalCount nodes { ...issueishListController_results From 1f7dcf85c53f11b84c98b534ebc2d6903dc64908 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 10:47:42 -0400 Subject: [PATCH 0296/4847] Rerender the CurrentPullRequestContainer when a push happens --- .../current-pull-request-container.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/containers/current-pull-request-container.js b/lib/containers/current-pull-request-container.js index eceb1fa853..f761b44d1a 100644 --- a/lib/containers/current-pull-request-container.js +++ b/lib/containers/current-pull-request-container.js @@ -49,15 +49,15 @@ export default class CurrentPullRequestContainer extends React.Component { const head = this.props.branches.getHeadBranch(); if (!head.isPresent()) { - return ; + return this.renderEmptyResult(); } const push = head.getPush(); if (!push.isPresent() || !push.isRemoteTracking()) { - return ; + return this.renderEmptyResult(); } const pushRemote = this.props.remotesByName.get(push.getRemoteName()); if (!pushRemote || !pushRemote.isPresent() || !pushRemote.isGithubRepo()) { - return ; + return this.renderEmptyResult(); } const query = graphql` @@ -91,6 +91,13 @@ export default class CurrentPullRequestContainer extends React.Component { ); } + renderEmptyResult() { + this.sub.dispose(); + this.sub = this.props.remoteOperationObserver.onDidComplete(() => this.forceUpdate()); + + return ; + } + renderQueryResult({error, props, retry}) { if (retry) { this.sub.dispose(); @@ -146,6 +153,10 @@ export default class CurrentPullRequestContainer extends React.Component { ); } + componentWillUnmount() { + this.sub.dispose(); + } + controllerProps() { return { title: 'Current pull request', From bc89289048d60b0f74f998197a0cb839c7062aca Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 10:47:57 -0400 Subject: [PATCH 0297/4847] Invalidated cached branches when an upstream is set --- lib/models/repository-states/present.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index bd8c2fb7c9..2fc3fc17b6 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -391,6 +391,7 @@ export default class Present extends State { ]; if (options.setUpstream) { + keys.push(Keys.branches); keys.push(...Keys.config.eachWithSetting(`branch.${branchName}.remote`)); } From 824a4f7cf693b3b1e4cd603fe50db695f9589560 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 10:48:23 -0400 Subject: [PATCH 0298/4847] Default a branch's push upstream to its fetch upstream --- lib/models/repository-states/present.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index 2fc3fc17b6..2acf5a28bc 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -651,7 +651,7 @@ export default class Present extends State { : new Branch(payload.upstream.trackingRef); } - let push = nullBranch; + let push = upstream; if (payload.push) { push = payload.push.remoteName ? Branch.createRemoteTracking( From d6eb712fa93ae7137a7637d12e2fae49e6cac525 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 11:06:36 -0400 Subject: [PATCH 0299/4847] Include a __typename in the pull request result fixture --- test/fixtures/factories/pull-request-result.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/fixtures/factories/pull-request-result.js b/test/fixtures/factories/pull-request-result.js index ed74e65ee2..aa18846853 100644 --- a/test/fixtures/factories/pull-request-result.js +++ b/test/fixtures/factories/pull-request-result.js @@ -30,6 +30,7 @@ export function createPullRequestResult(attrs = {}) { } return { + __typename: 'PullRequest', id: `pullrequest${o.number}`, number: o.number, title: `Pull Request ${o.number}`, From df88b3e3d335c40068d8eb97dd67330fae8ce436 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 11:06:53 -0400 Subject: [PATCH 0300/4847] Return a Disposable from the null OperationStateObserver --- lib/models/operation-state-observer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/models/operation-state-observer.js b/lib/models/operation-state-observer.js index df63767347..8189433556 100644 --- a/lib/models/operation-state-observer.js +++ b/lib/models/operation-state-observer.js @@ -1,4 +1,4 @@ -import {Emitter} from 'event-kit'; +import {Emitter, Disposable} from 'event-kit'; export const PUSH = { getter(o) { @@ -60,6 +60,6 @@ export default class OperationStateObserver { } export const nullOperationStateObserver = { - onDidComplete() {}, + onDidComplete() { return new Disposable(); }, dispose() {}, }; From afd739d647ec8748ba968ca1e5e7cc7de6af521e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 11:07:36 -0400 Subject: [PATCH 0301/4847] Use result factories in IssueishSearchContainer tests --- .../issueish-search-container.test.js | 43 +++---------------- 1 file changed, 5 insertions(+), 38 deletions(-) diff --git a/test/containers/issueish-search-container.test.js b/test/containers/issueish-search-container.test.js index 190e03db2a..e682a5193f 100644 --- a/test/containers/issueish-search-container.test.js +++ b/test/containers/issueish-search-container.test.js @@ -2,6 +2,7 @@ import React from 'react'; import {shallow, mount} from 'enzyme'; import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; +import {createPullRequestResult} from '../fixtures/factories/pull-request-result'; import Search, {nullSearch} from '../../lib/models/search'; import IssueishSearchContainer from '../../lib/containers/issueish-search-container'; import {ManualStateObserver} from '../helpers'; @@ -29,40 +30,6 @@ describe('IssueishSearchContainer', function() { ); } - function createPullRequest(number) { - return { - __typename: 'PullRequest', - id: number.toString(), - number, - title: 'One', - url: 'https://github.com/atom/github/1', - author: { - __typename: 'User', - id: 'u0', - login: 'smashwilson', - avatarUrl: 'https://avatar.com/yes.jpg', - }, - createdAt: '2018-06-12T14:50:08Z', - headRefName: 'aw/something', - headRepository: { - id: 'r0', - nameWithOwner: 'atom/github', - }, - commits: { - id: 'cs0', - nodes: [ - { - id: 'n0', - commit: { - id: 'c0', - status: null, - }, - }, - ], - }, - }; - } - it('performs no query for a null Search', function() { const wrapper = shallow(buildApp({search: nullSearch})); @@ -145,8 +112,8 @@ describe('IssueishSearchContainer', function() { search: { issueCount: 2, nodes: [ - createPullRequest(1), - createPullRequest(2), + createPullRequestResult({number: 1}), + createPullRequestResult({number: 2}), ], }, }); @@ -174,7 +141,7 @@ describe('IssueishSearchContainer', function() { }, { search: { issueCount: 1, - nodes: [createPullRequest(1)], + nodes: [createPullRequestResult({number: 1})], }, }); @@ -197,7 +164,7 @@ describe('IssueishSearchContainer', function() { }, { search: { issueCount: 1, - nodes: [createPullRequest(2)], + nodes: [createPullRequestResult({number: 2})], }, }); From 4bf55ea9df8f006e2b8e71a7dba052e0c9a28bd7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 11:08:03 -0400 Subject: [PATCH 0302/4847] Use result factories in RemoteContainer tests --- test/containers/remote-container.test.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/test/containers/remote-container.test.js b/test/containers/remote-container.test.js index 29076ea3c9..673b20d33f 100644 --- a/test/containers/remote-container.test.js +++ b/test/containers/remote-container.test.js @@ -1,6 +1,7 @@ import React from 'react'; import {mount} from 'enzyme'; +import {createRepositoryResult} from '../fixtures/factories/repository-result'; import Remote from '../../lib/models/remote'; import Branch, {nullBranch} from '../../lib/models/branch'; import BranchSet from '../../lib/models/branch-set'; @@ -59,14 +60,7 @@ describe('RemoteContainer', function() { name: 'github', }, }, { - repository: { - defaultBranchRef: { - prefix: 'refs/heads/', - name: 'master', - id: 'ref0', - }, - id: 'repo0', - }, + repository: createRepositoryResult(), }); } @@ -151,6 +145,7 @@ describe('RemoteContainer', function() { const controller = wrapper.find('RemoteController'); assert.strictEqual(controller.prop('token'), '1234'); assert.deepEqual(controller.prop('repository'), { + id: 'repository0', defaultBranchRef: { prefix: 'refs/heads/', name: 'master', From c1caa9f93bdd9079ce476e4df668e7263bb4a5fe Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 11:08:18 -0400 Subject: [PATCH 0303/4847] Bring query expectation name up to date --- test/containers/remote-container.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/containers/remote-container.test.js b/test/containers/remote-container.test.js index 673b20d33f..4996fc47fc 100644 --- a/test/containers/remote-container.test.js +++ b/test/containers/remote-container.test.js @@ -66,7 +66,7 @@ describe('RemoteContainer', function() { function expectEmptyIssueishQuery() { return expectRelayQuery({ - name: 'issueishListContainerQuery', + name: 'issueishSearchContainerQuery', variables: { query: 'repo:atom/github type:pr state:open', first: 20, From 322faa459618b28f3197c8492690b0732813ae85 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 11:08:32 -0400 Subject: [PATCH 0304/4847] Use result factory in IssueishSearchesController test --- .../issueish-searches-controller.test.js | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/test/controllers/issueish-searches-controller.test.js b/test/controllers/issueish-searches-controller.test.js index f1af5dcd81..f5ca3fe26d 100644 --- a/test/controllers/issueish-searches-controller.test.js +++ b/test/controllers/issueish-searches-controller.test.js @@ -2,6 +2,7 @@ import React from 'react'; import {shallow} from 'enzyme'; import {createRepositoryResult} from '../fixtures/factories/repository-result'; +import {createPullRequestResult} from '../fixtures/factories/pull-request-result'; import IssueishSearchesController from '../../lib/controllers/issueish-searches-controller'; import Remote from '../../lib/models/remote'; import Branch from '../../lib/models/branch'; @@ -90,21 +91,7 @@ describe('IssueishSearchesController', function() { const wrapper = shallow(buildApp()); const container = wrapper.find('IssueishSearchContainer').at(0); - const issueish = new Issueish({ - number: 123, - title: 'This is the title', - url: 'https://github.com/atom/github/pulls/123', - author: { - login: 'me', - avatarUrl: 'https://avatars2.githubusercontent.com/u/1234?v=6', - }, - createdAt: '2018-06-12T14:50:08Z', - refHeadName: 'feature', - headRepository: { - nameWithOwner: 'smashwilson/github', - }, - commits: {nodes: []}, - }); + const issueish = new Issueish(createPullRequestResult({number: 123})); await container.prop('onOpenIssueish')(issueish); assert.isTrue( From 35fe747bb07916216771c9ba21a5458e5d3e9677 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 11:45:40 -0400 Subject: [PATCH 0305/4847] Set flex-direction: column to center LoadingView --- styles/github-controller.less | 1 + 1 file changed, 1 insertion(+) diff --git a/styles/github-controller.less b/styles/github-controller.less index b6eb33e95a..89917d9146 100644 --- a/styles/github-controller.less +++ b/styles/github-controller.less @@ -12,6 +12,7 @@ &-content { flex: 1; display: flex; + flex-direction: column; } &-no-remotes { From 89a896f50fd4c432e45932a2d26212a04b6aba2a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 13:43:29 -0400 Subject: [PATCH 0306/4847] Delete unused components --- lib/containers/pr-info-container.js | 223 ----------- .../pr-selection-by-branch-container.js | 303 -------------- .../pr-selection-by-url-container.js | 61 --- lib/controllers/pr-info-controller.js | 194 --------- lib/views/pr-url-input-box.js | 54 --- .../pr-selection-by-branch-container.test.js | 374 ------------------ 6 files changed, 1209 deletions(-) delete mode 100644 lib/containers/pr-info-container.js delete mode 100644 lib/containers/pr-selection-by-branch-container.js delete mode 100644 lib/containers/pr-selection-by-url-container.js delete mode 100644 lib/controllers/pr-info-controller.js delete mode 100644 lib/views/pr-url-input-box.js delete mode 100644 test/containers/pr-selection-by-branch-container.test.js diff --git a/lib/containers/pr-info-container.js b/lib/containers/pr-info-container.js deleted file mode 100644 index 659e7e9267..0000000000 --- a/lib/containers/pr-info-container.js +++ /dev/null @@ -1,223 +0,0 @@ -import React from 'react'; -import {graphql, createRefetchContainer} from 'react-relay'; -import PropTypes from 'prop-types'; -import cx from 'classnames'; -import tinycolor from 'tinycolor2'; - -import Octicon from '../atom/octicon'; -import IssueishBadge from '../views/issueish-badge'; -import PeriodicRefresher from '../periodic-refresher'; -import PrStatusesContainer from './pr-statuses-container'; -import {autobind} from '../helpers'; - -const reactionTypeToEmoji = { - THUMBS_UP: '👍', - THUMBS_DOWN: '👎', - LAUGH: '😆', - HOORAY: '🎉', - CONFUSED: '😕', - HEART: '❤️', -}; - -export class PrInfo extends React.Component { - static propTypes = { - relay: PropTypes.shape({ - refetch: PropTypes.func.isRequired, - }).isRequired, - pinnedByUrl: PropTypes.bool, - onUnpinPr: PropTypes.func, - pullRequest: PropTypes.shape({ - id: PropTypes.string.isRequired, - title: PropTypes.string, - bodyHTML: PropTypes.string, - number: PropTypes.number, - repository: PropTypes.shape({ - name: PropTypes.string.isRequired, - owner: PropTypes.shape({ - login: PropTypes.string, - }), - }), - state: PropTypes.oneOf([ - 'OPEN', 'CLOSED', 'MERGED', - ]).isRequired, - author: PropTypes.shape({ - login: PropTypes.string.isRequired, - avatarUrl: PropTypes.string.isRequired, - url: PropTypes.string.isRequired, - }).isRequired, - reactionGroups: PropTypes.arrayOf( - PropTypes.shape({ - content: PropTypes.string.isRequired, - users: PropTypes.shape({ - totalCount: PropTypes.number.isRequired, - }).isRequired, - }), - ).isRequired, - }).isRequired, - } - - constructor(props) { - super(props); - autobind(this, 'handleRefreshClick', 'refresh', 'handleClickPrLink', 'handleUnpinClick'); - - this.state = { - refreshing: false, - }; - } - - componentDidMount() { - this.refresher = new PeriodicRefresher(PrInfo, { - interval: () => 3 * 60 * 1000, - getCurrentId: () => this.props.pullRequest.id, - refresh: this.refresh, - minimumIntervalPerId: 60 * 1000, - }); - this.refresher.start(); - } - - componentWillUnmount() { - this.refresher.destroy(); - } - - handleRefreshClick(e) { - e.preventDefault(); - this.refresher.refreshNow(true); - } - - refresh() { - if (this.state.refreshing) { - return; - } - - this.setState({refreshing: true}); - this.props.relay.refetch({ - id: this.props.pullRequest.id, - }, null, () => { - this.setState({refreshing: false}); - }, {force: true}); - } - - render() { - const pr = this.props.pullRequest; - const repo = pr.repository; - return ( -
- {this.props.pinnedByUrl && this.renderPinnedPr()} - -
- - - -

{pr.title}

-
-
- - Conversation -
-
- - Commits {pr.commitsCount.totalCount} -
-
- {pr.labels.edges.map(({node}) => { - const {name, color} = node; - const hex = `#${color}`; - const textColor = tinycolor.mostReadable(hex, ['#fff', '#000']).toHexString(); - return ( - {name} - ); - })} -
-
- {pr.reactionGroups.map(group => ( - group.users.totalCount > 0 - ? - {reactionTypeToEmoji[group.content]}   {group.users.totalCount} - - : null - ))} -
- -
- ); - } - - renderPinnedPr() { - return ( -
- - - This pull request has been manually pinned to the current branch. - You may unpin it. - -
- - ); - } - - handleClickPrLink(event) { - event.nativeEvent.preventDefault(); - event.nativeEvent.stopPropagation(); - const pr = this.props.pullRequest; - const repo = pr.repository; - atom.workspace.open(`atom-github://issueish/https%3A%2F%2Fapi.github.com/${repo.owner.login}/${repo.name}/${pr.number}`); - } - - handleUnpinClick(event) { - event.preventDefault(); - this.props.onUnpinPr && this.props.onUnpinPr(); - } -} - -export default createRefetchContainer(PrInfo, { - pullRequest: graphql` - fragment prInfoContainer_pullRequest on PullRequest { - ...prStatusesContainer_pullRequest - id url number title state createdAt - author { - login avatarUrl - ... on User { url } - ... on Bot { url } - } - repository { name owner { login } } - reactionGroups { - content users { totalCount } - } - commitsCount:commits { totalCount } - labels(first:100) { - edges { - node { - name color - } - } - } - } - `, -}, graphql` - query prInfoContainerRefetchQuery($id: ID!) { - pullRequest:node(id: $id) { - ... on PullRequest { - ...prInfoContainer_pullRequest - } - } - } -`); diff --git a/lib/containers/pr-selection-by-branch-container.js b/lib/containers/pr-selection-by-branch-container.js deleted file mode 100644 index 1874b0434c..0000000000 --- a/lib/containers/pr-selection-by-branch-container.js +++ /dev/null @@ -1,303 +0,0 @@ -import React from 'react'; -import {graphql, createFragmentContainer} from 'react-relay'; -import PropTypes from 'prop-types'; - -import PrInfoContainer from './pr-info-container'; -import PrUrlInputBox from '../views/pr-url-input-box'; -import Octicon from '../atom/octicon'; -import {RemotePropType, BranchSetPropType} from '../prop-types'; -import {autobind} from '../helpers'; - -export class PrSelectionByBranch extends React.Component { - static propTypes = { - repository: PropTypes.shape({ - defaultBranchRef: PropTypes.shape({ - prefix: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - }), - pullRequests: PropTypes.shape({ - totalCount: PropTypes.number.isRequired, - edges: PropTypes.arrayOf(PropTypes.shape({ - node: PropTypes.shape({ - id: PropTypes.string.isRequired, - number: PropTypes.number.isRequired, - title: PropTypes.string.isRequired, - url: PropTypes.string.isRequired, - }).isRequired, - })).isRequired, - }), - }), - onSelectPr: PropTypes.func.isRequired, - onUnpinPr: PropTypes.func.isRequired, - onCreatePr: PropTypes.func.isRequired, - onSearchAgain: PropTypes.func.isRequired, - variables: PropTypes.shape({ - repoOwner: PropTypes.string.isRequired, - repoName: PropTypes.string.isRequired, - branchName: PropTypes.string.isRequired, - }), - remote: RemotePropType, - aheadCount: PropTypes.number, - branches: BranchSetPropType.isRequired, - pushInProgress: PropTypes.bool.isRequired, - } - - constructor(props, context) { - super(props, context); - autobind(this, 'renderPrItem', 'toggleInputBoxVisibility', 'setPr', 'selectPullRequest'); - this.state = {displayInputBox: false}; - } - - render() { - return ( -
- {this.renderSubview()} -
- ); - } - - renderSubview() { - const repo = this.props.repository; - const {variables} = this.props; - if (!repo || !repo.pullRequests.edges.length) { - return this.renderCreatePr(); - } - - const edges = repo.pullRequests.edges; - if (edges.length === 1) { - return ( -
-
-
- - Specify Pull Request URL to pin -
- {this.state.displayInputBox && - -

- We found a pull request associated with the branch {variables.branchName} on the - repository {variables.repoOwner}/{variables.repoName}. -

-

- You can manually pin a different GitHub pull request to the current branch by entering its URL: -

-
- } -
- -
- ); - } - - return this.renderPrSelectionList(edges, repo.pullRequests.totalCount); - } - - renderCreatePr() { - return ( -
-
-
- -

New Pull Request

- {this.renderCreatePrControl()} -
-
-
-
- -

- Search again - to discover an existing pull request, or manually link a GitHub pull request to the current branch by - entering its URL: -

-
-
-
- ); - } - - renderCreatePrControl() { - if (!this.props.repository) { - return ( -
- Repository not found for the remote {this.props.remote.getName()}. - Do you need to update your remote URL? -
- ); - } - - if (this.isDetachedHead()) { - return ( -
- You are not currently on any branch. -  Create a new branch  - to share your work with a pull request. -
- ); - } - - if (!this.props.repository.defaultBranchRef) { - return ( -
- The repository at remote {this.props.remote.getName()} is - empty. Push a main branch to begin sharing your work. -
- ); - } - - if (this.isOnDefaultRef()) { - return ( -
- You are currently on your repository's default branch. -  Create a new branch  - to share your work with a pull request. -
- ); - } - - if (this.isSameAsDefaultRef()) { - return ( -
- Your current branch has not moved from the repository's default branch. -  Make some commits  - to share your work with a pull request. -
- ); - } - - let message = 'Open new pull request'; - let disable = false; - const differentRemote = this.pushesToDifferentRemote(); - if (this.props.pushInProgress) { - message = 'Pushing...'; - disable = true; - } else if (!this.hasUpstreamBranch() || differentRemote) { - message = 'Publish + open new pull request'; - } else if (this.props.aheadCount > 0) { - message = 'Push + open new pull request'; - } - - return ( -
- {differentRemote && -
- Your current branch is configured to push to the remote - {this.props.branches.getHeadBranch().getPush().getRemoteName()}. - Publish it to {this.props.remote.getName()} instead? -
- } -

- -

-
- ); - } - - renderPrSelectionList(edges, totalCount) { - const {variables} = this.props; - return ( -
-
- We found {totalCount} pull requests associated - with a branch named {variables.branchName} on the - repository {variables.repoOwner}/{variables.repoName}. - Select a pull request below to display it, or specify - any pull request URL to pin it manually: -
-
- -
-
    - {edges.map(this.renderPrItem)} -
-
- ); - } - - renderPrItem({node}) { - return ( -
  • this.selectPullRequest(e, node)}> - #{node.number}: {node.title} -
  • - ); - } - - toggleInputBoxVisibility() { - this.setState({displayInputBox: !this.state.displayInputBox}); - } - - setPr(prLink) { - this.props.onSelectPr(prLink); - } - - selectPullRequest(event, node) { - event.preventDefault(); - this.setPr(node.url); - } - - getDefaultBranchRef() { - const ref = this.props.repository.defaultBranchRef; - return `${ref.prefix}${ref.name}`; - } - - isDetachedHead() { - return !this.props.branches.getHeadBranch().isPresent(); - } - - isOnDefaultRef() { - if (!this.props.repository) { return false; } - - const currentBranch = this.props.branches.getHeadBranch(); - return currentBranch.getPush().getRemoteRef() === this.getDefaultBranchRef(); - } - - isSameAsDefaultRef() { - if (!this.props.repository) { return false; } - - const currentBranch = this.props.branches.getHeadBranch(); - const mainBranches = this.props.branches.getPushSources(this.props.remote.getName(), this.getDefaultBranchRef()); - return mainBranches.some(branch => branch.getSha() === currentBranch.getSha()); - } - - pushesToDifferentRemote() { - const p = this.props.branches.getHeadBranch().getPush(); - if (!p.isRemoteTracking()) { return false; } - - const pushRemoteName = p.getRemoteName(); - return pushRemoteName !== this.props.remote.getName(); - } - - hasUpstreamBranch() { - return this.props.branches.getHeadBranch().getUpstream().isPresent(); - } -} - -export default createFragmentContainer(PrSelectionByBranch, { - repository: graphql` - fragment prSelectionByBranchContainer_repository on Repository { - defaultBranchRef { - prefix - name - } - - pullRequests(first: 30, headRefName: $branchName) { - totalCount - edges { - node { - id number title url - ...prInfoContainer_pullRequest - } - } - } - } - `, -}); diff --git a/lib/containers/pr-selection-by-url-container.js b/lib/containers/pr-selection-by-url-container.js deleted file mode 100644 index e321ad9b7c..0000000000 --- a/lib/containers/pr-selection-by-url-container.js +++ /dev/null @@ -1,61 +0,0 @@ -import React from 'react'; -import {graphql, createFragmentContainer} from 'react-relay'; -import PropTypes from 'prop-types'; - -import PrInfoContainer from './pr-info-container'; -import PrUrlInputBox from '../views/pr-url-input-box'; - -export class PrSelectionByUrl extends React.Component { - static propTypes = { - resource: PropTypes.object, - prUrl: PropTypes.string, - onSelectPr: PropTypes.func.isRequired, - onUnpinPr: PropTypes.func.isRequired, - variables: PropTypes.shape({ - prUrl: PropTypes.string.isRequired, - }), - } - - render() { - const resource = this.props.resource; - if (!resource || resource.__typename !== 'PullRequest') { - return ( -
    - -

    - This branch is pinned to the pull request - at this URL: - - but we couldn't find a pull request at that URL. -

    -

    - You can manually pin another GitHub pull request to the current branch by entering its URL: -

    -
    -
    - ); - } - return ( - - ); - } - - setPr(prLink) { - this.props.onSelectPr(prLink); - } -} - -export default createFragmentContainer(PrSelectionByUrl, { - resource: graphql` - fragment prSelectionByUrlContainer_resource on UniformResourceLocatable { - __typename - ... on PullRequest { - ...prInfoContainer_pullRequest - } - } - `, -}); diff --git a/lib/controllers/pr-info-controller.js b/lib/controllers/pr-info-controller.js deleted file mode 100644 index 7bcf20048e..0000000000 --- a/lib/controllers/pr-info-controller.js +++ /dev/null @@ -1,194 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {QueryRenderer, graphql} from 'react-relay'; - -import {RemotePropType, BranchSetPropType} from '../prop-types'; -import PrSelectionByUrlContainer from '../containers/pr-selection-by-url-container'; -import PrSelectionByBranchContainer from '../containers/pr-selection-by-branch-container'; -import GithubLoginView from '../views/github-login-view'; -import RelayNetworkLayerManager from '../relay-network-layer-manager'; -import {UNAUTHENTICATED} from '../shared/keytar-strategy'; -import {autobind} from '../helpers'; - -export default class PrInfoController extends React.Component { - static propTypes = { - token: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.symbol, - ]).isRequired, - host: PropTypes.string.isRequired, - selectedPrUrl: PropTypes.string, - branches: BranchSetPropType.isRequired, - remote: RemotePropType.isRequired, - aheadCount: PropTypes.number, - pushInProgress: PropTypes.bool.isRequired, - onLogin: PropTypes.func.isRequired, - onLogout: PropTypes.func.isRequired, - onSelectPr: PropTypes.func.isRequired, - onUnpinPr: PropTypes.func.isRequired, - onCreatePr: PropTypes.func.isRequired, - } - - constructor(props) { - super(props); - autobind(this, 'renderLoading', 'renderSpecificPrFailure', 'renderFailure'); - } - - render() { - if (this.props.token === UNAUTHENTICATED) { - return null; - } - - if (this.props.selectedPrUrl) { - return this.renderSpecificPr(); - } else { - return this.renderPrByBranchName(); - } - } - - renderSpecificPr() { - const {token, host} = this.props; - - const environment = RelayNetworkLayerManager.getEnvironmentForHost(host, token); - const variables = { - prUrl: this.props.selectedPrUrl, - }; - - return ( - { - if (error) { - return this.renderSpecificPrFailure(error, retry); - } else if (props) { - return ( - - ); - } else { - return this.renderLoading(); - } - }} - /> - ); - } - - renderPrByBranchName() { - const {token, host} = this.props; - - const environment = RelayNetworkLayerManager.getEnvironmentForHost(host, token); - const variables = { - repoOwner: this.props.remote.getOwner(), - repoName: this.props.remote.getRepo(), - branchName: this.props.branches.getHeadBranch().getName(), - }; - return ( - { - if (error) { - return this.renderSpecificPrFailure(error, retry); - } else if (props) { - return ( - - ); - } else { - return this.renderLoading(); - } - }} - /> - ); - } - - renderLoading() { - return ( -
    - -
    - ); - } - - renderSpecificPrFailure(err, retry) { - if (this.isNotFoundError(err)) { - return ( - - ); - } else { - return this.renderFailure(err, retry); - } - } - - renderFailure(err, retry) { - if (err.response && err.response.status === 401) { - return ( -
    - -

    - The API endpoint returned a unauthorized error. Please try to re-authenticate with the endpoint. -

    -
    -
    - ); - } else { - return ( -
    -
    -

    Error

    -

    - An unknown error occurred -

    -
    - - -
    -
    -
    - ); - } - } - - isNotFoundError(err) { - return err.source && - err.source.errors && - err.source.errors[0] && - err.source.errors[0].type === 'NOT_FOUND'; - } -} diff --git a/lib/views/pr-url-input-box.js b/lib/views/pr-url-input-box.js deleted file mode 100644 index 790bf151ff..0000000000 --- a/lib/views/pr-url-input-box.js +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import {autobind} from '../helpers'; - -export default class PrUrlInputBox extends React.Component { - static propTypes = { - onSubmit: PropTypes.func.isRequired, - children: PropTypes.node, - } - - constructor(props, context) { - super(props, context); - autobind(this, 'handleSubmitUrlClick', 'handleSubmitUrl', 'handleUrlChange'); - this.state = { - url: '', - }; - } - - render() { - return ( -
    - {this.props.children} - -
    - -
    -
    - ); - } - - handleSubmitUrlClick(e) { - e.preventDefault(); - this.handleSubmitUrl(); - } - - handleSubmitUrl() { - this.props.onSubmit(this.state.url); - } - - handleUrlChange(e) { - this.setState({url: e.target.value}); - } -} diff --git a/test/containers/pr-selection-by-branch-container.test.js b/test/containers/pr-selection-by-branch-container.test.js deleted file mode 100644 index 181bd7680e..0000000000 --- a/test/containers/pr-selection-by-branch-container.test.js +++ /dev/null @@ -1,374 +0,0 @@ -import React from 'react'; -import {shallow} from 'enzyme'; - -import Remote from '../../lib/models/remote'; -import Branch, {nullBranch} from '../../lib/models/branch'; -import BranchSet from '../../lib/models/branch-set'; -import {PrSelectionByBranch} from '../../lib/containers/pr-selection-by-branch-container'; - -describe('PrSelectionByBranch', function() { - let branches, remote, onSelectPr, onUnpinPr, onCreatePr, onSearchAgain; - let app; - - beforeEach(function() { - branches = new BranchSet(); - remote = new Remote('origin', 'git@github.com:atom/github.git'); - - onSelectPr = sinon.spy(); - onUnpinPr = sinon.spy(); - onCreatePr = sinon.spy(); - onSearchAgain = sinon.spy(); - - app = ( - - ); - }); - - // Populate the `branches` prop with a set of Branches that triggers the happy path: HEAD on a feature branch that - // has been moved from the repository's main branch. - function setUpFeatureBranch() { - const mainUpstream = Branch.createRemoteTracking('refs/remotes/origin/master', 'origin', 'refs/heads/master'); - const main = new Branch( - 'master', - mainUpstream, - mainUpstream, - false, - {sha: 'ac133c710d2f789c36799bddffe88b10551c6484'}, - ); - branches.add(main); - const featureUpstream = Branch.createRemoteTracking( - 'refs/remotes/origin/feature', - 'origin', - 'refs/heads/feature', - ); - const feature = new Branch( - 'feature', - featureUpstream, - featureUpstream, - true, - {sha: 'ece5f33141b84077cbd68bfa09283d73d18433e5'}, - ); - branches.add(feature); - } - - describe('with no repository', function() { - beforeEach(function() { - app = React.cloneElement(app, { - repository: null, - variables: { - repoOwner: 'me', repoName: 'stuff', branchName: 'ohhai', - }, - }); - }); - - it('renders a message', function() { - const wrapper = shallow(app); - assert.isTrue(wrapper.find('.github-PrSelectionByBranch-message').exists()); - }); - }); - - describe('with no pull request', function() { - beforeEach(function() { - app = React.cloneElement(app, { - repository: { - defaultBranchRef: { - prefix: 'refs/heads/', - name: 'master', - }, - pullRequests: { - totalCount: 0, - edges: [], - }, - }, - variables: { - repoOwner: 'me', repoName: 'stuff', branchName: 'ohhai', - }, - }); - }); - - it('shows an input field to manually pin an existing pull request by URL', function() { - const wrapper = shallow(app); - - const inputField = wrapper.find('PrUrlInputBox'); - assert.isTrue(inputField.exists()); - inputField.prop('onSubmit')('https://github.com/me/stuff/pull/1234'); - assert.isTrue(onSelectPr.calledWith('https://github.com/me/stuff/pull/1234')); - }); - - describe('with no remote tracking branch', function() { - beforeEach(function() { - const feature = new Branch( - 'feature', - nullBranch, - nullBranch, - true, - {sha: 'ece5f33141b84077cbd68bfa09283d73d18433e5'}, - ); - branches.add(feature); - }); - - it('shows a button to publish your branch and create a PR', function() { - const wrapper = shallow(app); - - const button = wrapper.find('.github-PrSelectionByBranch-createPr'); - assert.isTrue(button.exists()); - assert.strictEqual(button.text(), 'Publish + open new pull request'); - button.simulate('click'); - assert.isTrue(onCreatePr.called); - }); - - it('shows a link to search again', function() { - const wrapper = shallow(app); - - const link = wrapper.find('.github-PrSelectionByBranch-searchAgain'); - assert.isTrue(link.exists()); - link.simulate('click'); - assert.isTrue(onSearchAgain.called); - }); - }); - - describe('with unpushed commits', function() { - beforeEach(function() { - setUpFeatureBranch(); - app = React.cloneElement(app, {aheadCount: 3}); - }); - - it('shows a button to push your commits and create a PR', function() { - const wrapper = shallow(app); - - const button = wrapper.find('.github-PrSelectionByBranch-createPr'); - assert.isTrue(button.exists()); - assert.strictEqual(button.text(), 'Push + open new pull request'); - button.simulate('click'); - assert.isTrue(onCreatePr.called); - }); - }); - - describe('while pushing is in progress', function() { - beforeEach(function() { - setUpFeatureBranch(); - app = React.cloneElement(app, { - aheadCount: 3, - pushInProgress: true, - }); - }); - - it('disables the button and changes the caption', function() { - const wrapper = shallow(app); - - const button = wrapper.find('.github-PrSelectionByBranch-createPr'); - assert.isTrue(button.prop('disabled')); - assert.strictEqual(button.text(), 'Pushing...'); - }); - }); - - describe('when fully pushed', function() { - beforeEach(function() { - setUpFeatureBranch(); - app = React.cloneElement(app, {aheadCount: 0}); - }); - - it('shows a button to open a new pull request', function() { - const wrapper = shallow(app); - - const button = wrapper.find('.github-PrSelectionByBranch-createPr'); - assert.isTrue(button.exists()); - assert.strictEqual(button.text(), 'Open new pull request'); - button.simulate('click'); - assert.isTrue(onCreatePr.called); - }); - }); - - describe('with no main branch', function() { - beforeEach(function() { - branches.add(new Branch('feature', nullBranch, nullBranch, true)); - - app = React.cloneElement(app, { - repository: { - defaultBranchRef: null, - pullRequests: { - totalCount: 0, - edges: [], - }, - }, - variables: { - repoOwner: 'me', repoName: 'empty', branchName: 'ohhai', - }, - }); - }); - - it('does not show the new pull request button', function() { - const wrapper = shallow(app); - assert.isFalse(wrapper.find('.github-PrSelectionByBranch-createPr').exists()); - }); - - it('shows a placeholder message', function() { - const wrapper = shallow(app); - assert.isTrue(wrapper.find('.github-PrSelectionByBranch-message').exists()); - }); - }); - - describe('while on the main branch', function() { - beforeEach(function() { - const mainUpstream = Branch.createRemoteTracking('refs/remotes/origin/master', 'origin', 'refs/heads/splork'); - const main = new Branch( - 'master', - mainUpstream, - mainUpstream, - true, - {sha: 'ac133c710d2f789c36799bddffe88b10551c6484'}, - ); - branches.add(main); - - app = React.cloneElement(app, { - repository: { - defaultBranchRef: { - prefix: 'refs/heads/', - name: 'splork', - }, - pullRequests: { - totalCount: 0, - edges: [], - }, - }, - }); - }); - - it('does not show the new pull request button', function() { - const wrapper = shallow(app); - assert.isFalse(wrapper.find('.github-PrSelectionByBranch-createPr').exists()); - }); - - it('prompts you to create a branch', function() { - const wrapper = shallow(app); - assert.strictEqual(wrapper.find('.github-CreatePr strong').text(), 'Create a new branch'); - }); - }); - - describe('when just branched from the main branch', function() { - beforeEach(function() { - // "main" and "feature" are still on the same SHA - const main = new Branch( - 'main', - Branch.createRemoteTracking('refs/remotes/elsewhere/main', 'elsewhere', 'refs/heads/develop'), - Branch.createRemoteTracking('refs/remotes/origin/main', 'origin', 'refs/heads/develop'), - false, - {sha: 'ece5f33141b84077cbd68bfa09283d73d18433e5'}, - ); - branches.add(main); - - const feature = new Branch( - 'feature', - nullBranch, - nullBranch, - true, - {sha: 'ece5f33141b84077cbd68bfa09283d73d18433e5'}, - ); - branches.add(feature); - - app = React.cloneElement(app, { - repository: { - defaultBranchRef: { - prefix: 'refs/heads/', - name: 'develop', - }, - pullRequests: { - totalCount: 0, - edges: [], - }, - }, - }); - }); - - it('does not show the new pull request button', function() { - const wrapper = shallow(app); - assert.isFalse(wrapper.find('.github-PrSelectionByBranch-createPr').exists()); - }); - - it('prompts you to commit', function() { - const wrapper = shallow(app); - assert.strictEqual(wrapper.find('.github-CreatePr strong').text(), 'Make some commits'); - }); - }); - - describe('when on a detached HEAD', function() { - beforeEach(function() { - const main = new Branch( - 'main', - Branch.createRemoteTracking('refs/remotes/elsewhere/main', 'elsewhere', 'refs/heads/develop'), - Branch.createRemoteTracking('refs/remotes/origin/main', 'origin', 'refs/heads/develop'), - false, - {sha: 'ece5f33141b84077cbd68bfa09283d73d18433e5'}, - ); - branches.add(main); - }); - - it('does not show the new pull request button', function() { - const wrapper = shallow(app); - assert.isFalse(wrapper.find('.github-PrSelectionByBranch-createPr').exists()); - }); - - it('prompts you to create or check out a branch', function() { - const wrapper = shallow(app); - assert.strictEqual(wrapper.find('.github-CreatePr strong').text(), 'Create a new branch'); - }); - }); - - describe('on a branch configured to push to a different remote', function() { - beforeEach(function() { - const u = Branch.createRemoteTracking( - 'refs/remotes/origin/feature', - 'origin', - 'refs/heads/feature', - ); - const p = Branch.createRemoteTracking( - 'refs/remotes/mine/feature', - 'mine', - 'refs/heads/feature', - ); - const feature = new Branch( - 'feature', - u, - p, - true, - {sha: 'ece5f33141b84077cbd68bfa09283d73d18433e5'}, - ); - branches.add(feature); - }); - - it('informs you that your branch is currently pushed to a different remote', function() { - const wrapper = shallow(app); - assert.strictEqual(wrapper.find('.github-CreatePr code').at(0).text(), 'mine'); - }); - - it('shows a button to publish your branch to the current remote and create a PR', function() { - const wrapper = shallow(app); - - const button = wrapper.find('.github-PrSelectionByBranch-createPr'); - assert.isTrue(button.exists()); - assert.strictEqual(button.text(), 'Publish + open new pull request'); - button.simulate('click'); - assert.isTrue(onCreatePr.called); - }); - - it('shows a link to search again', function() { - const wrapper = shallow(app); - - const link = wrapper.find('.github-PrSelectionByBranch-searchAgain'); - assert.isTrue(link.exists()); - link.simulate('click'); - assert.isTrue(onSearchAgain.called); - }); - }); - }); -}); From 39dab4778665681d38a786b13f2aea888e0b2557 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 13:48:18 -0400 Subject: [PATCH 0307/4847] Remove unused CSS --- styles/_global.less | 1 - styles/pr-info.less | 162 ----------------------------------- styles/pr-selection.less | 74 ---------------- styles/pr-url-input-box.less | 71 --------------- styles/tabs.less | 83 ------------------ 5 files changed, 391 deletions(-) delete mode 100644 styles/pr-info.less delete mode 100644 styles/pr-selection.less delete mode 100644 styles/pr-url-input-box.less delete mode 100644 styles/tabs.less diff --git a/styles/_global.less b/styles/_global.less index 3ebca030e2..691318a366 100644 --- a/styles/_global.less +++ b/styles/_global.less @@ -3,7 +3,6 @@ // Styles for things that are sprinkled throuout various places // vertical align the text with the icon -.github-Tabs, .github-PrPaneItem, .tooltip { .badge .icon:before { diff --git a/styles/pr-info.less b/styles/pr-info.less deleted file mode 100644 index 7e9d1064c3..0000000000 --- a/styles/pr-info.less +++ /dev/null @@ -1,162 +0,0 @@ -@import 'variables'; - -@label-padding: @component-padding / 2; -@avatar-size: 32px; - -.github-RemotePrController { - flex: 1; - min-width: 0; - display: flex; - flex-direction: column; - overflow-y: auto; -} - -.github-PrInfo { - padding: @component-padding * 2; - overflow: auto; - flex: 1; - cursor: default; - - .icon { - vertical-align: middle; - } - - .pinned-by-url { - cursor: pointer; - } - - .pinned-pr-info { - display: flex; - padding: @component-padding; - border: 1px solid @text-color-subtle; - border-radius: @component-border-radius; - margin-bottom: @component-padding * 2; - - a { - text-decoration: underline; - } - } - - // Badge and link ------------------------ - .pr-badge-and-link { - display: flex; - align-items: center; - margin-bottom: @component-padding * 2; - - .browser-link { - display: inline-block; - margin-left: 0.5em; - } - - :last-child { - flex: 1; - text-align: right; - } - } - - .pr-link a { - color: @text-color-subtle; - word-break: break-all; - } - - .refresh-button { - .icon { - color: @text-color-subtle; - cursor: pointer; - - &.refreshing::before { - @keyframes github-RefreshButton-animation { - 100% { transform: rotate(360deg); } - } - animation: github-RefreshButton-animation 2s linear 30; // limit to 1min in case something gets stuck - } - } - } - - - // Avatar and title ------------------------ - - .pr-avatar-and-title { - display: flex; - align-items: center; - margin-bottom: @component-padding; - } - - .author-avatar-link { - margin-right: @component-padding; - align-self: flex-start; - } - - .author-avatar { - max-height: @avatar-size; - border-radius: @component-border-radius; - } - - .pr-title { - margin: 0; - line-height: 1.2; - color: @text-color-highlight; - } - - // Status ------------------------ - - .merge-status, - .build-status { - line-height: 2; - } - .merge-status.success { - .icon { color: @text-color-success; } - } - .build-status.pending { - .icon { color: @text-color-warning; } - } - - // Info ------------------------ - - .count-number { - margin-left: .25em; - font-size: 1.1em; - font-weight: 600; - line-height: 1; - } - - .label { - padding: 0 @label-padding; - margin: 0 @label-padding @label-padding 0; - border-radius: @component-border-radius; - line-height: 2em; - display: inline-block; - } - - - // Reactions ------------------------ - - .reactions { - .reaction-group { - margin-right: @component-padding * 2; - } - } - - // Statuses ------------------------ - - .github-PrStatuses { - border-top: 1px solid @base-border-color; - padding-top: @component-padding * 2; - } - - // All "items" ------------------------ - - .meta-info, - .conversation, - .commit-count, - .file-count, - .reactions, - .labels { - border-top: 1px solid @base-border-color; - padding: @component-padding 0; - } - - .conversation { - cursor: pointer; - } -} diff --git a/styles/pr-selection.less b/styles/pr-selection.less deleted file mode 100644 index 92d0650666..0000000000 --- a/styles/pr-selection.less +++ /dev/null @@ -1,74 +0,0 @@ -@import 'variables'; - -.github-PrSelectionByBranch { - flex: 1; - display: flex; - overflow: auto; - - &-container { - flex: 1; - display: flex; - flex-direction: column; - } - - &-divider { - margin: 0; - border-top: 1px solid @base-border-color; - } - - &-cell { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; - text-align: center; - padding: @component-padding * 2; - - // TODO: Simplify selector - & > .github-PrUrlInputBox-Subview { - flex: none; - } - } - - &-message { - padding: 0 @component-padding; - margin: @component-padding 0; - } - - &-input { - padding: 0 @component-padding; - margin: @component-padding 0; - - // TODO: Simplify selector - .github-PrUrlInputBox-Subview > input { - margin-top: 0; - } - } - - &-list { - list-style: none; - padding-left: 0; - cursor: default; - - li { - padding: @component-padding/2 @component-padding; - border-top: 1px solid @base-border-color; - &:hover { - background-color: @background-color-highlight; - } - } - } - -} - -// New PR - -.github-CreatePr { - &-icon:before { - font-size: 3em; - } - - &-title { - font-size: 1.6em; - } -} diff --git a/styles/pr-url-input-box.less b/styles/pr-url-input-box.less deleted file mode 100644 index 9e4f5e5558..0000000000 --- a/styles/pr-url-input-box.less +++ /dev/null @@ -1,71 +0,0 @@ - -@import "variables"; - -.github-PrUrlInputBox { - - &-Container { - display: flex; - flex: 1; - flex-direction: row; - - // TODO: Simplify selector - // Only add padding when inside this container - .github-PrUrlInputBox-Subview { - padding: @component-padding * 2; - } - - p { - text-align: center; - } - } - - &-pinButton { - padding: @component-padding; - border-bottom: 1px solid @base-border-color; - cursor: default; - } - - // TODO: Simplify selector - &-pinButton + &-Subview { - padding: @component-padding; - border-bottom: 1px solid @base-border-color; - } - - &-Subview { - flex: 1; - display: flex; - flex-direction: column; - align-self: center; - align-items: center; - - > button, > input { - margin: @component-padding; - } - - .icon-git-pull-request:before { - width: auto; - font-size: 48px; - color: @text-color-subtle; - } - - p { - font-size: 1.1em; - line-height: 1.5; - -webkit-user-select: none; - cursor: default; - - &:last-of-type { - margin-bottom: 0; - } - - a { - color: @text-color-info; - } - } - - input[type=text] { - width: 100%; - } - } - -} diff --git a/styles/tabs.less b/styles/tabs.less deleted file mode 100644 index 0d2dc4259d..0000000000 --- a/styles/tabs.less +++ /dev/null @@ -1,83 +0,0 @@ -@import "variables"; - -// General Styles -.github-Tabs { - &-Panel { - &.active { - display: flex; - } - - &.inactive { - display: none; - } - } -} - -// App-specific styles -.github-Tabs.sidebar-tabs { - height: 100%; - display: flex; - flex-direction: column; - - .github-Tabs-NavigationContainer { - display: flex; - flex-direction: row; - padding: @component-padding; - border-bottom: 1px solid @panel-heading-border-color; - - .github-Tabs-NavigationItem { - flex: 1; - text-align: center; - cursor: pointer; - background-color: @button-background-color; - color: contrast(@button-background-color, hsla(0,0%,0%,.6), hsla(0,0%,100%,.6)); - border: 1px solid @button-border-color; - padding: .25em .5em; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - & + .github-Tabs-NavigationItem { - border-left: none; - } - - &.active { - background-color: @button-background-color-selected; - color: contrast(@button-background-color-selected, hsla(0,0%,0%,1), hsla(0,0%,100%,1)); - } - - &:first-child { - border-top-left-radius: @component-border-radius; - border-bottom-left-radius: @component-border-radius; - } - - &:last-child { - border-top-right-radius: @component-border-radius; - border-bottom-right-radius: @component-border-radius; - } - } - - } - - &[data-tabs-count="1"] { - .github-Tabs-NavigationContainer { - display: none; - } - } - - .github-Tabs-PanelContainer { - flex: 1; - display: flex; - flex-direction: column; - } - - .github-Tabs-Panel { - flex: 1; - - &.active { - } - - &.inactive { - } - } -} From dd0a882c80b1fa86e6d655bf118aa078472866fe Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 13:55:44 -0400 Subject: [PATCH 0308/4847] Render a "loading" message for each IssueishList --- lib/views/issueish-list-view.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index c60bfc3216..bc78532783 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -32,7 +32,7 @@ export default class IssueishListView extends React.Component { constructor(props) { super(props); - autobind(this, 'renderIssueish', 'renderEmptyTile', 'renderMoreTile'); + autobind(this, 'renderIssueish', 'renderLoadingTile', 'renderEmptyTile', 'renderMoreTile'); } render() { @@ -42,6 +42,7 @@ export default class IssueishListView extends React.Component { isLoading={this.props.isLoading} results={this.props.issueishes} total={this.props.total} + loadingComponent={this.renderLoadingTile} emptyComponent={this.renderEmptyTile} moreComponent={this.renderMoreTile} onClickItem={this.props.onIssueishClick}> @@ -90,6 +91,14 @@ export default class IssueishListView extends React.Component { return ; } + renderLoadingTile() { + return ( +
    + Loading +
    + ); + } + renderEmptyTile() { if (this.props.error) { return ; From 1269ca90f1c4461397338ba33bbc19c06677d12e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 13:55:54 -0400 Subject: [PATCH 0309/4847] Keep stylesheet name consistent --- ...{issuesish-list-view.less => issueish-list-view.less} | 9 +++++++++ 1 file changed, 9 insertions(+) rename styles/{issuesish-list-view.less => issueish-list-view.less} (88%) diff --git a/styles/issuesish-list-view.less b/styles/issueish-list-view.less similarity index 88% rename from styles/issuesish-list-view.less rename to styles/issueish-list-view.less index 0f7047c5cd..6d78ce45f6 100644 --- a/styles/issuesish-list-view.less +++ b/styles/issueish-list-view.less @@ -74,6 +74,15 @@ color: @text-color-subtle; } } + + &-loading { + margin: @component-padding / 4; + display: flex; + flex-direction: row; + justify-content: center; + font-style: italic; + color: @text-color-subtle; + } } .github-CreatePullRequestTile { From d3b5cfad7f942480c4088cea068796c36d2c3ae0 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 14:48:42 -0400 Subject: [PATCH 0310/4847] :art: Error styling --- lib/views/query-error-tile.js | 33 ++++++++++++++++++++------------- lib/views/query-error-view.js | 6 +++--- styles/issueish-list-view.less | 20 ++++++++++++++++++++ styles/message.less | 5 +++++ 4 files changed, 48 insertions(+), 16 deletions(-) diff --git a/lib/views/query-error-tile.js b/lib/views/query-error-tile.js index 2a260fea9a..e946f9d85e 100644 --- a/lib/views/query-error-tile.js +++ b/lib/views/query-error-tile.js @@ -16,11 +16,17 @@ export default class QueryErrorTile extends React.Component { }).isRequired, } + componentDidMount() { + // eslint-disable-next-line no-console + console.error('Error encountered in subquery', this.props.error); + } + render() { return (
    - - {this.renderMessages()} +
    + {this.renderMessages()} +
    ); } @@ -28,22 +34,23 @@ export default class QueryErrorTile extends React.Component { renderMessages() { if (this.props.error.errors) { return this.props.error.errors.map((error, index) => { - return ( -

    - {error.message} -

    - ); + return this.renderMessage(error.message, index); }); } if (this.props.error.response) { - return ( -

    - {this.props.error.responseText} -

    - ); + return this.renderMessage(this.props.error.responseText, '0'); } - return

    {this.props.error.toString()}

    ; + return this.renderMessage(this.props.error.toString(), '0'); + } + + renderMessage(body, key) { + return ( +

    + + {body} +

    + ); } } diff --git a/lib/views/query-error-view.js b/lib/views/query-error-view.js index 83614161f1..da0d38e67e 100644 --- a/lib/views/query-error-view.js +++ b/lib/views/query-error-view.js @@ -32,7 +32,7 @@ export default class QueryErrorView extends React.Component { case 200: // Do the default break; - default: return this.renderUnknown(e.response); + default: return this.renderUnknown(e.response, e.responseText); } } @@ -72,11 +72,11 @@ export default class QueryErrorView extends React.Component { ); } - renderUnknown(response) { + renderUnknown(response, text) { return ( diff --git a/styles/issueish-list-view.less b/styles/issueish-list-view.less index 6d78ce45f6..bf7e4a2753 100644 --- a/styles/issueish-list-view.less +++ b/styles/issueish-list-view.less @@ -92,3 +92,23 @@ text-align: center; } } + +.github-QueryErrorTile { + padding: @component-padding; + display: flex; + color: @text-color-error; + + &-messages { + display: flex; + flex-direction: column; + flex-grow: 1 + } + + .icon-alert { + vertical-align: text-top; + } + + &-message { + font-weight: bold; + } +} diff --git a/styles/message.less b/styles/message.less index 9bbe0a020f..7328ed601a 100644 --- a/styles/message.less +++ b/styles/message.less @@ -29,6 +29,7 @@ margin: auto; padding: @component-padding*2; text-align: center; + width: 100%; } &-title { @@ -41,6 +42,10 @@ font-size: 1.2em; line-height: 1.4; margin-bottom: 0; + + pre& { + text-align: left; + } } &-longDescription { From 66f593dcde7189667d9e48c60d646cf27eb031c7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 20 Jun 2018 14:59:20 -0400 Subject: [PATCH 0311/4847] Response text is extracted beforehand --- test/views/query-error-view.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/views/query-error-view.test.js b/test/views/query-error-view.test.js index e8d4e67362..a78c907694 100644 --- a/test/views/query-error-view.test.js +++ b/test/views/query-error-view.test.js @@ -45,8 +45,8 @@ describe('QueryErrorView', function() { const error = new Error('GraphQL error'); error.response = { status: 500, - text: () => 'response text', }; + error.responseText = 'response text'; error.rawStack = error.stack; const wrapper = shallow(buildApp({error})); From c523511f0298b7ef920f993551785d6f8095605c Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 21 Jun 2018 12:51:58 +0900 Subject: [PATCH 0312/4847] Add styling tweaks to messages and controls --- styles/accordion.less | 8 +++++++- styles/issueish-list-view.less | 11 +++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/styles/accordion.less b/styles/accordion.less index 5f20841dc0..683b4562cf 100644 --- a/styles/accordion.less +++ b/styles/accordion.less @@ -16,6 +16,9 @@ } &-content { + border-bottom: 1px solid @base-border-color; + background-color: @base-background-color; + // Add an "Empty" label for empty items &:empty::before { content: "Empty"; @@ -41,7 +44,10 @@ align-items: center; padding: @component-padding / 4; border-bottom: 1px solid @base-border-color; - background-color: @base-background-color; + + &:last-child { + border: none; + } &:active { background-color: @background-color-highlight; diff --git a/styles/issueish-list-view.less b/styles/issueish-list-view.less index bf7e4a2753..2710da8f4a 100644 --- a/styles/issueish-list-view.less +++ b/styles/issueish-list-view.less @@ -76,11 +76,10 @@ } &-loading { - margin: @component-padding / 4; - display: flex; - flex-direction: row; - justify-content: center; + padding: @component-padding / 2; + min-height: 29px; // Magic number: Prevents jumping. font-style: italic; + text-align: center; color: @text-color-subtle; } } @@ -90,6 +89,10 @@ &-controls { padding: @component-padding; text-align: center; + margin-bottom: 0; + } + &-createPr { + width: 100%; } } From ea66f29573e055672bcca581fa6ac72aeeac69cc Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 21 Jun 2018 13:01:08 +0900 Subject: [PATCH 0313/4847] Align status icons --- styles/issueish-list-view.less | 1 + 1 file changed, 1 insertion(+) diff --git a/styles/issueish-list-view.less b/styles/issueish-list-view.less index 2710da8f4a..a4ebfc4fdf 100644 --- a/styles/issueish-list-view.less +++ b/styles/issueish-list-view.less @@ -25,6 +25,7 @@ &--status { @size: 20px; + text-align: center; &:before { margin-right: 0; From 9eaa3dbb757ea00e4e83bc36dd53243cb27d4fa2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 07:30:32 -0400 Subject: [PATCH 0314/4847] Use an IssueishPropType for IssueishListView --- lib/prop-types.js | 12 ++++++++++++ lib/views/issueish-list-view.js | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/prop-types.js b/lib/prop-types.js index b34e868bd2..e4aa34754f 100644 --- a/lib/prop-types.js +++ b/lib/prop-types.js @@ -75,6 +75,18 @@ export const OperationStateObserverPropType = PropTypes.shape({ dispose: PropTypes.func.isRequired, }); +export const IssueishPropType = PropTypes.shape({ + getNumber: PropTypes.func.isRequired, + getTitle: PropTypes.func.isRequired, + getGitHubURL: PropTypes.func.isRequired, + getAuthorLogin: PropTypes.func.isRequired, + getAuthorAvatarURL: PropTypes.func.isRequired, + getCreatedAt: PropTypes.func.isRequired, + getHeadRefName: PropTypes.func.isRequired, + getHeadRepositoryID: PropTypes.func.isRequired, + getStatusCounts: PropTypes.func.isRequired, +}); + export const FilePatchItemPropType = PropTypes.shape({ filePath: PropTypes.string.isRequired, status: PropTypes.string.isRequired, diff --git a/lib/views/issueish-list-view.js b/lib/views/issueish-list-view.js index bc78532783..90b7fa2573 100644 --- a/lib/views/issueish-list-view.js +++ b/lib/views/issueish-list-view.js @@ -2,6 +2,7 @@ import React, {Fragment} from 'react'; import PropTypes from 'prop-types'; import {autobind} from '../helpers'; +import {IssueishPropType} from '../prop-types'; import Accordion from './accordion'; import Timeago from './timeago'; import StatusDonutChart from './status-donut-chart'; @@ -13,7 +14,7 @@ export default class IssueishListView extends React.Component { title: PropTypes.string.isRequired, isLoading: PropTypes.bool.isRequired, total: PropTypes.number.isRequired, - issueishes: PropTypes.arrayOf(PropTypes.any).isRequired, + issueishes: PropTypes.arrayOf(IssueishPropType).isRequired, repository: PropTypes.shape({ defaultBranchRef: PropTypes.shape({ From aa61a7495dc544cf3976da5e5add3f9671c4c773 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 07:38:18 -0400 Subject: [PATCH 0315/4847] Test passing an Error to an IssueishListController --- test/controllers/issueish-list-controller.test.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/controllers/issueish-list-controller.test.js b/test/controllers/issueish-list-controller.test.js index fc9eb4dc72..d5b0970684 100644 --- a/test/controllers/issueish-list-controller.test.js +++ b/test/controllers/issueish-list-controller.test.js @@ -32,6 +32,15 @@ describe('IssueishListController', function() { assert.lengthOf(view.prop('issueishes'), 0); }); + it('renders an IssueishListView in an error state', function() { + const error = new Error("d'oh"); + error.rawStack = error.stack; + const wrapper = shallow(buildApp({error})); + + const view = wrapper.find('IssueishListView'); + assert.strictEqual(view.prop('error'), error); + }); + it('renders an IssueishListView with issueish results', function() { const mockPullRequest = createPullRequestResult({number: 1}); From ebee2600ffbccf1c321fc479c9e62287b1a9ffba Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 07:41:42 -0400 Subject: [PATCH 0316/4847] (capital H *cough*) --- lib/models/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/search.js b/lib/models/search.js index 7e23cc4ef7..42d8a12681 100644 --- a/lib/models/search.js +++ b/lib/models/search.js @@ -27,7 +27,7 @@ export default class Search { getWebURL(remote) { if (!remote.isGithubRepo()) { - throw new Error(`Attempt to generate web URL for non-Github remote ${remote.getName()}`); + throw new Error(`Attempt to generate web URL for non-GitHub remote ${remote.getName()}`); } return `https://${remote.getDomain()}/search?q=${encodeURIComponent(this.createQuery())}`; From a0c17a759245f6bdc325241cae3b51d38df6accb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 07:42:03 -0400 Subject: [PATCH 0317/4847] Test failing to generate search URLs from non-GitHub remotes --- test/models/search.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/models/search.test.js b/test/models/search.test.js index 7afe94dd7d..ec2122eea1 100644 --- a/test/models/search.test.js +++ b/test/models/search.test.js @@ -13,6 +13,13 @@ describe('Search', function() { ); }); + it('throws an error when attempting to generate a dotcom URL from a non-dotcom remote', function() { + const nonDotCom = new Remote('elsewhere', 'git://git.gnupg.org/gnupg.git'); + + const s = new Search('zzz', 'type:pr is:open'); + assert.throws(() => s.getWebURL(nonDotCom), /non-GitHub remote/); + }); + describe('when scoped to a remote', function() { it('is a null search when the remote is not present', function() { const s = Search.inRemote(nullRemote, 'name', 'query'); From 2d24625589aae3d2c64d16597f23d4ee5f12a853 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 07:57:42 -0400 Subject: [PATCH 0318/4847] Depend on nyc --- package-lock.json | 5430 +++++++++++++++++++++++++++++++-------------- package.json | 3 +- 2 files changed, 3812 insertions(+), 1621 deletions(-) diff --git a/package-lock.json b/package-lock.json index d671bcad3d..968497caea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,10 +26,10 @@ "dev": true, "requires": { "@babel/types": "7.0.0-beta.44", - "jsesc": "2.5.1", - "lodash": "4.17.5", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "jsesc": "^2.5.1", + "lodash": "^4.2.0", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" }, "dependencies": { "jsesc": { @@ -87,9 +87,9 @@ "integrity": "sha1-GMlM5UORaoBVPtzc9oGJCyAHR9U=", "dev": true, "requires": { - "chalk": "2.4.1", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" }, "dependencies": { "ansi-styles": { @@ -98,7 +98,7 @@ "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "chalk": { @@ -107,9 +107,9 @@ "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "escape-string-regexp": { @@ -130,11 +130,17 @@ "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } }, + "@babel/parser": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.0.0-beta.49.tgz", + "integrity": "sha1-lE0MW6KBK7FZ7b0iZ0Ov0mUXm9w=", + "dev": true + }, "@babel/template": { "version": "7.0.0-beta.44", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz", @@ -144,7 +150,7 @@ "@babel/code-frame": "7.0.0-beta.44", "@babel/types": "7.0.0-beta.44", "babylon": "7.0.0-beta.44", - "lodash": "4.17.5" + "lodash": "^4.2.0" }, "dependencies": { "babylon": { @@ -167,10 +173,10 @@ "@babel/helper-split-export-declaration": "7.0.0-beta.44", "@babel/types": "7.0.0-beta.44", "babylon": "7.0.0-beta.44", - "debug": "3.1.0", - "globals": "11.5.0", - "invariant": "2.2.4", - "lodash": "4.17.5" + "debug": "^3.1.0", + "globals": "^11.1.0", + "invariant": "^2.2.0", + "lodash": "^4.2.0" }, "dependencies": { "babylon": { @@ -200,7 +206,7 @@ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, "requires": { - "loose-envify": "1.3.1" + "loose-envify": "^1.0.0" } }, "loose-envify": { @@ -209,7 +215,7 @@ "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "dev": true, "requires": { - "js-tokens": "3.0.2" + "js-tokens": "^3.0.0" } } } @@ -220,9 +226,9 @@ "integrity": "sha1-axsWRZH3fewKA0KsqZXy0Eazp1c=", "dev": true, "requires": { - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" }, "dependencies": { "esutils": { @@ -242,17 +248,17 @@ "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=", "dev": true, "requires": { - "call-me-maybe": "1.0.1", - "glob-to-regexp": "0.3.0" + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" } }, "@sinonjs/formatio": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", - "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", + "integrity": "sha1-hNt+nrVTHfGKjF4L+25EnlXmVLI=", "dev": true, "requires": { "samsam": "1.3.0" @@ -261,27 +267,27 @@ "@smashwilson/enzyme-adapter-react-16": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@smashwilson/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.2.tgz", - "integrity": "sha512-YGotyPAPOwi9vbRzvTutDgqYbBo5gX8mELNHPICcAXilV9XMa0yxqCQ6OY4ItIO5dPiRkc9RkjSYBr2M1fFOZw==", + "integrity": "sha1-8NRWRn/qp5AwV8vF5PqsZKWoBsg=", "dev": true, "requires": { - "@smashwilson/enzyme-adapter-utils": "1.0.0", - "lodash": "4.17.5", - "object.assign": "4.1.0", - "object.values": "1.0.4", - "prop-types": "15.6.1", - "react-reconciler": "0.7.0", - "react-test-renderer": "16.4.1" + "@smashwilson/enzyme-adapter-utils": "^1.0.0", + "lodash": "^4.17.4", + "object.assign": "^4.1.0", + "object.values": "^1.0.4", + "prop-types": "^15.6.0", + "react-reconciler": "^0.7.0", + "react-test-renderer": "^16.0.0-0" } }, "@smashwilson/enzyme-adapter-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@smashwilson/enzyme-adapter-utils/-/enzyme-adapter-utils-1.0.0.tgz", - "integrity": "sha512-/kQoTFU5bdbZbh6C9Ohxz1BgoHW+n2BX/kGUcS3DucGZfVNl4Em9lJqzd3aelyZSJz+cRX/FuE6ccnO6MnZc0Q==", + "integrity": "sha1-H5zSVcvNm1Fd8WkCGgLbEMX8Ydc=", "dev": true, "requires": { - "lodash": "4.17.5", - "object.assign": "4.1.0", - "prop-types": "15.6.1" + "lodash": "^4.17.4", + "object.assign": "^4.1.0", + "prop-types": "^15.6.0" } }, "@types/node": { @@ -302,7 +308,7 @@ "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "acorn": "3.3.0" + "acorn": "^3.0.4" }, "dependencies": { "acorn": { @@ -318,10 +324,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "ajv-keywords": { @@ -358,8 +364,8 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.3" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "argparse": { @@ -368,7 +374,7 @@ "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "arr-diff": { @@ -395,7 +401,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -416,8 +422,8 @@ "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", "dev": true, "requires": { - "define-properties": "1.1.2", - "es-abstract": "1.11.0" + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" } }, "arrify": { @@ -469,7 +475,7 @@ "resolved": "https://registry.npmjs.org/atom-babel6-transpiler/-/atom-babel6-transpiler-1.1.3.tgz", "integrity": "sha1-1wKxDpDrzx+R4apcSnm5zqmKm6Y=", "requires": { - "babel-core": "6.26.3" + "babel-core": "6.x" } }, "atom-mocha-test-runner": { @@ -478,10 +484,10 @@ "integrity": "sha1-qPZQm40pqAn8tv9H8FiEthLNxqk=", "dev": true, "requires": { - "etch": "0.8.0", - "grim": "2.0.2", - "less": "2.7.3", - "mocha": "3.5.3", + "etch": "^0.8.0", + "grim": "^2.0.1", + "less": "^2.7.1", + "mocha": "^3.0.0", "tmp": "0.0.31" }, "dependencies": { @@ -497,7 +503,7 @@ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", "dev": true, "requires": { - "graceful-readlink": "1.0.1" + "graceful-readlink": ">= 1.0.0" } }, "debug": { @@ -521,7 +527,7 @@ "integrity": "sha1-VPYZV0NG+KPueXP1T7vQG1YnItY=", "dev": true, "requires": { - "virtual-dom": "2.1.1" + "virtual-dom": "^2.0.1" } }, "fs.realpath": { @@ -536,12 +542,12 @@ "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "grim": { @@ -550,7 +556,7 @@ "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==", "dev": true, "requires": { - "event-kit": "2.5.0" + "event-kit": "^2.0.0" } }, "growl": { @@ -571,8 +577,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -587,7 +593,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "mocha": { @@ -624,7 +630,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "path-is-absolute": { @@ -639,7 +645,7 @@ "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } }, "wrappy": { @@ -665,9 +671,9 @@ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" }, "dependencies": { "ansi-regex": { @@ -685,11 +691,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "escape-string-regexp": { @@ -707,7 +713,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-ansi": { @@ -715,7 +721,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "supports-color": { @@ -730,25 +736,25 @@ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", "integrity": "sha1-suLwnjQtDwyI4vAuBneUEl51wgc=", "requires": { - "babel-code-frame": "6.26.0", - "babel-generator": "6.26.1", - "babel-helpers": "6.24.1", - "babel-messages": "6.23.0", - "babel-register": "6.26.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "convert-source-map": "1.5.1", - "debug": "2.6.9", - "json5": "0.5.1", - "lodash": "4.17.5", - "minimatch": "3.0.4", - "path-is-absolute": "1.0.1", - "private": "0.1.8", - "slash": "1.0.0", - "source-map": "0.5.7" + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" }, "dependencies": { "babel-runtime": { @@ -756,8 +762,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-template": { @@ -765,11 +771,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.5" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" } }, "babel-traverse": { @@ -777,15 +783,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" } }, "babel-types": { @@ -793,10 +799,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "babylon": { @@ -826,8 +832,8 @@ "@babel/traverse": "7.0.0-beta.44", "@babel/types": "7.0.0-beta.44", "babylon": "7.0.0-beta.44", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0" + "eslint-scope": "~3.7.1", + "eslint-visitor-keys": "^1.0.0" }, "dependencies": { "babylon": { @@ -843,14 +849,14 @@ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", "integrity": "sha1-GERAjTuPDTWkBOp6wYDwh6YBvZA=", "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.5", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" }, "dependencies": { "babel-messages": { @@ -858,7 +864,7 @@ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" } }, "babel-runtime": { @@ -866,8 +872,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-types": { @@ -875,10 +881,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "esutils": { @@ -913,9 +919,9 @@ "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "esutils": "2.0.2" + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "esutils": "^2.0.2" }, "dependencies": { "babel-runtime": { @@ -923,8 +929,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-types": { @@ -932,10 +938,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "esutils": { @@ -961,10 +967,10 @@ "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", "dev": true, "requires": { - "babel-helper-hoist-variables": "6.24.1", - "babel-runtime": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0" + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" } }, "babel-helper-define-map": { @@ -973,10 +979,10 @@ "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", "dev": true, "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.5" + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" }, "dependencies": { "babel-runtime": { @@ -985,8 +991,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-types": { @@ -995,16 +1001,16 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", "dev": true }, "to-fast-properties": { @@ -1021,11 +1027,11 @@ "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", "dev": true, "requires": { - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.25.0", - "babel-template": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0" + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" } }, "babel-helper-get-function-arity": { @@ -1034,8 +1040,8 @@ "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", "dev": true, "requires": { - "babel-runtime": "6.25.0", - "babel-types": "6.25.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, "babel-helper-hoist-variables": { @@ -1044,8 +1050,8 @@ "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", "dev": true, "requires": { - "babel-runtime": "6.25.0", - "babel-types": "6.25.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, "babel-helper-optimise-call-expression": { @@ -1054,8 +1060,8 @@ "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", "dev": true, "requires": { - "babel-runtime": "6.25.0", - "babel-types": "6.25.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, "babel-helper-replace-supers": { @@ -1064,12 +1070,12 @@ "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", "dev": true, "requires": { - "babel-helper-optimise-call-expression": "6.24.1", - "babel-messages": "6.23.0", - "babel-runtime": "6.25.0", - "babel-template": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0" + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" } }, "babel-helpers": { @@ -1077,8 +1083,8 @@ "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", "requires": { - "babel-runtime": "6.25.0", - "babel-template": "6.25.0" + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" } }, "babel-messages": { @@ -1086,7 +1092,7 @@ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-chai-assert-async": { @@ -1100,7 +1106,7 @@ "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", "dev": true, "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-relay": { @@ -1108,8 +1114,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-relay/-/babel-plugin-relay-1.6.0.tgz", "integrity": "sha1-oiTaUkNi1pA6UkIUobhAUw/fvSg=", "requires": { - "babel-runtime": "6.25.0", - "babel-types": "6.25.0" + "babel-runtime": "^6.23.0", + "babel-types": "^6.24.1" } }, "babel-plugin-syntax-class-properties": { @@ -1143,10 +1149,10 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", "requires": { - "babel-helper-function-name": "6.24.1", - "babel-plugin-syntax-class-properties": "6.13.0", - "babel-runtime": "6.25.0", - "babel-template": "6.25.0" + "babel-helper-function-name": "^6.24.1", + "babel-plugin-syntax-class-properties": "^6.8.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" }, "dependencies": { "babel-helper-function-name": { @@ -1154,11 +1160,11 @@ "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", "requires": { - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.25.0", - "babel-template": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0" + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" } }, "babel-helper-get-function-arity": { @@ -1166,8 +1172,8 @@ "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", "requires": { - "babel-runtime": "6.25.0", - "babel-types": "6.25.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } } } @@ -1178,7 +1184,7 @@ "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", "dev": true, "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-es2015-block-scoped-functions": { @@ -1187,7 +1193,7 @@ "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", "dev": true, "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-es2015-block-scoping": { @@ -1196,11 +1202,11 @@ "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.5" + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" }, "dependencies": { "babel-runtime": { @@ -1209,8 +1215,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-template": { @@ -1219,11 +1225,11 @@ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.5" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" } }, "babel-traverse": { @@ -1232,15 +1238,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" } }, "babel-types": { @@ -1249,22 +1255,22 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=", "dev": true }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", "dev": true }, "to-fast-properties": { @@ -1281,15 +1287,15 @@ "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", "dev": true, "requires": { - "babel-helper-define-map": "6.26.0", - "babel-helper-function-name": "6.24.1", - "babel-helper-optimise-call-expression": "6.24.1", - "babel-helper-replace-supers": "6.24.1", - "babel-messages": "6.23.0", - "babel-runtime": "6.25.0", - "babel-template": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0" + "babel-helper-define-map": "^6.24.1", + "babel-helper-function-name": "^6.24.1", + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-helper-replace-supers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" } }, "babel-plugin-transform-es2015-computed-properties": { @@ -1298,8 +1304,8 @@ "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", "dev": true, "requires": { - "babel-runtime": "6.25.0", - "babel-template": "6.25.0" + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" } }, "babel-plugin-transform-es2015-destructuring": { @@ -1308,7 +1314,7 @@ "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", "dev": true, "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-es2015-for-of": { @@ -1317,7 +1323,7 @@ "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", "dev": true, "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-es2015-function-name": { @@ -1326,9 +1332,9 @@ "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", "dev": true, "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.25.0", - "babel-types": "6.25.0" + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, "babel-plugin-transform-es2015-literals": { @@ -1337,7 +1343,7 @@ "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", "dev": true, "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-es2015-modules-commonjs": { @@ -1345,10 +1351,10 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", "integrity": "sha1-WKeThjqefKhwvcWogRF/+sJ9tvM=", "requires": { - "babel-plugin-transform-strict-mode": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-types": "6.26.0" + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" }, "dependencies": { "ansi-regex": { @@ -1366,9 +1372,9 @@ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" } }, "babel-messages": { @@ -1376,7 +1382,7 @@ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" } }, "babel-runtime": { @@ -1384,8 +1390,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-template": { @@ -1393,11 +1399,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.5" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" } }, "babel-traverse": { @@ -1405,15 +1411,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" } }, "babel-types": { @@ -1421,10 +1427,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "babylon": { @@ -1437,11 +1443,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "escape-string-regexp": { @@ -1459,7 +1465,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "regenerator-runtime": { @@ -1472,7 +1478,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "supports-color": { @@ -1493,8 +1499,8 @@ "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", "dev": true, "requires": { - "babel-helper-replace-supers": "6.24.1", - "babel-runtime": "6.25.0" + "babel-helper-replace-supers": "^6.24.1", + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-es2015-parameters": { @@ -1503,12 +1509,12 @@ "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", "dev": true, "requires": { - "babel-helper-call-delegate": "6.24.1", - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.25.0", - "babel-template": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0" + "babel-helper-call-delegate": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" } }, "babel-plugin-transform-es2015-shorthand-properties": { @@ -1517,8 +1523,8 @@ "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", "dev": true, "requires": { - "babel-runtime": "6.25.0", - "babel-types": "6.25.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, "babel-plugin-transform-es2015-spread": { @@ -1527,7 +1533,7 @@ "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", "dev": true, "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-es2015-template-literals": { @@ -1536,7 +1542,7 @@ "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", "dev": true, "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-es3-member-expression-literals": { @@ -1545,7 +1551,7 @@ "integrity": "sha1-cz00RPPsxBvvjtGmpOCWV7iWnrs=", "dev": true, "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-es3-property-literals": { @@ -1554,7 +1560,7 @@ "integrity": "sha1-sgeNWELiKr9A9z6M3pzTcRq9V1g=", "dev": true, "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-flow-strip-types": { @@ -1562,8 +1568,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", "requires": { - "babel-plugin-syntax-flow": "6.18.0", - "babel-runtime": "6.25.0" + "babel-plugin-syntax-flow": "^6.18.0", + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-object-rest-spread": { @@ -1571,8 +1577,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", "requires": { - "babel-plugin-syntax-object-rest-spread": "6.13.0", - "babel-runtime": "6.26.0" + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" }, "dependencies": { "babel-runtime": { @@ -1580,8 +1586,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "regenerator-runtime": { @@ -1596,7 +1602,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=", "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-react-jsx": { @@ -1604,9 +1610,9 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", "requires": { - "babel-helper-builder-react-jsx": "6.26.0", - "babel-plugin-syntax-jsx": "6.18.0", - "babel-runtime": "6.25.0" + "babel-helper-builder-react-jsx": "^6.24.1", + "babel-plugin-syntax-jsx": "^6.8.0", + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-react-jsx-self": { @@ -1614,8 +1620,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz", "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=", "requires": { - "babel-plugin-syntax-jsx": "6.18.0", - "babel-runtime": "6.25.0" + "babel-plugin-syntax-jsx": "^6.8.0", + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-react-jsx-source": { @@ -1623,8 +1629,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz", "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=", "requires": { - "babel-plugin-syntax-jsx": "6.18.0", - "babel-runtime": "6.25.0" + "babel-plugin-syntax-jsx": "^6.8.0", + "babel-runtime": "^6.22.0" } }, "babel-plugin-transform-strict-mode": { @@ -1632,8 +1638,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", "requires": { - "babel-runtime": "6.25.0", - "babel-types": "6.25.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, "babel-polyfill": { @@ -1642,9 +1648,9 @@ "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "core-js": "2.5.0", - "regenerator-runtime": "0.10.5" + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "regenerator-runtime": "^0.10.5" }, "dependencies": { "babel-runtime": { @@ -1653,14 +1659,14 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" }, "dependencies": { "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", "dev": true } } @@ -1673,34 +1679,34 @@ "integrity": "sha1-IvNY5mVAc6z2HkegUqd317zPA68=", "dev": true, "requires": { - "babel-plugin-check-es2015-constants": "6.22.0", - "babel-plugin-syntax-class-properties": "6.13.0", - "babel-plugin-syntax-flow": "6.18.0", - "babel-plugin-syntax-jsx": "6.18.0", - "babel-plugin-syntax-object-rest-spread": "6.13.0", - "babel-plugin-syntax-trailing-function-commas": "6.22.0", - "babel-plugin-transform-class-properties": "6.24.1", - "babel-plugin-transform-es2015-arrow-functions": "6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", - "babel-plugin-transform-es2015-block-scoping": "6.26.0", - "babel-plugin-transform-es2015-classes": "6.24.1", - "babel-plugin-transform-es2015-computed-properties": "6.24.1", - "babel-plugin-transform-es2015-destructuring": "6.23.0", - "babel-plugin-transform-es2015-for-of": "6.23.0", - "babel-plugin-transform-es2015-function-name": "6.24.1", - "babel-plugin-transform-es2015-literals": "6.22.0", - "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", - "babel-plugin-transform-es2015-object-super": "6.24.1", - "babel-plugin-transform-es2015-parameters": "6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", - "babel-plugin-transform-es2015-spread": "6.22.0", - "babel-plugin-transform-es2015-template-literals": "6.22.0", - "babel-plugin-transform-es3-member-expression-literals": "6.22.0", - "babel-plugin-transform-es3-property-literals": "6.22.0", - "babel-plugin-transform-flow-strip-types": "6.22.0", - "babel-plugin-transform-object-rest-spread": "6.26.0", - "babel-plugin-transform-react-display-name": "6.25.0", - "babel-plugin-transform-react-jsx": "6.24.1" + "babel-plugin-check-es2015-constants": "^6.8.0", + "babel-plugin-syntax-class-properties": "^6.8.0", + "babel-plugin-syntax-flow": "^6.8.0", + "babel-plugin-syntax-jsx": "^6.8.0", + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-plugin-syntax-trailing-function-commas": "^6.8.0", + "babel-plugin-transform-class-properties": "^6.8.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.8.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.8.0", + "babel-plugin-transform-es2015-block-scoping": "^6.8.0", + "babel-plugin-transform-es2015-classes": "^6.8.0", + "babel-plugin-transform-es2015-computed-properties": "^6.8.0", + "babel-plugin-transform-es2015-destructuring": "^6.8.0", + "babel-plugin-transform-es2015-for-of": "^6.8.0", + "babel-plugin-transform-es2015-function-name": "^6.8.0", + "babel-plugin-transform-es2015-literals": "^6.8.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.8.0", + "babel-plugin-transform-es2015-object-super": "^6.8.0", + "babel-plugin-transform-es2015-parameters": "^6.8.0", + "babel-plugin-transform-es2015-shorthand-properties": "^6.8.0", + "babel-plugin-transform-es2015-spread": "^6.8.0", + "babel-plugin-transform-es2015-template-literals": "^6.8.0", + "babel-plugin-transform-es3-member-expression-literals": "^6.8.0", + "babel-plugin-transform-es3-property-literals": "^6.8.0", + "babel-plugin-transform-flow-strip-types": "^6.8.0", + "babel-plugin-transform-object-rest-spread": "^6.8.0", + "babel-plugin-transform-react-display-name": "^6.8.0", + "babel-plugin-transform-react-jsx": "^6.8.0" } }, "babel-preset-flow": { @@ -1708,7 +1714,7 @@ "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=", "requires": { - "babel-plugin-transform-flow-strip-types": "6.22.0" + "babel-plugin-transform-flow-strip-types": "^6.22.0" } }, "babel-preset-react": { @@ -1716,12 +1722,12 @@ "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", "requires": { - "babel-plugin-syntax-jsx": "6.18.0", - "babel-plugin-transform-react-display-name": "6.25.0", - "babel-plugin-transform-react-jsx": "6.24.1", - "babel-plugin-transform-react-jsx-self": "6.22.0", - "babel-plugin-transform-react-jsx-source": "6.22.0", - "babel-preset-flow": "6.23.0" + "babel-plugin-syntax-jsx": "^6.3.13", + "babel-plugin-transform-react-display-name": "^6.23.0", + "babel-plugin-transform-react-jsx": "^6.24.1", + "babel-plugin-transform-react-jsx-self": "^6.22.0", + "babel-plugin-transform-react-jsx-source": "^6.22.0", + "babel-preset-flow": "^6.23.0" } }, "babel-register": { @@ -1729,13 +1735,13 @@ "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", "requires": { - "babel-core": "6.26.3", - "babel-runtime": "6.26.0", - "core-js": "2.5.0", - "home-or-tmp": "2.0.0", - "lodash": "4.17.5", - "mkdirp": "0.5.1", - "source-map-support": "0.4.18" + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" }, "dependencies": { "babel-runtime": { @@ -1743,8 +1749,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "regenerator-runtime": { @@ -1759,8 +1765,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.25.0.tgz", "integrity": "sha1-M7mOql1IK7AajRqmtDetKwGuxBw=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.10.5" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.10.0" } }, "babel-template": { @@ -1768,11 +1774,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", "requires": { - "babel-runtime": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "lodash": "4.17.5" + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.25.0", + "babel-types": "^6.25.0", + "babylon": "^6.17.2", + "lodash": "^4.2.0" } }, "babel-traverse": { @@ -1780,15 +1786,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" + "babel-code-frame": "^6.22.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-types": "^6.25.0", + "babylon": "^6.17.2", + "debug": "^2.2.0", + "globals": "^9.0.0", + "invariant": "^2.2.0", + "lodash": "^4.2.0" }, "dependencies": { "babel-messages": { @@ -1796,7 +1802,7 @@ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "requires": { - "babel-runtime": "6.25.0" + "babel-runtime": "^6.22.0" } } } @@ -1806,10 +1812,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", "requires": { - "babel-runtime": "6.25.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.22.0", + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^1.0.1" }, "dependencies": { "esutils": { @@ -1840,13 +1846,13 @@ "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", "dev": true, "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.1", - "pascalcase": "0.1.1" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "dependencies": { "define-property": { @@ -1855,36 +1861,36 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -1895,7 +1901,7 @@ "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "bl": { @@ -1903,8 +1909,8 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha1-oWCRFxcQPAdBDO9j71Gzl8Alr5w=", "requires": { - "readable-stream": "2.3.6", - "safe-buffer": "5.1.1" + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" }, "dependencies": { "core-util-is": { @@ -1932,13 +1938,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -1946,7 +1952,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "util-deprecate": { @@ -1968,7 +1974,7 @@ "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", "dev": true, "requires": { - "hoek": "4.2.1" + "hoek": "4.x.x" } }, "brace-expansion": { @@ -1976,26 +1982,26 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.2", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -2004,7 +2010,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2021,7 +2027,7 @@ "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", "dev": true, "requires": { - "node-int64": "0.4.0" + "node-int64": "^0.4.0" } }, "buffer-alloc": { @@ -2029,8 +2035,8 @@ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.1.0.tgz", "integrity": "sha1-BVFNM78WVtNUDGhPZbEgLpDsowM=", "requires": { - "buffer-alloc-unsafe": "0.1.1", - "buffer-fill": "0.1.1" + "buffer-alloc-unsafe": "^0.1.0", + "buffer-fill": "^0.1.0" } }, "buffer-alloc-unsafe": { @@ -2066,15 +2072,15 @@ "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", "dev": true, "requires": { - "collection-visit": "1.0.0", - "component-emitter": "1.2.1", - "get-value": "2.0.6", - "has-value": "1.0.0", - "isobject": "3.0.1", - "set-value": "2.0.0", - "to-object-path": "0.3.0", - "union-value": "1.0.0", - "unset-value": "1.0.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" } }, "call-me-maybe": { @@ -2089,7 +2095,7 @@ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "0.2.0" + "callsites": "^0.2.0" } }, "callsites": { @@ -2121,12 +2127,12 @@ "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", "dev": true, "requires": { - "assertion-error": "1.1.0", - "check-error": "1.0.2", - "deep-eql": "3.0.1", - "get-func-name": "2.0.0", - "pathval": "1.1.0", - "type-detect": "4.0.8" + "assertion-error": "^1.0.1", + "check-error": "^1.0.1", + "deep-eql": "^3.0.0", + "get-func-name": "^2.0.0", + "pathval": "^1.0.0", + "type-detect": "^4.0.0" } }, "chai-as-promised": { @@ -2135,7 +2141,7 @@ "integrity": "sha1-CGRdgl3rhpbuYXJdv1kMAS6wDKA=", "dev": true, "requires": { - "check-error": "1.0.2" + "check-error": "^1.0.2" } }, "chalk": { @@ -2144,11 +2150,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "chardet": { @@ -2168,7 +2174,7 @@ "resolved": "https://registry.npmjs.org/checksum/-/checksum-0.1.1.tgz", "integrity": "sha1-3GUn1MkL6FYNvR7Uzs8yl9Uo6ek=", "requires": { - "optimist": "0.3.7" + "optimist": "~0.3.5" } }, "cheerio": { @@ -2177,12 +2183,12 @@ "integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=", "dev": true, "requires": { - "css-select": "1.2.0", - "dom-serializer": "0.1.0", - "entities": "1.1.1", - "htmlparser2": "3.9.2", - "lodash": "4.17.5", - "parse5": "3.0.3" + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash": "^4.15.0", + "parse5": "^3.0.1" } }, "chownr": { @@ -2202,10 +2208,10 @@ "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", "dev": true, "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { "define-property": { @@ -2214,7 +2220,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -2222,7 +2228,7 @@ "classnames": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + "integrity": "sha1-Q5Nb/90pHzJtrQogUwmzjQD2UM4=" }, "cli-cursor": { "version": "2.1.0", @@ -2230,7 +2236,7 @@ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "restore-cursor": "2.0.0" + "restore-cursor": "^2.0.0" } }, "cli-width": { @@ -2245,9 +2251,9 @@ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" }, "dependencies": { "string-width": { @@ -2256,9 +2262,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -2279,8 +2285,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "color-convert": { @@ -2289,7 +2295,7 @@ "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "^1.1.1" } }, "color-name": { @@ -2309,7 +2315,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "compare-sets": { @@ -2334,10 +2340,10 @@ "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", "dev": true, "requires": { - "buffer-from": "1.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "typedarray": "0.0.6" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" }, "dependencies": { "inherits": { @@ -2375,9 +2381,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.2", - "shebang-command": "1.2.0", - "which": "1.3.0" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" }, "dependencies": { "lru-cache": { @@ -2386,8 +2392,8 @@ "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "yallist": { @@ -2410,7 +2416,7 @@ "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", "dev": true, "requires": { - "boom": "5.2.0" + "boom": "5.x.x" }, "dependencies": { "boom": { @@ -2419,7 +2425,7 @@ "integrity": "sha1-XdnabuOl8wIHdDYpDLcX0/SlTgI=", "dev": true, "requires": { - "hoek": "4.2.1" + "hoek": "4.x.x" } } } @@ -2430,10 +2436,10 @@ "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "dev": true, "requires": { - "boolbase": "1.0.0", - "css-what": "2.1.0", + "boolbase": "~1.0.0", + "css-what": "2.1", "domutils": "1.5.1", - "nth-check": "1.0.1" + "nth-check": "~1.0.1" } }, "css-what": { @@ -2447,7 +2453,7 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "debug": { @@ -2475,7 +2481,7 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "requires": { - "mimic-response": "1.0.0" + "mimic-response": "^1.0.0" } }, "dedent-js": { @@ -2490,7 +2496,7 @@ "integrity": "sha1-38lARACtHI/gI+faHfHBR8S0RN8=", "dev": true, "requires": { - "type-detect": "4.0.8" + "type-detect": "^4.0.0" } }, "deep-extend": { @@ -2510,8 +2516,8 @@ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", "dev": true, "requires": { - "foreach": "2.0.5", - "object-keys": "1.0.11" + "foreach": "^2.0.5", + "object-keys": "^1.0.8" } }, "define-property": { @@ -2520,37 +2526,37 @@ "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", "dev": true, "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -2561,13 +2567,13 @@ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" }, "dependencies": { "object-assign": { @@ -2594,7 +2600,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "rimraf": { @@ -2603,7 +2609,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } } } @@ -2623,7 +2629,7 @@ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" } }, "detect-libc": { @@ -2649,8 +2655,8 @@ "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" }, "dependencies": { "esutils": { @@ -2673,8 +2679,8 @@ "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "dev": true, "requires": { - "domelementtype": "1.1.3", - "entities": "1.1.1" + "domelementtype": "~1.1.1", + "entities": "~1.1.1" }, "dependencies": { "domelementtype": { @@ -2703,7 +2709,7 @@ "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", "dev": true, "requires": { - "domelementtype": "1.3.0" + "domelementtype": "1" } }, "domutils": { @@ -2712,8 +2718,8 @@ "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "dev": true, "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.3.0" + "dom-serializer": "0", + "domelementtype": "1" } }, "dugite": { @@ -2721,12 +2727,12 @@ "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.66.0.tgz", "integrity": "sha1-X9q2aDwLU4p5vb7Emenz0+pyEPk=", "requires": { - "checksum": "0.1.1", - "mkdirp": "0.5.1", - "progress": "2.0.0", - "request": "2.87.0", - "rimraf": "2.6.2", - "tar": "4.4.4" + "checksum": "^0.1.1", + "mkdirp": "^0.5.1", + "progress": "^2.0.0", + "request": "^2.86.0", + "rimraf": "^2.5.4", + "tar": "^4.0.2" } }, "ecc-jsbn": { @@ -2735,19 +2741,19 @@ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "optional": true, "requires": { - "jsbn": "0.1.1" + "jsbn": "~0.1.0" } }, "electron-devtools-installer": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-2.2.4.tgz", - "integrity": "sha512-b5kcM3hmUqn64+RUcHjjr8ZMpHS2WJ5YO0pnG9+P/RTdx46of/JrEjuciHWux6pE+On6ynWhHJF53j/EDJN0PA==", + "integrity": "sha1-JhpQM343Eh0zi5ZvB5IutJOah2M=", "dev": true, "requires": { "7zip": "0.0.6", "cross-unzip": "0.0.2", - "rimraf": "2.6.2", - "semver": "5.4.1" + "rimraf": "^2.5.2", + "semver": "^5.3.0" } }, "encoding": { @@ -2755,7 +2761,7 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "requires": { - "iconv-lite": "0.4.18" + "iconv-lite": "~0.4.13" } }, "end-of-stream": { @@ -2763,7 +2769,7 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", "requires": { - "once": "1.4.0" + "once": "^1.4.0" }, "dependencies": { "once": { @@ -2771,7 +2777,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "wrappy": { @@ -2793,22 +2799,22 @@ "integrity": "sha1-CXGr0Wfy1L8/W9UIIp4cS23FBHk=", "dev": true, "requires": { - "cheerio": "1.0.0-rc.2", - "function.prototype.name": "1.1.0", - "has": "1.0.1", - "is-boolean-object": "1.0.0", - "is-callable": "1.1.3", - "is-number-object": "1.0.3", - "is-string": "1.0.4", - "is-subset": "0.1.1", - "lodash": "4.17.5", - "object-inspect": "1.5.0", - "object-is": "1.0.1", - "object.assign": "4.1.0", - "object.entries": "1.0.4", - "object.values": "1.0.4", - "raf": "3.4.0", - "rst-selector-parser": "2.2.3" + "cheerio": "^1.0.0-rc.2", + "function.prototype.name": "^1.0.3", + "has": "^1.0.1", + "is-boolean-object": "^1.0.0", + "is-callable": "^1.1.3", + "is-number-object": "^1.0.3", + "is-string": "^1.0.4", + "is-subset": "^0.1.1", + "lodash": "^4.17.4", + "object-inspect": "^1.5.0", + "object-is": "^1.0.1", + "object.assign": "^4.1.0", + "object.entries": "^1.0.4", + "object.values": "^1.0.4", + "raf": "^3.4.0", + "rst-selector-parser": "^2.2.3" } }, "errno": { @@ -2818,7 +2824,7 @@ "dev": true, "optional": true, "requires": { - "prr": "0.0.0" + "prr": "~0.0.0" } }, "error": { @@ -2827,9 +2833,9 @@ "integrity": "sha1-v2n/JR+0onnBmtzNqmth6Q2b8So=", "dev": true, "requires": { - "camelize": "1.0.0", - "string-template": "0.2.1", - "xtend": "4.0.1" + "camelize": "^1.0.0", + "string-template": "~0.2.0", + "xtend": "~4.0.0" } }, "error-ex": { @@ -2838,7 +2844,7 @@ "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, "es-abstract": { @@ -2847,11 +2853,11 @@ "integrity": "sha1-zOh9UY8Elok7GjDNhGGDVTVIBoE=", "dev": true, "requires": { - "es-to-primitive": "1.1.1", - "function-bind": "1.1.1", - "has": "1.0.1", - "is-callable": "1.1.3", - "is-regex": "1.0.4" + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" }, "dependencies": { "function-bind": { @@ -2868,9 +2874,9 @@ "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", "dev": true, "requires": { - "is-callable": "1.1.3", - "is-date-object": "1.0.1", - "is-symbol": "1.0.1" + "is-callable": "^1.1.1", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.1" } }, "escape-string-regexp": { @@ -2885,44 +2891,44 @@ "integrity": "sha1-MtHWU+HZBAiFS/spbwdux+GGowA=", "dev": true, "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.2", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.5.0", - "ignore": "3.3.8", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.11.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.5", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "regexpp": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.4.1", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", "table": "4.0.2", - "text-table": "0.2.0" + "text-table": "~0.2.0" }, "dependencies": { "ansi-regex": { @@ -2937,7 +2943,7 @@ "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "babel-code-frame": { @@ -2946,9 +2952,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" }, "dependencies": { "ansi-regex": { @@ -2969,11 +2975,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "strip-ansi": { @@ -2982,7 +2988,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "supports-color": { @@ -2999,9 +3005,9 @@ "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "debug": { @@ -3016,10 +3022,10 @@ "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", "dev": true, "requires": { - "esutils": "2.0.2" + "esutils": "^2.0.2" } }, "escape-string-regexp": { @@ -3046,7 +3052,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" }, "dependencies": { "ansi-regex": { @@ -3063,7 +3069,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "strip-ansi": { @@ -3072,7 +3078,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } }, "supports-color": { @@ -3081,7 +3087,7 @@ "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -3092,13 +3098,13 @@ "integrity": "sha1-n2yIvtUXwGDuqcQ0BqBXMw2whJc=", "dev": true, "requires": { - "babel-eslint": "7.2.3", - "eslint-plugin-babel": "4.1.2", - "eslint-plugin-flowtype": "2.46.3", - "eslint-plugin-jasmine": "2.9.3", - "eslint-plugin-prefer-object-spread": "1.2.1", - "eslint-plugin-react": "6.10.3", - "fbjs-eslint-utils": "1.0.0" + "babel-eslint": "^7.1.1", + "eslint-plugin-babel": "^4.0.1", + "eslint-plugin-flowtype": "^2.30.0", + "eslint-plugin-jasmine": "^2.2.0", + "eslint-plugin-prefer-object-spread": "^1.1.0", + "eslint-plugin-react": "^6.9.0", + "fbjs-eslint-utils": "^1.0.0" }, "dependencies": { "ansi-regex": { @@ -3119,9 +3125,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" } }, "babel-eslint": { @@ -3130,10 +3136,10 @@ "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.17.4" + "babel-code-frame": "^6.22.0", + "babel-traverse": "^6.23.1", + "babel-types": "^6.23.0", + "babylon": "^6.17.0" } }, "chalk": { @@ -3142,11 +3148,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "escape-string-regexp": { @@ -3167,11 +3173,11 @@ "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", "dev": true, "requires": { - "array.prototype.find": "2.0.4", - "doctrine": "1.5.0", - "has": "1.0.1", - "jsx-ast-utils": "1.4.1", - "object.assign": "4.1.0" + "array.prototype.find": "^2.0.1", + "doctrine": "^1.2.2", + "has": "^1.0.1", + "jsx-ast-utils": "^1.3.4", + "object.assign": "^4.0.4" } }, "esutils": { @@ -3186,7 +3192,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "jsx-ast-utils": { @@ -3201,7 +3207,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "supports-color": { @@ -3218,7 +3224,7 @@ "integrity": "sha1-foQTHYfvGLSWsYEESFkzdIYLTo4=", "dev": true, "requires": { - "lodash": "4.17.5" + "lodash": "^4.15.0" } }, "eslint-plugin-jasmine": { @@ -3239,8 +3245,8 @@ "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", "dev": true, "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "eslint-visitor-keys": { @@ -3255,8 +3261,8 @@ "integrity": "sha1-sPRHGHyKi+2US4FaZgvd9d610ac=", "dev": true, "requires": { - "acorn": "5.5.3", - "acorn-jsx": "3.0.1" + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" } }, "esprima": { @@ -3271,7 +3277,7 @@ "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.0.0" } }, "esrecurse": { @@ -3280,7 +3286,7 @@ "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.1.0" } }, "estraverse": { @@ -3300,13 +3306,13 @@ "integrity": "sha1-GrDH+CE2UF3XSzHRdwHLK+bSZVg=", "dev": true, "requires": { - "individual": "3.0.0" + "individual": "^3.0.0" } }, "event-kit": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.0.tgz", - "integrity": "sha512-tUDxeNC9JzN2Tw/f8mLtksY34v1hHmaR7lV7X4p04XSjaeUhFMfzjF6Nwov9e0EKGEx63BaKcgXKxjpQaPo0wg==" + "integrity": "sha1-L3KxHitfUzzByVA4cEBiSkoCX+g=" }, "execa": { "version": "0.7.0", @@ -3314,13 +3320,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "expand-brackets": { @@ -3329,13 +3335,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -3344,7 +3350,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -3353,7 +3359,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -3374,8 +3380,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -3384,7 +3390,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -3395,9 +3401,9 @@ "integrity": "sha1-BFURz9jRM/OEZnPRBHwVTiFK09U=", "dev": true, "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.18", - "tmp": "0.0.33" + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" }, "dependencies": { "os-tmpdir": { @@ -3412,7 +3418,7 @@ "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.2" } } } @@ -3423,14 +3429,14 @@ "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", "dev": true, "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -3439,7 +3445,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -3448,36 +3454,36 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -3509,7 +3515,7 @@ "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", "dev": true, "requires": { - "bser": "2.0.0" + "bser": "^2.0.0" } }, "fbjs": { @@ -3517,13 +3523,13 @@ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", "requires": { - "core-js": "1.2.7", - "isomorphic-fetch": "2.2.1", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "promise": "7.3.1", - "setimmediate": "1.0.5", - "ua-parser-js": "0.7.14" + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.9" }, "dependencies": { "core-js": { @@ -3541,8 +3547,8 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { - "node-fetch": "1.7.3", - "whatwg-fetch": "2.0.4" + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" } }, "loose-envify": { @@ -3550,7 +3556,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "3.0.2" + "js-tokens": "^3.0.0" } }, "node-fetch": { @@ -3558,8 +3564,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" + "encoding": "^0.1.11", + "is-stream": "^1.0.1" } }, "object-assign": { @@ -3586,7 +3592,7 @@ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5" + "escape-string-regexp": "^1.0.5" }, "dependencies": { "escape-string-regexp": { @@ -3603,8 +3609,8 @@ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" }, "dependencies": { "object-assign": { @@ -3621,10 +3627,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -3633,7 +3639,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -3644,7 +3650,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "2.0.0" + "locate-path": "^2.0.0" } }, "flat-cache": { @@ -3653,10 +3659,10 @@ "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "dev": true, "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" + "circular-json": "^0.3.1", + "del": "^2.0.2", + "graceful-fs": "^4.1.2", + "write": "^0.2.1" }, "dependencies": { "graceful-fs": { @@ -3689,9 +3695,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "0.4.0", + "asynckit": "^0.4.0", "combined-stream": "1.0.6", - "mime-types": "2.1.16" + "mime-types": "^2.1.12" } }, "fragment-cache": { @@ -3700,7 +3706,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "0.2.2" + "map-cache": "^0.2.2" } }, "fs-constants": { @@ -3711,11 +3717,11 @@ "fs-extra": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "integrity": "sha1-DYUhIuW8W+tFP7Ao6cDJvzY0DJQ=", "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "4.0.0", - "universalify": "0.1.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, "fs-minipass": { @@ -3723,7 +3729,7 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", "integrity": "sha1-BsJ3IYRU7CiN93raVKA7hwKqy50=", "requires": { - "minipass": "2.3.3" + "minipass": "^2.2.1" } }, "function.prototype.name": { @@ -3732,9 +3738,9 @@ "integrity": "sha1-i9djzAr4YKhZzF1JOE10uTLNIyc=", "dev": true, "requires": { - "define-properties": "1.1.2", - "function-bind": "1.1.1", - "is-callable": "1.1.3" + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "is-callable": "^1.1.3" }, "dependencies": { "function-bind": { @@ -3756,14 +3762,14 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" }, "dependencies": { "ansi-regex": { @@ -3781,9 +3787,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "strip-ansi": { @@ -3791,7 +3797,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } } } @@ -3825,7 +3831,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "github-from-package": { @@ -3838,12 +3844,12 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "dependencies": { "fs.realpath": { @@ -3856,8 +3862,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -3870,7 +3876,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "once": { @@ -3878,7 +3884,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "path-is-absolute": { @@ -3899,8 +3905,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { @@ -3909,7 +3915,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } } } @@ -3926,8 +3932,8 @@ "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", "dev": true, "requires": { - "min-document": "2.19.0", - "process": "0.5.2" + "min-document": "^2.19.0", + "process": "~0.5.1" } }, "globals": { @@ -3941,12 +3947,12 @@ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "dependencies": { "object-assign": { @@ -3973,7 +3979,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } } } @@ -3994,18 +4000,18 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.13.2.tgz", "integrity": "sha1-THQK48Iigj5wBAlvgy57k7IQgnA=", "requires": { - "iterall": "1.2.2" + "iterall": "^1.2.1" } }, "graphql-compiler": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/graphql-compiler/-/graphql-compiler-1.6.0.tgz", - "integrity": "sha512-9r6IHZYA9N+teTfiIC2X4WcHgRjzfSCtEI4Sxe80eMOckvWhT84d2rESQfMpJl+zelxyqFTs+HTHnApRRwy0/Q==", + "integrity": "sha1-JPFGzfiLgOBFMipXKhpdhLnCqdU=", "dev": true, "requires": { - "chalk": "1.1.3", - "fb-watchman": "2.0.0", - "immutable": "3.7.6" + "chalk": "^1.1.1", + "fb-watchman": "^2.0.0", + "immutable": "~3.7.6" } }, "har-schema": { @@ -4018,8 +4024,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^5.1.0", + "har-schema": "^2.0.0" } }, "has": { @@ -4028,7 +4034,7 @@ "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", "dev": true, "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.0.2" }, "dependencies": { "function-bind": { @@ -4045,7 +4051,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -4071,9 +4077,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" } }, "has-values": { @@ -4082,8 +4088,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "kind-of": { @@ -4092,7 +4098,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -4103,10 +4109,10 @@ "integrity": "sha1-r02RTrBl+bXOTZ0RwcshJu7MMDg=", "dev": true, "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.1", - "sntp": "2.1.0" + "boom": "4.x.x", + "cryptiles": "3.x.x", + "hoek": "4.x.x", + "sntp": "2.x.x" } }, "he": { @@ -4143,14 +4149,14 @@ "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" } }, "hosted-git-info": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", + "integrity": "sha1-IyNbKasjDFdqqw1PE/wEawsDgiI=", "dev": true }, "htmlparser2": { @@ -4159,12 +4165,12 @@ "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", "dev": true, "requires": { - "domelementtype": "1.3.0", - "domhandler": "2.4.1", - "domutils": "1.5.1", - "entities": "1.1.1", - "inherits": "2.0.3", - "readable-stream": "2.3.3" + "domelementtype": "^1.3.0", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" }, "dependencies": { "inherits": { @@ -4180,15 +4186,15 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.14.1" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "iconv-lite": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" + "integrity": "sha1-I9hlaxaq5nQqwpcy6o8DNqR4nPI=" }, "ignore": { "version": "3.3.8", @@ -4232,20 +4238,20 @@ "integrity": "sha1-ndLyrXZdyrH/BEO0kUQqILoifck=", "dev": true, "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.5", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" }, "dependencies": { "ansi-regex": { @@ -4260,7 +4266,7 @@ "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "chalk": { @@ -4269,9 +4275,9 @@ "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "escape-string-regexp": { @@ -4286,7 +4292,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } }, "supports-color": { @@ -4295,7 +4301,7 @@ "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "through": { @@ -4311,7 +4317,7 @@ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", "requires": { - "loose-envify": "1.3.1" + "loose-envify": "^1.0.0" }, "dependencies": { "loose-envify": { @@ -4319,7 +4325,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "3.0.2" + "js-tokens": "^3.0.0" } } } @@ -4336,7 +4342,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -4345,7 +4351,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -4374,7 +4380,7 @@ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { - "builtin-modules": "1.1.1" + "builtin-modules": "^1.0.0" } }, "is-callable": { @@ -4389,7 +4395,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -4398,7 +4404,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -4412,18 +4418,18 @@ "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", "dev": true } } @@ -4445,7 +4451,7 @@ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" }, "dependencies": { "number-is-nan": { @@ -4460,7 +4466,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" }, "dependencies": { "number-is-nan": { @@ -4476,7 +4482,7 @@ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } }, "is-number": { @@ -4485,7 +4491,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -4494,7 +4500,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -4517,7 +4523,7 @@ "integrity": "sha1-dkZiRnH9fqVYzNmieVGC8pWPGyQ=", "dev": true, "requires": { - "is-number": "4.0.0" + "is-number": "^4.0.0" }, "dependencies": { "is-number": { @@ -4540,7 +4546,7 @@ "integrity": "sha1-WsSLNF72dTOb1sekipEhELJBz1I=", "dev": true, "requires": { - "is-path-inside": "1.0.1" + "is-path-inside": "^1.0.0" } }, "is-path-inside": { @@ -4549,7 +4555,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-plain-object": { @@ -4558,7 +4564,7 @@ "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "is-promise": { @@ -4573,7 +4579,7 @@ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { - "has": "1.0.1" + "has": "^1.0.1" } }, "is-resolvable": { @@ -4640,6 +4646,188 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, + "istanbul-lib-coverage": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz", + "integrity": "sha512-yMSw5xLIbdaxiVXHk3amfNM2WeBxLrwH/BCyZ9HvA/fylwziAIJOG2rKqWyLqEJqwKT725vxxqidv+SyynnGAA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-2.2.0.tgz", + "integrity": "sha512-ozQGtlIw+/a/F3n6QwWiuuyRAPp64+g2GVsKYsIez0sgIEzkU5ZpL2uZ5pmAzbEJ82anlRaPlOQZzkRXspgJyg==", + "dev": true, + "requires": { + "@babel/generator": "7.0.0-beta.49", + "@babel/parser": "7.0.0-beta.49", + "@babel/template": "7.0.0-beta.49", + "@babel/traverse": "7.0.0-beta.49", + "@babel/types": "7.0.0-beta.49", + "istanbul-lib-coverage": "^2.0.0", + "semver": "^5.5.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.49.tgz", + "integrity": "sha1-vs2AVIJzREDJ0TfkbXc0DmTX9Rs=", + "dev": true, + "requires": { + "@babel/highlight": "7.0.0-beta.49" + } + }, + "@babel/generator": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.49.tgz", + "integrity": "sha1-6c/9qROZaszseTu8JauRvBnQv3o=", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.49", + "jsesc": "^2.5.1", + "lodash": "^4.17.5", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-function-name": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.49.tgz", + "integrity": "sha1-olwRGbnwNSeGcBJuAiXAMEHI3jI=", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "7.0.0-beta.49", + "@babel/template": "7.0.0-beta.49", + "@babel/types": "7.0.0-beta.49" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.49.tgz", + "integrity": "sha1-z1Aj8y0q2S0Ic3STnOwJUby1FEE=", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.49" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.49.tgz", + "integrity": "sha1-QNeO2glo0BGxxShm5XRs+yPldUg=", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.49" + } + }, + "@babel/highlight": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.49.tgz", + "integrity": "sha1-lr3GtD4TSCASumaRsQGEktOWIsw=", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "@babel/template": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.49.tgz", + "integrity": "sha1-44q+ghfLl5P0YaUwbXrXRdg+HSc=", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.49", + "@babel/parser": "7.0.0-beta.49", + "@babel/types": "7.0.0-beta.49", + "lodash": "^4.17.5" + } + }, + "@babel/traverse": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.49.tgz", + "integrity": "sha1-TypzaCoYM07WYl0QCo0nMZ98LWg=", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.49", + "@babel/generator": "7.0.0-beta.49", + "@babel/helper-function-name": "7.0.0-beta.49", + "@babel/helper-split-export-declaration": "7.0.0-beta.49", + "@babel/parser": "7.0.0-beta.49", + "@babel/types": "7.0.0-beta.49", + "debug": "^3.1.0", + "globals": "^11.1.0", + "invariant": "^2.2.0", + "lodash": "^4.17.5" + } + }, + "@babel/types": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.49.tgz", + "integrity": "sha1-t+Oxw/TUz+Eb34yJ8e/V4WF7h6Y=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.5", + "to-fast-properties": "^2.0.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "dev": true + }, + "jsesc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", + "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", + "dev": true + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "iterall": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", @@ -4680,8 +4868,8 @@ "integrity": "sha1-WXwai9VxUvJtYizkEXhRpR9euu8=", "dev": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "jsbn": { @@ -4732,7 +4920,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "requires": { - "graceful-fs": "4.1.11" + "graceful-fs": "^4.1.6" } }, "jsprim": { @@ -4756,7 +4944,7 @@ "just-extend": { "version": "1.1.27", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", + "integrity": "sha1-7G55QQ/5FORyZSq/oOYDwD1g6QU=", "dev": true }, "keytar": { @@ -4765,7 +4953,7 @@ "integrity": "sha1-igamV3/fY3PgqmsRInfmPex3/RI=", "requires": { "nan": "2.8.0", - "prebuild-install": "2.5.3" + "prebuild-install": "^2.4.1" } }, "kind-of": { @@ -4780,7 +4968,7 @@ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "invert-kv": "1.0.0" + "invert-kv": "^1.0.0" } }, "less": { @@ -4789,14 +4977,14 @@ "integrity": "sha1-zBJg9RyQCp7A2R+2mYE54CUHtjs=", "dev": true, "requires": { - "errno": "0.1.4", - "graceful-fs": "4.1.11", - "image-size": "0.5.5", - "mime": "1.4.1", - "mkdirp": "0.5.1", - "promise": "7.3.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.2.11", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", "request": "2.81.0", - "source-map": "0.5.7" + "source-map": "^0.5.3" }, "dependencies": { "ajv": { @@ -4806,8 +4994,8 @@ "dev": true, "optional": true, "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" } }, "assert-plus": { @@ -4837,14 +5025,14 @@ "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, "requires": { - "hoek": "2.16.3" + "hoek": "2.x.x" } }, "combined-stream": { "version": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha512-JgSRe4l4UzPwpJuxfcPWEK1SCrL4dxNjp1uqrQLMop3QZUVo+hDU8w9BJKA4JPbulTWI+UzrI2UA3tK12yQ6bg==", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "cryptiles": { @@ -4854,7 +5042,7 @@ "dev": true, "optional": true, "requires": { - "boom": "2.10.1" + "boom": "2.x.x" } }, "extend": { @@ -4878,9 +5066,9 @@ "dev": true, "optional": true, "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.6", - "mime-types": "2.1.16" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" }, "dependencies": { "combined-stream": { @@ -4890,7 +5078,7 @@ "dev": true, "optional": true, "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } } } @@ -4916,8 +5104,8 @@ "dev": true, "optional": true, "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" + "ajv": "^4.9.1", + "har-schema": "^1.0.5" } }, "hawk": { @@ -4927,10 +5115,10 @@ "dev": true, "optional": true, "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" } }, "hoek": { @@ -4946,9 +5134,9 @@ "dev": true, "optional": true, "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.1", - "sshpk": "1.14.1" + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "is-typedarray": { @@ -4972,7 +5160,7 @@ "dev": true, "optional": true, "requires": { - "jsonify": "0.0.0" + "jsonify": "~0.0.0" } }, "json-stringify-safe": { @@ -5024,28 +5212,28 @@ "dev": true, "optional": true, "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.7.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.16", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.1", - "stringstream": "0.0.6", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" }, "dependencies": { "combined-stream": { @@ -5055,7 +5243,7 @@ "dev": true, "optional": true, "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "tough-cookie": { @@ -5065,7 +5253,7 @@ "dev": true, "optional": true, "requires": { - "punycode": "1.4.1" + "punycode": "^1.4.1" } } } @@ -5077,7 +5265,7 @@ "dev": true, "optional": true, "requires": { - "hoek": "2.16.3" + "hoek": "2.x.x" } }, "source-map": { @@ -5091,7 +5279,7 @@ "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", "integrity": "sha512-42UXjmzk88F7URyg9wDV/dlQ7hXtl/SDV6xIMVdDq82cnDGQDyg8mI8xGBPOwpEfbhvrja6cJ8H1wr0xxykBKA==", "requires": { - "punycode": "1.4.1" + "punycode": "^1.4.1" } } } @@ -5102,8 +5290,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "load-json-file": { @@ -5112,10 +5300,10 @@ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" } }, "locate-path": { @@ -5124,8 +5312,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" } }, "lodash": { @@ -5139,8 +5327,8 @@ "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", "dev": true, "requires": { - "lodash._basecopy": "3.0.1", - "lodash.keys": "3.1.2" + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" } }, "lodash._basecopy": { @@ -5173,9 +5361,9 @@ "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", "dev": true, "requires": { - "lodash._baseassign": "3.2.0", - "lodash._basecreate": "3.0.3", - "lodash._isiterateecall": "3.0.9" + "lodash._baseassign": "^3.0.0", + "lodash._basecreate": "^3.0.0", + "lodash._isiterateecall": "^3.0.0" } }, "lodash.flattendeep": { @@ -5214,9 +5402,9 @@ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" } }, "lodash.memoize": { @@ -5232,7 +5420,7 @@ "lolex": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.0.tgz", - "integrity": "sha512-uJkH2e0BVfU5KOJUevbTOtpDduooSarH5PopO+LfM/vZf8Z9sJzODqKev804JYM2i++ktJfUmC1le4LwFQ1VMg==", + "integrity": "sha1-nAh6aexEDjnT95Z2fPGyzcQ9XqU=", "dev": true }, "loose-envify": { @@ -5240,7 +5428,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "3.0.2" + "js-tokens": "^3.0.0" } }, "lru-cache": { @@ -5261,7 +5449,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "mem": { @@ -5270,7 +5458,7 @@ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "merge2": { @@ -5282,22 +5470,22 @@ "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.9", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } }, "mime-db": { @@ -5310,7 +5498,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=", "requires": { - "mime-db": "1.29.0" + "mime-db": "~1.29.0" } }, "mimic-fn": { @@ -5330,7 +5518,7 @@ "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", "dev": true, "requires": { - "dom-walk": "0.1.1" + "dom-walk": "^0.1.0" } }, "minimatch": { @@ -5338,7 +5526,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -5349,10 +5537,10 @@ "minipass": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz", - "integrity": "sha512-/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw==", + "integrity": "sha1-p9zIt7gz9dNodZzOVE3MtV9Q8jM=", "requires": { - "safe-buffer": "5.1.2", - "yallist": "3.0.2" + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" }, "dependencies": { "safe-buffer": { @@ -5367,7 +5555,7 @@ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz", "integrity": "sha1-EeE2WM5GvDpwomeqxYNZ0eDCnOs=", "requires": { - "minipass": "2.3.3" + "minipass": "^2.2.1" } }, "mixin-deep": { @@ -5376,8 +5564,8 @@ "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", "dev": true, "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -5386,7 +5574,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -5412,7 +5600,7 @@ "integrity": "sha1-gpOC/8Bla2Z+e+ZQoJSgba69Uk8=", "dev": true, "requires": { - "request-json": "0.6.3" + "request-json": "^0.6.1" }, "dependencies": { "depd": { @@ -5463,7 +5651,7 @@ "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "dev": true, "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.33.0" } }, "oauth-sign": { @@ -5478,28 +5666,28 @@ "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", "dev": true, "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.7.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.18", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "hawk": "~6.0.2", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "stringstream": "~0.0.5", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" } }, "request-json": { @@ -5514,8 +5702,7 @@ }, "stringstream": { "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "resolved": "", "dev": true } } @@ -5526,10 +5713,10 @@ "integrity": "sha1-kBmEuev51g9xXvDo4EwG5KsSJFc=", "dev": true, "requires": { - "debug": "2.6.9", - "mkdirp": "0.5.1", - "mocha": "2.5.3", - "xml": "1.0.1" + "debug": "^2.2.0", + "mkdirp": "~0.5.1", + "mocha": "^2.2.5", + "xml": "^1.0.0" }, "dependencies": { "commander": { @@ -5565,8 +5752,8 @@ "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", "dev": true, "requires": { - "inherits": "2.0.3", - "minimatch": "0.3.0" + "inherits": "2", + "minimatch": "0.3" } }, "growl": { @@ -5587,8 +5774,8 @@ "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", "dev": true, "requires": { - "lru-cache": "2.7.3", - "sigmund": "1.0.1" + "lru-cache": "2", + "sigmund": "~1.0.0" } }, "mocha": { @@ -5667,18 +5854,18 @@ "integrity": "sha1-h59xUMstq3pHElkGbBBO7m4Pp8I=", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "fragment-cache": "0.2.1", - "is-odd": "2.0.0", - "is-windows": "1.0.2", - "kind-of": "6.0.2", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-odd": "^2.0.0", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -5687,8 +5874,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" } }, "is-extendable": { @@ -5697,7 +5884,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -5714,10 +5901,10 @@ "integrity": "sha1-bnsPTmi/w+dMmervLto55RMUNDk=", "dev": true, "requires": { - "nomnom": "1.6.2", - "railroad-diagrams": "1.0.0", + "nomnom": "~1.6.2", + "railroad-diagrams": "^1.0.0", "randexp": "0.4.6", - "semver": "5.4.1" + "semver": "^5.4.1" } }, "next-tick": { @@ -5729,14 +5916,14 @@ "nise": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.1.tgz", - "integrity": "sha512-9JX3YwoIt3kS237scmSSOpEv7vCukVzLfwK0I0XhocDSHUANid8ZHnLEULbbSkfeMn98B2y5kphIWzZUylESRQ==", + "integrity": "sha1-eLwrND1f8QMeqdG7LIepTCbbclA=", "dev": true, "requires": { - "@sinonjs/formatio": "2.0.0", - "just-extend": "1.1.27", - "lolex": "2.7.0", - "path-to-regexp": "1.7.0", - "text-encoding": "0.6.4" + "@sinonjs/formatio": "^2.0.0", + "just-extend": "^1.1.27", + "lolex": "^2.3.2", + "path-to-regexp": "^1.7.0", + "text-encoding": "^0.6.4" } }, "node-abi": { @@ -5744,15 +5931,15 @@ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.0.tgz", "integrity": "sha1-PCdRXLhC9bvBMqMSVPnx4cVce4M=", "requires": { - "semver": "5.4.1" + "semver": "^5.4.1" } }, "node-emoji": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz", - "integrity": "sha512-+ktMAh1Jwas+TnGodfCfjUbJKoANqPaJFN0z0iqh41eqD8dvguNzcitVSBSVK1pidz0AqGbLKcoVuVLRVZ/aVg==", + "integrity": "sha1-buxr+wdCHiFIx1xrunJCH4UwqCY=", "requires": { - "lodash.toarray": "4.4.0" + "lodash.toarray": "^4.4.0" } }, "node-fetch": { @@ -5773,8 +5960,8 @@ "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", "dev": true, "requires": { - "colors": "0.5.1", - "underscore": "1.4.4" + "colors": "0.5.x", + "underscore": "~1.4.4" } }, "noop-logger": { @@ -5788,10 +5975,10 @@ "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", "dev": true, "requires": { - "hosted-git-info": "2.6.0", - "is-builtin-module": "1.0.0", - "semver": "5.4.1", - "validate-npm-package-license": "3.0.3" + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "npm-run-path": { @@ -5800,7 +5987,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "npmlog": { @@ -5808,10 +5995,10 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "nth-check": { @@ -5820,181 +6007,2234 @@ "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", "dev": true, "requires": { - "boolbase": "1.0.0" - } - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "boolbase": "~1.0.0" + } + }, + "nyc": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-12.0.2.tgz", + "integrity": "sha1-ikpO1pCWbBHsWH/4fuoMEsl0upk=", + "dev": true, + "requires": { + "archy": "^1.0.0", + "arrify": "^1.0.1", + "caching-transform": "^1.0.0", + "convert-source-map": "^1.5.1", + "debug-log": "^1.0.1", + "default-require-extensions": "^1.0.0", + "find-cache-dir": "^0.1.1", + "find-up": "^2.1.0", + "foreground-child": "^1.5.3", + "glob": "^7.0.6", + "istanbul-lib-coverage": "^1.2.0", + "istanbul-lib-hook": "^1.1.0", + "istanbul-lib-instrument": "^2.1.0", + "istanbul-lib-report": "^1.1.3", + "istanbul-lib-source-maps": "^1.2.5", + "istanbul-reports": "^1.4.1", + "md5-hex": "^1.2.0", + "merge-source-map": "^1.1.0", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.0", + "resolve-from": "^2.0.0", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.1", + "spawn-wrap": "^1.4.2", + "test-exclude": "^4.2.0", + "yargs": "11.1.0", + "yargs-parser": "^8.0.0" }, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "align-text": { + "version": "0.1.4", + "bundled": true, "dev": true, "requires": { - "is-descriptor": "0.1.6" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" } }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "amdefine": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "append-transform": { + "version": "0.4.0", + "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.6" + "default-require-extensions": "^1.0.0" } - } - } - }, - "object-inspect": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.5.0.tgz", - "integrity": "sha1-nYdsEeQPSFx5IVZwKBt2dIj5v+M=", - "dev": true - }, - "object-is": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", - "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", - "dev": true - }, - "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "3.0.1" - } - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", - "dev": true, - "requires": { - "define-properties": "1.1.2", - "function-bind": "1.1.1", - "has-symbols": "1.0.0", - "object-keys": "1.0.11" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + }, + "archy": { + "version": "1.0.0", + "bundled": true, "dev": true - } - } - }, - "object.entries": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", - "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", - "dev": true, - "requires": { - "define-properties": "1.1.2", - "es-abstract": "1.11.0", - "function-bind": "1.1.1", - "has": "1.0.1" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + }, + "arr-diff": { + "version": "4.0.0", + "bundled": true, "dev": true - } - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "3.0.1" - } - }, - "object.values": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", - "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", - "dev": true, - "requires": { - "define-properties": "1.1.2", - "es-abstract": "1.11.0", - "function-bind": "1.1.1", - "has": "1.0.1" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + }, + "arr-flatten": { + "version": "1.1.0", + "bundled": true, "dev": true - } - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "1.2.0" - } - }, - "optimist": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", - "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", - "requires": { - "wordwrap": "0.0.3" - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - }, - "dependencies": { - "wordwrap": { + }, + "arr-union": { + "version": "3.1.0", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "assign-symbols": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "bundled": true, + "dev": true + }, + "async": { + "version": "1.5.2", + "bundled": true, + "dev": true + }, + "atob": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "base": { + "version": "0.11.2", + "bundled": true, + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "caching-transform": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "md5-hex": "^1.2.0", + "mkdirp": "^0.5.1", + "write-file-atomic": "^1.1.4" + } + }, + "camelcase": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true + }, + "center-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "class-utils": { + "version": "0.3.6", + "bundled": true, + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cliui": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "commondir": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "convert-source-map": { + "version": "1.5.1", + "bundled": true, + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "cross-spawn": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "debug-log": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "default-require-extensions": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "strip-bom": "^2.0.0" + } + }, + "define-property": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "error-ex": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "execa": { + "version": "0.7.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "fill-range": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "requires": { + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "for-in": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "foreground-child": { + "version": "1.5.6", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^4", + "signal-exit": "^3.0.0" + } + }, + "fragment-cache": { + "version": "0.2.1", + "bundled": true, + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "get-caller-file": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "get-value": { + "version": "2.0.6", + "bundled": true, + "dev": true + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "handlebars": { + "version": "4.0.11", + "bundled": true, + "dev": true, + "requires": { + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "bundled": true, + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "has-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hosted-git-info": { + "version": "2.6.0", + "bundled": true, + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "bundled": true, + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-odd": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "bundled": true, + "dev": true + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "istanbul-lib-coverage": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "append-transform": "^0.4.0" + } + }, + "istanbul-lib-report": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "requires": { + "istanbul-lib-coverage": "^1.1.2", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" + }, + "dependencies": { + "has-flag": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "requires": { + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.2.0", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" + } + }, + "istanbul-reports": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "handlebars": "^4.0.3" + } + }, + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "lazy-cache": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "optional": true + }, + "lcid": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + }, + "longest": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "lru-cache": { + "version": "4.1.3", + "bundled": true, + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "map-cache": { + "version": "0.2.2", + "bundled": true, + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5-hex": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "md5-o-matic": "^0.1.1" + } + }, + "md5-o-matic": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "mem": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "merge-source-map": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "bundled": true, + "dev": true + } + } + }, + "micromatch": { + "version": "3.1.10", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "nanomatch": { + "version": "1.2.9", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-odd": "^2.0.0", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optimist": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "pascalcase": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "path-type": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "bundled": true, + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "find-up": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + } + } + }, + "regex-not": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "repeat-element": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "bundled": true, + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "resolve-from": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "ret": { + "version": "0.1.15", + "bundled": true, + "dev": true + }, + "right-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-regex": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "semver": { + "version": "5.5.0", + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "set-value": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "slide": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.2.0" + } + }, + "source-map": { + "version": "0.5.7", + "bundled": true, + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "bundled": true, + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "bundled": true, + "dev": true + }, + "spawn-wrap": { + "version": "1.4.2", + "bundled": true, + "dev": true, + "requires": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "split-string": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "static-extend": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "test-exclude": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "requires": { + "arrify": "^1.0.1", + "micromatch": "^3.1.8", + "object-assign": "^4.1.0", + "read-pkg-up": "^1.0.1", + "require-main-filename": "^1.0.1" + } + }, + "to-object-path": { + "version": "0.3.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "uglify-js": { + "version": "2.8.29", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "union-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "unset-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "bundled": true, + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "bundled": true, + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "bundled": true, + "dev": true + }, + "use": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "window-size": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "0.0.3", + "bundled": true, + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + }, + "y18n": { + "version": "3.2.1", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "11.1.0", + "bundled": true, + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "cliui": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "yargs-parser": { + "version": "9.0.2", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "8.1.0", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "^4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + } + } + } + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.5.0.tgz", + "integrity": "sha1-nYdsEeQPSFx5IVZwKBt2dIj5v+M=", + "dev": true + }, + "object-is": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", + "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", + "dev": true + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "dependencies": { + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "dev": true + } + } + }, + "object.entries": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", + "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.6.1", + "function-bind": "^1.1.0", + "has": "^1.0.1" + }, + "dependencies": { + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + } + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", + "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.6.1", + "function-bind": "^1.1.0", + "has": "^1.0.1" + }, + "dependencies": { + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + } + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", + "requires": { + "wordwrap": "~0.0.2" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true } } @@ -6010,9 +8250,9 @@ "integrity": "sha1-QrwpAKa1uL0XN2yOiCtlr8zyS/I=", "dev": true, "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, "os-tmpdir": { @@ -6032,7 +8272,7 @@ "integrity": "sha1-DpK2vty1nwIsE9DxlJ3ILRWQnxw=", "dev": true, "requires": { - "p-try": "1.0.0" + "p-try": "^1.0.0" } }, "p-locate": { @@ -6041,7 +8281,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "1.2.0" + "p-limit": "^1.1.0" } }, "p-try": { @@ -6056,7 +8296,7 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "1.3.1" + "error-ex": "^1.2.0" } }, "parse5": { @@ -6065,7 +8305,7 @@ "integrity": "sha1-BC95L/3TaFFVHPTp4Gazh0q0W1w=", "dev": true, "requires": { - "@types/node": "9.6.4" + "@types/node": "*" } }, "pascalcase": { @@ -6118,7 +8358,7 @@ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { - "pify": "2.3.0" + "pify": "^2.0.0" } }, "pathval": { @@ -6155,21 +8395,21 @@ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.5.3.tgz", "integrity": "sha1-n2XyQngtNwKWNTcQ6byENJDBn2k=", "requires": { - "detect-libc": "1.0.3", - "expand-template": "1.1.0", + "detect-libc": "^1.0.3", + "expand-template": "^1.0.2", "github-from-package": "0.0.0", - "minimist": "1.2.0", - "mkdirp": "0.5.1", - "node-abi": "2.4.0", - "noop-logger": "0.1.1", - "npmlog": "4.1.2", - "os-homedir": "1.0.2", - "pump": "2.0.1", - "rc": "1.2.7", - "simple-get": "2.8.1", - "tar-fs": "1.16.2", - "tunnel-agent": "0.6.0", - "which-pm-runs": "1.0.0" + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "node-abi": "^2.2.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "os-homedir": "^1.0.1", + "pump": "^2.0.1", + "rc": "^1.1.6", + "simple-get": "^2.7.0", + "tar-fs": "^1.13.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" }, "dependencies": { "os-homedir": { @@ -6206,79 +8446,16 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", "requires": { - "asap": "2.0.6" + "asap": "~2.0.3" } }, "prop-types": { - "version": "15.6.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", - "integrity": "sha1-NmREU1ZCVd3aORGR+zoSXL32VMo=", + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", + "integrity": "sha1-BdXKd7RFPphdYPx/+MhZCUpJcQI=", "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" - }, - "fbjs": { - "version": "0.8.16", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", - "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", - "requires": { - "core-js": "1.2.7", - "isomorphic-fetch": "2.2.1", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "promise": "7.3.1", - "setimmediate": "1.0.5", - "ua-parser-js": "0.7.14" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "requires": { - "node-fetch": "1.7.3", - "whatwg-fetch": "2.0.4" - } - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "3.0.2" - } - }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - } + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" } }, "prr": { @@ -6299,8 +8476,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" }, "dependencies": { "once": { @@ -6308,7 +8485,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "wrappy": { @@ -6334,7 +8511,7 @@ "integrity": "sha1-ooh2iBtLwsqRF9QTgWPduA94FXU=", "dev": true, "requires": { - "performance-now": "2.1.0" + "performance-now": "^2.1.0" } }, "railroad-diagrams": { @@ -6350,7 +8527,7 @@ "dev": true, "requires": { "discontinuous-range": "1.0.0", - "ret": "0.1.15" + "ret": "~0.1.10" } }, "rc": { @@ -6358,32 +8535,32 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz", "integrity": "sha1-ihDKMNWI0ARkNgNyuJDQbazQIpc=", "requires": { - "deep-extend": "0.5.1", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" } }, "react": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/react/-/react-16.4.1.tgz", - "integrity": "sha512-3GEs0giKp6E0Oh/Y9ZC60CmYgUPnp7voH9fbjWsvXtYFb4EWtgQub0ADSq0sJR0BbHc4FThLLtzlcFaFXIorwg==", + "integrity": "sha1-3lG6V2S1280fkHkDe4Yr0muC/jI=", "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "prop-types": "15.6.1" + "fbjs": "^0.8.16", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.0" } }, "react-dom": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.1.tgz", - "integrity": "sha512-1Gin+wghF/7gl4Cqcvr1DxFX2Osz7ugxSwl6gBqCMpdrxHjIFUS7GYxrFftZ9Ln44FHw0JxCFD9YtZsrbR5/4A==", + "integrity": "sha1-f4sCI7Ol++IFEWxW3rhd4yaF2tY=", "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "prop-types": "15.6.1" + "fbjs": "^0.8.16", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.0" } }, "react-input-autosize": { @@ -6391,7 +8568,7 @@ "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.1.tgz", "integrity": "sha1-7EKPoVsVkplPtfmqFbsetrr0IPg=", "requires": { - "prop-types": "15.6.1" + "prop-types": "^15.5.8" }, "dependencies": { "core-js": { @@ -6404,13 +8581,13 @@ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", "requires": { - "core-js": "1.2.7", - "isomorphic-fetch": "2.2.1", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "promise": "7.3.1", - "setimmediate": "1.0.5", - "ua-parser-js": "0.7.14" + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.9" } }, "is-stream": { @@ -6423,8 +8600,8 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { - "node-fetch": "1.7.3", - "whatwg-fetch": "2.0.4" + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" } }, "loose-envify": { @@ -6432,7 +8609,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "3.0.2" + "js-tokens": "^3.0.0" } }, "node-fetch": { @@ -6440,8 +8617,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" + "encoding": "^0.1.11", + "is-stream": "^1.0.1" } }, "object-assign": { @@ -6454,9 +8631,9 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1" + "fbjs": "^0.8.16", + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" } }, "setimmediate": { @@ -6475,23 +8652,23 @@ "react-reconciler": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.7.0.tgz", - "integrity": "sha512-50JwZ3yNyMS8fchN+jjWEJOH3Oze7UmhxeoJLn2j6f3NjpfCRbcmih83XTWmzqtar/ivd5f7tvQhvvhism2fgg==", + "integrity": "sha1-lhSJQQPl8Tje7rXquvPugOsdAm0=", "dev": true, "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "prop-types": "15.6.1" + "fbjs": "^0.8.16", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.0" } }, "react-relay": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/react-relay/-/react-relay-1.6.0.tgz", - "integrity": "sha512-8clmRHXNo96pcdkA8ZeiqF7xGjE+mjSbdX/INj5upRm2M8AprSrFk2Oz5nH084O+0hvXQhZtFyraXJWQO9ld3A==", + "integrity": "sha1-eg7KQ1yBubAdiRfUvKZQfu+83+Q=", "requires": { - "babel-runtime": "6.25.0", - "fbjs": "0.8.16", - "prop-types": "15.6.1", + "babel-runtime": "^6.23.0", + "fbjs": "^0.8.14", + "prop-types": "^15.5.8", "relay-runtime": "1.6.0" } }, @@ -6500,9 +8677,9 @@ "resolved": "https://registry.npmjs.org/react-select/-/react-select-1.2.1.tgz", "integrity": "sha1-ov5YpWnrFNyqZUOBYmC5flOBINE=", "requires": { - "classnames": "2.2.6", - "prop-types": "15.6.1", - "react-input-autosize": "2.2.1" + "classnames": "^2.2.4", + "prop-types": "^15.5.8", + "react-input-autosize": "^2.1.2" }, "dependencies": { "core-js": { @@ -6515,13 +8692,13 @@ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", "requires": { - "core-js": "1.2.7", - "isomorphic-fetch": "2.2.1", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "promise": "7.3.1", - "setimmediate": "1.0.5", - "ua-parser-js": "0.7.14" + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.9" } }, "is-stream": { @@ -6534,8 +8711,8 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { - "node-fetch": "1.7.3", - "whatwg-fetch": "2.0.4" + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" } }, "loose-envify": { @@ -6543,7 +8720,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "3.0.2" + "js-tokens": "^3.0.0" } }, "node-fetch": { @@ -6551,8 +8728,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" + "encoding": "^0.1.11", + "is-stream": "^1.0.1" } }, "object-assign": { @@ -6565,9 +8742,9 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1" + "fbjs": "^0.8.16", + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" } }, "setimmediate": { @@ -6583,10 +8760,23 @@ "integrity": "sha512-wyyiPxRZOTpKnNIgUBOB6xPLTpIzwcQMIURhZvzUqZzezvHjaGNsDPBhMac5fIY3Jf5NuKxoGvV64zDSOECPPQ==", "dev": true, "requires": { - "fbjs": "0.8.16", - "object-assign": "4.1.1", - "prop-types": "15.6.1", - "react-is": "16.4.1" + "fbjs": "^0.8.16", + "object-assign": "^4.1.1", + "prop-types": "^15.6.0", + "react-is": "^16.4.1" + }, + "dependencies": { + "prop-types": { + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", + "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", + "dev": true, + "requires": { + "fbjs": "^0.8.16", + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + } } }, "read-pkg": { @@ -6595,9 +8785,9 @@ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" } }, "read-pkg-up": { @@ -6606,22 +8796,22 @@ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" } }, "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" }, "dependencies": { "core-util-is": { @@ -6654,7 +8844,7 @@ "regenerator-runtime": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w==" + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" }, "regex-not": { "version": "1.0.2", @@ -6662,8 +8852,8 @@ "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", "dev": true, "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" }, "dependencies": { "extend-shallow": { @@ -6672,8 +8862,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" } }, "is-extendable": { @@ -6682,7 +8872,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -6696,49 +8886,49 @@ "relay-compiler": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/relay-compiler/-/relay-compiler-1.6.0.tgz", - "integrity": "sha512-qm9Xp/5tcpMli0z4WFYeb4E16ynxTKtmaAPT077vDpAzalBB2f71JEkQJUdrvVzcdr5m53LuXhXBODkUNkLQkg==", + "integrity": "sha1-ChvI0owc8x2JhRCKdhumwNtI1KE=", "dev": true, "requires": { "@babel/generator": "7.0.0-beta.40", "@babel/types": "7.0.0-beta.40", - "babel-polyfill": "6.26.0", - "babel-preset-fbjs": "2.1.4", - "babel-runtime": "6.25.0", - "babel-traverse": "6.26.0", + "babel-polyfill": "^6.20.0", + "babel-preset-fbjs": "^2.1.4", + "babel-runtime": "^6.23.0", + "babel-traverse": "^6.26.0", "babylon": "7.0.0-beta.40", - "chalk": "1.1.3", - "fast-glob": "2.2.1", - "fb-watchman": "2.0.0", - "fbjs": "0.8.16", + "chalk": "^1.1.1", + "fast-glob": "^2.0.0", + "fb-watchman": "^2.0.0", + "fbjs": "^0.8.14", "graphql-compiler": "1.6.0", - "immutable": "3.7.6", + "immutable": "~3.7.6", "relay-runtime": "1.6.0", - "signedsource": "1.0.0", - "yargs": "9.0.1" + "signedsource": "^1.0.0", + "yargs": "^9.0.0" }, "dependencies": { "@babel/generator": { "version": "7.0.0-beta.40", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.40.tgz", - "integrity": "sha512-c91BQcXyTq/5aFV4afgOionxZS1dxWt8OghEx5Q52SKssdGRFSiMKnk9tGkev1pYULPJBqjSDZU2Pcuc58ffZw==", + "integrity": "sha1-q2H5VW9PcdvRE4lJx5W7miHjAuo=", "dev": true, "requires": { "@babel/types": "7.0.0-beta.40", - "jsesc": "2.5.1", - "lodash": "4.17.5", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "jsesc": "^2.5.1", + "lodash": "^4.2.0", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" } }, "@babel/types": { "version": "7.0.0-beta.40", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.40.tgz", - "integrity": "sha512-uXCGCzTgMZxcSUzutCPtZmXbVC+cvENgS2e0tRuhn+Y1hZnMb8IHP0Trq7Q2MB/eFmG5pKrAeTIUfQIe5kA4Tg==", + "integrity": "sha1-JcPXquFBJqvgX8sJjGWma21rjBQ=", "dev": true, "requires": { - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" } }, "babel-traverse": { @@ -6747,15 +8937,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" }, "dependencies": { "babel-runtime": { @@ -6764,14 +8954,14 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=", "dev": true } } @@ -6782,10 +8972,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" }, "dependencies": { "babel-runtime": { @@ -6794,8 +8984,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "to-fast-properties": { @@ -6809,7 +8999,7 @@ "babylon": { "version": "7.0.0-beta.40", "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.40.tgz", - "integrity": "sha512-AVxF2EcxvGD5hhOuLTOLAXBb0VhwWpEX0HyHdAI2zU+AAP4qEwtQj8voz1JR3uclGai0rfcE+dCTHnNMOnimFg==", + "integrity": "sha1-kfyM1W1euYso5v3kEEXylXd5lAo=", "dev": true }, "fast-glob": { @@ -6818,11 +9008,11 @@ "integrity": "sha512-wSyW1TBK3ia5V+te0rGPXudeMHoUQW6O5Y9oATiaGhpENmEifPDlOdhpsnlj5HoG6ttIvGiY1DdCmI9X2xGMhg==", "dev": true, "requires": { - "@mrmlnc/readdir-enhanced": "2.2.1", - "glob-parent": "3.1.0", - "is-glob": "4.0.0", - "merge2": "1.2.1", - "micromatch": "3.1.10" + "@mrmlnc/readdir-enhanced": "^2.2.1", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.1", + "micromatch": "^3.1.10" } }, "jsesc": { @@ -6834,7 +9024,7 @@ "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", "dev": true } } @@ -6842,10 +9032,10 @@ "relay-runtime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/relay-runtime/-/relay-runtime-1.6.0.tgz", - "integrity": "sha512-UJiEHp8CX2uFxXdM0nVLTCQ6yAT0GLmyMceXLISuW/l2a9jrS9a4MdZgdr/9UkkYno7Sj1hU/EUIQ0GaVkou8g==", + "integrity": "sha1-K3AFj7d6TJOhcXUs4Uf47o2KiLk=", "requires": { - "babel-runtime": "6.25.0", - "fbjs": "0.8.16" + "babel-runtime": "^6.23.0", + "fbjs": "^0.8.14" } }, "repeat-element": { @@ -6865,47 +9055,47 @@ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "requires": { - "is-finite": "1.0.2" + "is-finite": "^1.0.0" } }, "request": { "version": "2.87.0", "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", - "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", - "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.7.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.0.3", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.18", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" + "integrity": "sha1-MvACNc0I1IK00NaNuTqCnA7VdW4=", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" }, "dependencies": { "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha1-o0kgUKXLm2NFBUHjnZeI0icng9s=" + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" }, "mime-types": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha1-bzI/YKg9ERRvgx/xH9ZuL+VQO7g=", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.33.0" } } } @@ -6928,8 +9118,8 @@ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" } }, "resolve-from": { @@ -6950,8 +9140,8 @@ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" } }, "ret": { @@ -6963,9 +9153,9 @@ "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "rst-selector-parser": { @@ -6974,8 +9164,8 @@ "integrity": "sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=", "dev": true, "requires": { - "lodash.flattendeep": "4.4.0", - "nearley": "2.13.0" + "lodash.flattendeep": "^4.4.0", + "nearley": "^2.7.10" } }, "run-async": { @@ -6984,7 +9174,7 @@ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true, "requires": { - "is-promise": "2.1.0" + "is-promise": "^2.1.0" } }, "rx-lite": { @@ -6999,7 +9189,7 @@ "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", "dev": true, "requires": { - "rx-lite": "4.0.8" + "rx-lite": "*" } }, "safe-buffer": { @@ -7013,19 +9203,19 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "0.1.15" + "ret": "~0.1.10" } }, "samsam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", + "integrity": "sha1-jR2TUOJWItow3j5EumkrUiGrfFA=", "dev": true }, "semver": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" + "integrity": "sha1-4FnAnYVx8FQII3M0M1BdOi8AsY4=" }, "set-blocking": { "version": "2.0.0", @@ -7038,10 +9228,10 @@ "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -7050,7 +9240,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -7061,7 +9251,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -7097,9 +9287,9 @@ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", "integrity": "sha1-DiLpHUV12HYgYgvJEwjVenf0S10=", "requires": { - "decompress-response": "3.3.0", - "once": "1.4.0", - "simple-concat": "1.0.0" + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" }, "dependencies": { "once": { @@ -7107,7 +9297,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "wrappy": { @@ -7120,16 +9310,16 @@ "sinon": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.0.0.tgz", - "integrity": "sha512-MatciKXyM5pXMSoqd593MqTsItJNCkSSl53HJYeKR5wfsDdp2yljjUQJLfVwAWLoBNfx1HThteqygGQ0ZEpXpQ==", + "integrity": "sha1-8mYn5IMNw0J5ZhR02iyeeE8WYhU=", "dev": true, "requires": { - "@sinonjs/formatio": "2.0.0", - "diff": "3.5.0", - "lodash.get": "4.4.2", - "lolex": "2.7.0", - "nise": "1.4.1", - "supports-color": "5.4.0", - "type-detect": "4.0.8" + "@sinonjs/formatio": "^2.0.0", + "diff": "^3.5.0", + "lodash.get": "^4.4.2", + "lolex": "^2.4.2", + "nise": "^1.3.3", + "supports-color": "^5.4.0", + "type-detect": "^4.0.8" }, "dependencies": { "supports-color": { @@ -7138,7 +9328,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -7154,7 +9344,7 @@ "integrity": "sha1-BE8aSdiEL/MHqta1Be0Xi9lQE00=", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0" + "is-fullwidth-code-point": "^2.0.0" }, "dependencies": { "is-fullwidth-code-point": { @@ -7168,17 +9358,17 @@ "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", "dev": true, "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.1", - "use": "3.1.0" + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" }, "dependencies": { "define-property": { @@ -7187,7 +9377,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -7196,7 +9386,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -7207,9 +9397,9 @@ "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", "dev": true, "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { @@ -7218,36 +9408,36 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -7258,7 +9448,7 @@ "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.2.0" }, "dependencies": { "kind-of": { @@ -7267,7 +9457,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -7278,7 +9468,7 @@ "integrity": "sha1-LGzsFP7cIiJznK+bXD2F0cxaLMg=", "dev": true, "requires": { - "hoek": "4.2.1" + "hoek": "4.x.x" } }, "source-map": { @@ -7292,11 +9482,11 @@ "integrity": "sha1-etD1k/IoFZjoVN+A8ZquS5LXoRo=", "dev": true, "requires": { - "atob": "2.1.1", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.0", - "urix": "0.1.0" + "atob": "^2.0.0", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-support": { @@ -7304,7 +9494,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", "integrity": "sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8=", "requires": { - "source-map": "0.5.7" + "source-map": "^0.5.6" } }, "source-map-url": { @@ -7316,33 +9506,33 @@ "spdx-correct": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "integrity": "sha1-BaW01xU6GVvJLDxCW2nzsqlSTII=", "dev": true, "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", + "integrity": "sha1-LHrmEFbHFKW5ubKyr30xHvXHj+k=", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", "dev": true, "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", + "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=", "dev": true }, "split": { @@ -7350,7 +9540,7 @@ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", "integrity": "sha1-YFvZvjA6pZ+zX5Ip++oN3snqB9k=", "requires": { - "through": "2.3.8" + "through": "2" }, "dependencies": { "through": { @@ -7366,7 +9556,7 @@ "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", "dev": true, "requires": { - "extend-shallow": "3.0.2" + "extend-shallow": "^3.0.0" }, "dependencies": { "extend-shallow": { @@ -7375,8 +9565,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" } }, "is-extendable": { @@ -7385,7 +9575,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -7401,14 +9591,14 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" } }, "static-extend": { @@ -7417,8 +9607,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { @@ -7427,7 +9617,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -7441,11 +9631,11 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" }, "dependencies": { "ansi-regex": { @@ -7456,15 +9646,15 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { @@ -7472,7 +9662,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -7482,7 +9672,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "stringstream": { @@ -7498,7 +9688,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -7530,12 +9720,12 @@ "integrity": "sha1-ozRHN1OR52atNNNIbm4q7chNLjY=", "dev": true, "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.5", + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", "slice-ansi": "1.0.0", - "string-width": "2.1.1" + "string-width": "^2.1.1" }, "dependencies": { "ansi-styles": { @@ -7544,7 +9734,7 @@ "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "chalk": { @@ -7553,9 +9743,9 @@ "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "escape-string-regexp": { @@ -7570,7 +9760,7 @@ "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -7580,19 +9770,19 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.4.tgz", "integrity": "sha1-7IQJ+un2ZaQ1XMO0CH0IICMruM0=", "requires": { - "chownr": "1.0.1", - "fs-minipass": "1.2.5", - "minipass": "2.3.3", - "minizlib": "1.1.0", - "mkdirp": "0.5.1", - "safe-buffer": "5.1.2", - "yallist": "3.0.2" + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.3", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" }, "dependencies": { "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" } } }, @@ -7601,10 +9791,10 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.2.tgz", "integrity": "sha1-F+Ujl0fjmffnc0T19TNl8Er1NXc=", "requires": { - "chownr": "1.0.1", - "mkdirp": "0.5.1", - "pump": "1.0.3", - "tar-stream": "1.6.0" + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" }, "dependencies": { "once": { @@ -7612,7 +9802,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "pump": { @@ -7620,8 +9810,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", "integrity": "sha1-Xf6DEcM7v2/BgmH580cCxHwIqVQ=", "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "wrappy": { @@ -7636,13 +9826,13 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.0.tgz", "integrity": "sha1-pQ76p7F3YLgsJ7PK5KMBqCVKVxU=", "requires": { - "bl": "1.2.2", - "buffer-alloc": "1.1.0", - "end-of-stream": "1.4.1", - "fs-constants": "1.0.0", - "readable-stream": "2.3.3", - "to-buffer": "1.1.1", - "xtend": "4.0.1" + "bl": "^1.0.0", + "buffer-alloc": "^1.1.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.0.0", + "to-buffer": "^1.1.0", + "xtend": "^4.0.0" } }, "temp": { @@ -7650,8 +9840,8 @@ "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", "requires": { - "os-tmpdir": "1.0.2", - "rimraf": "2.2.8" + "os-tmpdir": "^1.0.0", + "rimraf": "~2.2.6" }, "dependencies": { "os-tmpdir": { @@ -7695,7 +9885,7 @@ "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.1" }, "dependencies": { "os-tmpdir": { @@ -7729,7 +9919,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -7738,7 +9928,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -7749,10 +9939,10 @@ "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", "dev": true, "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" }, "dependencies": { "extend-shallow": { @@ -7761,8 +9951,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" } }, "is-extendable": { @@ -7771,7 +9961,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -7782,8 +9972,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } }, "tough-cookie": { @@ -7791,7 +9981,7 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha1-7GDO44rGdQY//JelwYlwV47oNlU=", "requires": { - "punycode": "1.4.1" + "punycode": "^1.4.1" } }, "tree-kill": { @@ -7810,7 +10000,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -7825,7 +10015,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "type-detect": { @@ -7857,10 +10047,10 @@ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" }, "dependencies": { "extend-shallow": { @@ -7869,7 +10059,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "set-value": { @@ -7878,10 +10068,10 @@ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" } } } @@ -7897,8 +10087,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "dependencies": { "has-value": { @@ -7907,9 +10097,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "dependencies": { "isobject": { @@ -7946,25 +10136,25 @@ "use": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", + "integrity": "sha1-FHFr8D/f79AwQK71jYtLhfOnxUQ=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.2" } }, "uuid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=" }, "validate-npm-package-license": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", + "integrity": "sha1-gWQ7y+8b3+zUYjeT3EZIlIupgzg=", "dev": true, "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, "verror": { @@ -7972,9 +10162,9 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" }, "dependencies": { "assert-plus": { @@ -7996,11 +10186,11 @@ "dev": true, "requires": { "browser-split": "0.0.1", - "error": "4.4.0", - "ev-store": "7.0.0", - "global": "4.3.2", - "is-object": "1.0.1", - "next-tick": "0.2.2", + "error": "^4.3.0", + "ev-store": "^7.0.0", + "global": "^4.3.0", + "is-object": "^1.0.1", + "next-tick": "^0.2.2", "x-is-array": "0.1.0", "x-is-string": "0.1.0" } @@ -8015,7 +10205,7 @@ "resolved": "https://registry.npmjs.org/what-the-status/-/what-the-status-1.0.3.tgz", "integrity": "sha1-lP3NAR/7U6Ijnnb6+NrL78mHdRA=", "requires": { - "split": "1.0.1" + "split": "^1.0.0" } }, "whatwg-fetch": { @@ -8029,7 +10219,7 @@ "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "which-module": { @@ -8048,7 +10238,7 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", "integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=", "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2" }, "dependencies": { "ansi-regex": { @@ -8061,9 +10251,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "strip-ansi": { @@ -8071,7 +10261,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } } } @@ -8087,8 +10277,8 @@ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" }, "dependencies": { "string-width": { @@ -8097,9 +10287,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -8110,7 +10300,7 @@ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "0.5.1" + "mkdirp": "^0.5.1" } }, "x-is-array": { @@ -8153,19 +10343,19 @@ "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", "dev": true, "requires": { - "camelcase": "4.1.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "read-pkg-up": "2.0.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "7.0.0" + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^7.0.0" } }, "yargs-parser": { @@ -8174,7 +10364,7 @@ "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", "dev": true, "requires": { - "camelcase": "4.1.0" + "camelcase": "^4.1.0" } }, "yubikiri": { diff --git a/package.json b/package.json index e5624d73d4..0ce2f5ab3d 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "yubikiri": "1.0.0" }, "devDependencies": { + "@smashwilson/enzyme-adapter-react-16": "1.0.2", "atom-mocha-test-runner": "1.2.0", "babel-eslint": "8.2.3", "chai": "4.1.2", @@ -70,7 +71,6 @@ "dedent-js": "1.0.1", "electron-devtools-installer": "2.2.4", "enzyme": "3.3.0", - "@smashwilson/enzyme-adapter-react-16": "1.0.2", "eslint": "4.19.1", "eslint-config-fbjs-opensource": "1.0.0", "hock": "1.3.2", @@ -80,6 +80,7 @@ "mocha-junit-and-console-reporter": "1.6.0", "mocha-stress": "1.0.0", "node-fetch": "2.1.2", + "nyc": "^12.0.2", "relay-compiler": "1.6.0", "sinon": "6.0.0", "test-until": "1.1.1" From 34e26df01ba24d33f286beeb425b81c42c91086e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 12:14:15 -0400 Subject: [PATCH 0319/4847] Got it working kind of! --- .babelrc | 7 +- .gitignore | 1 + .nycrc.json | 7 + package-lock.json | 1538 +++++++++++-------------------------------- package.json | 12 +- script/intermediate | 7 + test/helpers.js | 4 + test/runner.js | 15 + 8 files changed, 433 insertions(+), 1158 deletions(-) create mode 100644 .nycrc.json create mode 100755 script/intermediate diff --git a/.babelrc b/.babelrc index 751318c9c1..b02160737d 100644 --- a/.babelrc +++ b/.babelrc @@ -11,5 +11,10 @@ ], "presets": [ "react", - ] + ], + "env": { + "test": { + "plugins": ["istanbul"] + } + } } diff --git a/.gitignore b/.gitignore index b2c6816eaf..bc032629fb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules spec/fixtures/a/ spec/fixtures/b/ .tern-project +.nyc_output/ diff --git a/.nycrc.json b/.nycrc.json new file mode 100644 index 0000000000..eab5121c4c --- /dev/null +++ b/.nycrc.json @@ -0,0 +1,7 @@ +{ + "instrument": false, + "source-map": false, + "include": [ + "lib/**/*.js" + ] +} diff --git a/package-lock.json b/package-lock.json index 968497caea..5200d27d31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1109,6 +1109,47 @@ "babel-runtime": "^6.22.0" } }, + "babel-plugin-istanbul": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", + "integrity": "sha1-NsWbIZLvzoHFs3gyG3QXWt0cmkU=", + "dev": true, + "requires": { + "babel-plugin-syntax-object-rest-spread": "^6.13.0", + "find-up": "^2.1.0", + "istanbul-lib-instrument": "^1.10.1", + "test-exclude": "^4.2.1" + }, + "dependencies": { + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz", + "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz", + "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", + "dev": true, + "requires": { + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.0", + "semver": "^5.3.0" + } + } + } + }, "babel-plugin-relay": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/babel-plugin-relay/-/babel-plugin-relay-1.6.0.tgz", @@ -2375,6 +2416,37 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.0.tgz", "integrity": "sha1-VpwFCRi+ZIazg3VSAorgRmtxcIY=" }, + "cross-env": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz", + "integrity": "sha1-bs1MAV1Xc+YUA57lKQdmabnRJvI=", + "dev": true, + "requires": { + "cross-spawn": "^6.0.5", + "is-windows": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + } + } + }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -4617,6 +4689,12 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -5702,7 +5780,8 @@ }, "stringstream": { "version": "0.0.5", - "resolved": "", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", "dev": true } } @@ -5913,6 +5992,12 @@ "integrity": "sha1-ddpKkn7liH45BliABltzNkE7MQ0=", "dev": true }, + "nice-try": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", + "integrity": "sha1-2Tli9sUvLBVYwPvabVEoGfHv4cQ=", + "dev": true + }, "nise": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.1.tgz", @@ -6011,38 +6096,36 @@ } }, "nyc": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-12.0.2.tgz", - "integrity": "sha1-ikpO1pCWbBHsWH/4fuoMEsl0upk=", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-13.0.0.tgz", + "integrity": "sha512-aQo5UssY25uCJ6M3yNjem0C3KJ1z4IYLp9iR2KqRsuwAII1YofEnRDrHOzp/0Zk2YMYXXxuvWUzjr24i4nmfDA==", "dev": true, "requires": { "archy": "^1.0.0", "arrify": "^1.0.1", - "caching-transform": "^1.0.0", + "caching-transform": "^1.0.1", "convert-source-map": "^1.5.1", "debug-log": "^1.0.1", - "default-require-extensions": "^1.0.0", - "find-cache-dir": "^0.1.1", + "find-cache-dir": "^1.0.0", "find-up": "^2.1.0", - "foreground-child": "^1.5.3", - "glob": "^7.0.6", - "istanbul-lib-coverage": "^1.2.0", - "istanbul-lib-hook": "^1.1.0", - "istanbul-lib-instrument": "^2.1.0", - "istanbul-lib-report": "^1.1.3", - "istanbul-lib-source-maps": "^1.2.5", - "istanbul-reports": "^1.4.1", - "md5-hex": "^1.2.0", + "foreground-child": "^1.5.6", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.0", + "istanbul-lib-hook": "^2.0.0", + "istanbul-lib-instrument": "^2.2.0", + "istanbul-lib-report": "^2.0.0", + "istanbul-lib-source-maps": "^2.0.0", + "istanbul-reports": "^1.5.0", + "make-dir": "^1.3.0", + "md5-hex": "^2.0.0", "merge-source-map": "^1.1.0", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.0", - "resolve-from": "^2.0.0", + "resolve-from": "^4.0.0", "rimraf": "^2.6.2", - "signal-exit": "^3.0.1", + "signal-exit": "^3.0.2", "spawn-wrap": "^1.4.2", - "test-exclude": "^4.2.0", + "test-exclude": "^4.2.2", "yargs": "11.1.0", - "yargs-parser": "^8.0.0" + "yargs-parser": "^9.0.2" }, "dependencies": { "align-text": { @@ -6066,11 +6149,11 @@ "dev": true }, "append-transform": { - "version": "0.4.0", + "version": "1.0.0", "bundled": true, "dev": true, "requires": { - "default-require-extensions": "^1.0.0" + "default-require-extensions": "^2.0.0" } }, "archy": { @@ -6078,106 +6161,21 @@ "bundled": true, "dev": true }, - "arr-diff": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "bundled": true, - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "bundled": true, - "dev": true - }, "arrify": { "version": "1.0.1", "bundled": true, "dev": true }, - "assign-symbols": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, "async": { "version": "1.5.2", "bundled": true, "dev": true }, - "atob": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, "balanced-match": { "version": "1.0.0", "bundled": true, "dev": true }, - "base": { - "version": "0.11.2", - "bundled": true, - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, "brace-expansion": { "version": "1.1.11", "bundled": true, @@ -6187,54 +6185,11 @@ "concat-map": "0.0.1" } }, - "braces": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "builtin-modules": { "version": "1.1.1", "bundled": true, "dev": true }, - "cache-base": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, "caching-transform": { "version": "1.0.1", "bundled": true, @@ -6243,6 +6198,16 @@ "md5-hex": "^1.2.0", "mkdirp": "^0.5.1", "write-file-atomic": "^1.1.4" + }, + "dependencies": { + "md5-hex": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "md5-o-matic": "^0.1.1" + } + } } }, "camelcase": { @@ -6261,27 +6226,6 @@ "lazy-cache": "^1.0.3" } }, - "class-utils": { - "version": "0.3.6", - "bundled": true, - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "cliui": { "version": "2.1.0", "bundled": true, @@ -6306,25 +6250,11 @@ "bundled": true, "dev": true }, - "collection-visit": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, "commondir": { "version": "1.0.1", "bundled": true, "dev": true }, - "component-emitter": { - "version": "1.2.1", - "bundled": true, - "dev": true - }, "concat-map": { "version": "0.0.1", "bundled": true, @@ -6335,11 +6265,6 @@ "bundled": true, "dev": true }, - "copy-descriptor": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, "cross-spawn": { "version": "4.0.2", "bundled": true, @@ -6367,56 +6292,16 @@ "bundled": true, "dev": true }, - "decode-uri-component": { - "version": "0.2.0", - "bundled": true, - "dev": true - }, "default-require-extensions": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "strip-bom": "^2.0.0" - } - }, - "define-property": { - "version": "2.0.2", + "version": "2.0.0", "bundled": true, "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "strip-bom": "^3.0.0" }, "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", + "strip-bom": { + "version": "3.0.0", "bundled": true, "dev": true } @@ -6456,175 +6341,26 @@ } } }, - "expand-brackets": { - "version": "2.1.4", + "find-cache-dir": { + "version": "1.0.0", "bundled": true, "dev": true, "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" } }, - "extend-shallow": { - "version": "3.0.2", + "find-up": { + "version": "2.1.0", "bundled": true, "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "locate-path": "^2.0.0" } }, - "extglob": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "fill-range": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "find-cache-dir": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "requires": { - "commondir": "^1.0.1", - "mkdirp": "^0.5.1", - "pkg-dir": "^1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "for-in": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "foreground-child": { - "version": "1.5.6", + "foreground-child": { + "version": "1.5.6", "bundled": true, "dev": true, "requires": { @@ -6632,14 +6368,6 @@ "signal-exit": "^3.0.0" } }, - "fragment-cache": { - "version": "0.2.1", - "bundled": true, - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, "fs.realpath": { "version": "1.0.0", "bundled": true, @@ -6655,11 +6383,6 @@ "bundled": true, "dev": true }, - "get-value": { - "version": "2.0.6", - "bundled": true, - "dev": true - }, "glob": { "version": "7.1.2", "bundled": true, @@ -6699,34 +6422,10 @@ } } }, - "has-value": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", + "has-flag": { + "version": "3.0.0", "bundled": true, - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "dev": true }, "hosted-git-info": { "version": "2.6.0", @@ -6757,14 +6456,6 @@ "bundled": true, "dev": true }, - "is-accessor-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, "is-arrayish": { "version": "0.2.1", "bundled": true, @@ -6783,161 +6474,76 @@ "builtin-modules": "^1.0.0" } }, - "is-data-descriptor": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "bundled": true, - "dev": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, "is-fullwidth-code-point": { "version": "2.0.0", "bundled": true, "dev": true }, - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-odd": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "bundled": true, - "dev": true - } - } - }, - "is-plain-object": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "is-stream": { "version": "1.1.0", "bundled": true, "dev": true }, - "is-utf8": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, "isexe": { "version": "2.0.0", "bundled": true, "dev": true }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, "istanbul-lib-coverage": { - "version": "1.2.0", + "version": "2.0.0", "bundled": true, "dev": true }, "istanbul-lib-hook": { - "version": "1.1.0", + "version": "2.0.0", "bundled": true, "dev": true, "requires": { - "append-transform": "^0.4.0" + "append-transform": "^1.0.0" } }, "istanbul-lib-report": { - "version": "1.1.3", + "version": "2.0.0", "bundled": true, "dev": true, "requires": { - "istanbul-lib-coverage": "^1.1.2", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "bundled": true, - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } + "istanbul-lib-coverage": "^2.0.0", + "make-dir": "^1.3.0", + "supports-color": "^5.4.0" } }, "istanbul-lib-source-maps": { - "version": "1.2.5", + "version": "2.0.0", "bundled": true, "dev": true, "requires": { "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.2.0", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" + "istanbul-lib-coverage": "^2.0.0", + "make-dir": "^1.3.0", + "rimraf": "^2.6.2", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "bundled": true, + "dev": true + } } }, "istanbul-reports": { - "version": "1.4.1", + "version": "1.5.0", "bundled": true, "dev": true, "requires": { - "handlebars": "^4.0.3" + "handlebars": "^4.0.11" } }, + "json-parse-better-errors": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, "kind-of": { "version": "3.2.2", "bundled": true, @@ -6960,18 +6566,6 @@ "invert-kv": "^1.0.0" } }, - "load-json-file": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, "locate-path": { "version": "2.0.0", "bundled": true, @@ -7002,21 +6596,23 @@ "yallist": "^2.1.2" } }, - "map-cache": { - "version": "0.2.2", - "bundled": true, - "dev": true - }, - "map-visit": { - "version": "1.0.0", + "make-dir": { + "version": "1.3.0", "bundled": true, "dev": true, "requires": { - "object-visit": "^1.0.0" + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "bundled": true, + "dev": true + } } }, "md5-hex": { - "version": "1.3.0", + "version": "2.0.0", "bundled": true, "dev": true, "requires": { @@ -7051,33 +6647,6 @@ } } }, - "micromatch": { - "version": "3.1.10", - "bundled": true, - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, "mimic-fn": { "version": "1.2.0", "bundled": true, @@ -7096,25 +6665,6 @@ "bundled": true, "dev": true }, - "mixin-deep": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "mkdirp": { "version": "0.5.1", "bundled": true, @@ -7128,32 +6678,6 @@ "bundled": true, "dev": true }, - "nanomatch": { - "version": "1.2.9", - "bundled": true, - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, "normalize-package-data": { "version": "2.4.0", "bundled": true, @@ -7178,49 +6702,8 @@ "bundled": true, "dev": true }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "bundled": true, - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "object-visit": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "once": { - "version": "1.4.0", + "once": { + "version": "1.4.0", "bundled": true, "dev": true, "requires": { @@ -7277,27 +6760,6 @@ "bundled": true, "dev": true }, - "parse-json": { - "version": "2.2.0", - "bundled": true, - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "pascalcase": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "path-exists": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, "path-is-absolute": { "version": "1.0.1", "bundled": true, @@ -7308,112 +6770,19 @@ "bundled": true, "dev": true }, - "path-parse": { - "version": "1.0.5", - "bundled": true, - "dev": true - }, - "path-type": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "bundled": true, - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "bundled": true, - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, "pkg-dir": { - "version": "1.0.0", + "version": "2.0.0", "bundled": true, "dev": true, "requires": { - "find-up": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - } + "find-up": "^2.1.0" } }, - "posix-character-classes": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, "pseudomap": { "version": "1.0.2", "bundled": true, "dev": true }, - "read-pkg": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - } - } - }, - "regex-not": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "repeat-element": { - "version": "1.1.2", - "bundled": true, - "dev": true - }, "repeat-string": { "version": "1.6.1", "bundled": true, @@ -7430,221 +6799,66 @@ "dev": true }, "resolve-from": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "ret": { - "version": "0.1.15", + "version": "4.0.0", "bundled": true, "dev": true }, "right-align": { "version": "0.1.3", "bundled": true, - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.1" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "dev": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-regex": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "semver": { - "version": "5.5.0", - "bundled": true, - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "set-value": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "slide": { - "version": "1.1.6", - "bundled": true, - "dev": true - }, - "snapdragon": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.1" } }, - "snapdragon-util": { - "version": "3.0.1", + "rimraf": { + "version": "2.6.2", "bundled": true, "dev": true, "requires": { - "kind-of": "^3.2.0" + "glob": "^7.0.5" } }, - "source-map": { - "version": "0.5.7", + "semver": { + "version": "5.5.0", + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", "bundled": true, "dev": true }, - "source-map-resolve": { - "version": "0.5.2", + "shebang-command": { + "version": "1.2.0", "bundled": true, "dev": true, "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "shebang-regex": "^1.0.0" } }, - "source-map-url": { - "version": "0.4.0", + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "slide": { + "version": "1.1.6", "bundled": true, "dev": true }, + "source-map": { + "version": "0.5.7", + "bundled": true, + "dev": true, + "optional": true + }, "spawn-wrap": { "version": "1.4.2", "bundled": true, @@ -7686,33 +6900,6 @@ "bundled": true, "dev": true }, - "split-string": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "static-extend": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "string-width": { "version": "2.1.1", "bundled": true, @@ -7730,178 +6917,120 @@ "ansi-regex": "^3.0.0" } }, - "strip-bom": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - }, "strip-eof": { "version": "1.0.0", "bundled": true, "dev": true }, - "test-exclude": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "requires": { - "arrify": "^1.0.1", - "micromatch": "^3.1.8", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", - "require-main-filename": "^1.0.1" - } - }, - "to-object-path": { - "version": "0.3.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "to-regex": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", + "supports-color": { + "version": "5.4.0", "bundled": true, "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "has-flag": "^3.0.0" } }, - "uglify-js": { - "version": "2.8.29", + "test-exclude": { + "version": "4.2.2", "bundled": true, "dev": true, - "optional": true, "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" + "arrify": "^1.0.1", + "minimatch": "^3.0.4", + "read-pkg-up": "^3.0.0", + "require-main-filename": "^1.0.1" }, "dependencies": { - "yargs": { - "version": "3.10.0", + "load-json-file": { + "version": "4.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" } - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "union-value": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", + }, + "parse-json": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "is-extendable": "^0.1.0" + "pify": "^3.0.0" } }, - "set-value": { - "version": "0.4.3", + "pify": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "read-pkg": { + "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" } - } - } - }, - "unset-value": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", + }, + "read-pkg-up": { + "version": "3.0.0", "bundled": true, "dev": true, "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" } }, - "has-values": { - "version": "0.1.4", + "strip-bom": { + "version": "3.0.0", "bundled": true, "dev": true } } }, - "urix": { - "version": "0.1.0", - "bundled": true, - "dev": true - }, - "use": { - "version": "3.1.0", + "uglify-js": { + "version": "2.8.29", "bundled": true, "dev": true, + "optional": true, "requires": { - "kind-of": "^6.0.2" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" }, "dependencies": { - "kind-of": { - "version": "6.0.2", + "yargs": { + "version": "3.10.0", "bundled": true, - "dev": true + "dev": true, + "optional": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } } } }, + "uglify-to-browserify": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, "validate-npm-package-license": { "version": "3.0.3", "bundled": true, @@ -8047,7 +7176,7 @@ } }, "yargs-parser": { - "version": "8.1.0", + "version": "9.0.2", "bundled": true, "dev": true, "requires": { @@ -8378,6 +7507,21 @@ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", @@ -8646,7 +7790,7 @@ "react-is": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.4.1.tgz", - "integrity": "sha512-xpb0PpALlFWNw/q13A+1aHeyJyLYCg0/cCHPUA43zYluZuIPHaHL3k8OBsTgQtxqW0FhyDEMvi8fZ/+7+r4OSQ==", + "integrity": "sha1-1iTEZQ0sZdvVLHJiK784lDXZd24=", "dev": true }, "react-reconciler": { @@ -8757,7 +7901,7 @@ "react-test-renderer": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.4.1.tgz", - "integrity": "sha512-wyyiPxRZOTpKnNIgUBOB6xPLTpIzwcQMIURhZvzUqZzezvHjaGNsDPBhMac5fIY3Jf5NuKxoGvV64zDSOECPPQ==", + "integrity": "sha1-8vswwse1F9tuWxDtILtrCnzNjXA=", "dev": true, "requires": { "fbjs": "^0.8.16", @@ -9325,7 +8469,7 @@ "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -9856,6 +9000,94 @@ } } }, + "test-exclude": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.1.tgz", + "integrity": "sha1-36Ii8DSAvKaSB8pyizfXS0X3JPo=", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "micromatch": "^3.1.8", + "object-assign": "^4.1.0", + "read-pkg-up": "^1.0.1", + "require-main-filename": "^1.0.1" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + } + } + }, "test-until": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/test-until/-/test-until-1.1.1.tgz", diff --git a/package.json b/package.json index 0ce2f5ab3d..2c932dce11 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "repository": "https://github.com/atom/github", "license": "MIT", "scripts": { - "test": "atom --test test", + "test": "cross-env BABEL_ENV=test nyc --show-process-tree script/intermediate", "lint": "eslint --max-warnings 0 test lib", "fetch-schema": "node script/fetch-schema", "relay": "relay-compiler --src ./lib --schema graphql/schema.graphql" @@ -24,8 +24,10 @@ "package.json", ".babelrc", "assert-messages-plugin.js", - "graphql/schema.graphql" - ] + "graphql/schema.graphql", + "one-up" + ], + "setBabelEnv": false } } ], @@ -66,8 +68,10 @@ "@smashwilson/enzyme-adapter-react-16": "1.0.2", "atom-mocha-test-runner": "1.2.0", "babel-eslint": "8.2.3", + "babel-plugin-istanbul": "4.1.6", "chai": "4.1.2", "chai-as-promised": "7.1.1", + "cross-env": "5.2.0", "dedent-js": "1.0.1", "electron-devtools-installer": "2.2.4", "enzyme": "3.3.0", @@ -80,7 +84,7 @@ "mocha-junit-and-console-reporter": "1.6.0", "mocha-stress": "1.0.0", "node-fetch": "2.1.2", - "nyc": "^12.0.2", + "nyc": "^13.0.0", "relay-compiler": "1.6.0", "sinon": "6.0.0", "test-until": "1.1.1" diff --git a/script/intermediate b/script/intermediate new file mode 100755 index 0000000000..319ded2fbd --- /dev/null +++ b/script/intermediate @@ -0,0 +1,7 @@ +#!/usr/bin/env node + +const {spawnSync} = require('child_process'); + +spawnSync('atom', ['--test', 'test'], { + stdio: 'inherit', +}); diff --git a/test/helpers.js b/test/helpers.js index eedbeae74c..55b6c348ef 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -258,4 +258,8 @@ after(() => { if (!process.env.ATOM_GITHUB_SHOW_RENDERER_WINDOW) { WorkerManager.reset(true); } + + if (global._nyc) { + global._nyc.writeCoverageFile(); + } }); diff --git a/test/runner.js b/test/runner.js index 32abefb5f8..d3e47cd764 100644 --- a/test/runner.js +++ b/test/runner.js @@ -4,6 +4,7 @@ import chaiAsPromised from 'chai-as-promised'; import path from 'path'; import until from 'test-until'; +import NYC from 'nyc'; chai.use(chaiAsPromised); global.assert = chai.assert; @@ -11,6 +12,20 @@ global.assert = chai.assert; // Give tests that rely on filesystem event delivery lots of breathing room. until.setDefaultTimeout(parseInt(process.env.UNTIL_TIMEOUT || '3000', 10)); +if (process.env.NYC_CONFIG) { + const parentPid = process.env.NYC_PARENT_PID || '0'; + process.env.NYC_PARENT_PID = process.pid; + + const config = JSON.parse(process.env.NYC_CONFIG); + config.isChildProcess = true; + config._processInfo = { + ppid: parentPid, + root: process.env.NYC_ROOT_ID, + }; + global._nyc = new NYC(config); + global._nyc.wrap(); +} + module.exports = createRunner({ htmlTitle: `GitHub Package Tests - pid ${process.pid}`, reporter: process.env.MOCHA_REPORTER || 'spec', From 37e36254d577e8f5b26c19dd21a0a7078b82b3f7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 14:25:20 -0400 Subject: [PATCH 0320/4847] No need for cross-env --- package-lock.json | 40 ++-------------------------------------- package.json | 1 - 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5200d27d31..e70e743944 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2416,37 +2416,6 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.0.tgz", "integrity": "sha1-VpwFCRi+ZIazg3VSAorgRmtxcIY=" }, - "cross-env": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz", - "integrity": "sha1-bs1MAV1Xc+YUA57lKQdmabnRJvI=", - "dev": true, - "requires": { - "cross-spawn": "^6.0.5", - "is-windows": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true - } - } - }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -5102,6 +5071,7 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, + "optional": true, "requires": { "hoek": "2.x.x" } @@ -5992,12 +5962,6 @@ "integrity": "sha1-ddpKkn7liH45BliABltzNkE7MQ0=", "dev": true }, - "nice-try": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", - "integrity": "sha1-2Tli9sUvLBVYwPvabVEoGfHv4cQ=", - "dev": true - }, "nise": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.1.tgz", @@ -6098,7 +6062,7 @@ "nyc": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-13.0.0.tgz", - "integrity": "sha512-aQo5UssY25uCJ6M3yNjem0C3KJ1z4IYLp9iR2KqRsuwAII1YofEnRDrHOzp/0Zk2YMYXXxuvWUzjr24i4nmfDA==", + "integrity": "sha1-4Awm6b0zq16B7emSu+STCEhYmbY=", "dev": true, "requires": { "archy": "^1.0.0", diff --git a/package.json b/package.json index 2c932dce11..1b61980684 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,6 @@ "babel-plugin-istanbul": "4.1.6", "chai": "4.1.2", "chai-as-promised": "7.1.1", - "cross-env": "5.2.0", "dedent-js": "1.0.1", "electron-devtools-installer": "2.2.4", "enzyme": "3.3.0", From 5265e48d276a1426c1b1f0020887c4b8b5ae8b4d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 14:25:38 -0400 Subject: [PATCH 0321/4847] Rename "intermediate" to "capture-env" --- script/capture-env | 10 ++++++++++ script/intermediate | 7 ------- 2 files changed, 10 insertions(+), 7 deletions(-) create mode 100755 script/capture-env delete mode 100755 script/intermediate diff --git a/script/capture-env b/script/capture-env new file mode 100755 index 0000000000..4ca5ec7a46 --- /dev/null +++ b/script/capture-env @@ -0,0 +1,10 @@ +#!/usr/bin/env node +// Capture the environment variables that istanbul sets via spawn-wrap, then exec Atom's test runner. + +const {spawnSync} = require('child_process'); +const atomPath = process.env.ATOM_SCRIPT_PATH || 'atom'; +process.env.BABEL_ENV = 'coverage'; + +spawnSync(atomPath, ['--test', 'test'], { + stdio: 'inherit', +}); diff --git a/script/intermediate b/script/intermediate deleted file mode 100755 index 319ded2fbd..0000000000 --- a/script/intermediate +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env node - -const {spawnSync} = require('child_process'); - -spawnSync('atom', ['--test', 'test'], { - stdio: 'inherit', -}); From 48f3aed953c679de2dac3a70f72b788f63b7541e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 14:34:33 -0400 Subject: [PATCH 0322/4847] Change the babel env to the more descriptive "coverage" --- .babelrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.babelrc b/.babelrc index b02160737d..4421da864b 100644 --- a/.babelrc +++ b/.babelrc @@ -13,7 +13,7 @@ "react", ], "env": { - "test": { + "coverage": { "plugins": ["istanbul"] } } From 5bfd38f2b0dc1afe229b5cbde523ec4c5b9ab9a9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 14:34:53 -0400 Subject: [PATCH 0323/4847] Separate "test" and "generate coverage" npm scripts --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1b61980684..c19bfd86be 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "repository": "https://github.com/atom/github", "license": "MIT", "scripts": { - "test": "cross-env BABEL_ENV=test nyc --show-process-tree script/intermediate", + "test": "atom --test test", + "test:coverage": "nyc script/capture-env", "lint": "eslint --max-warnings 0 test lib", "fetch-schema": "node script/fetch-schema", "relay": "relay-compiler --src ./lib --schema graphql/schema.graphql" From cd5c58d8d099e7b070638efa44fe55b7a2d75679 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 14:35:06 -0400 Subject: [PATCH 0324/4847] Generate test coverage on Travis --- script/cibuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/cibuild b/script/cibuild index 673ea5cf98..31fadb3fff 100755 --- a/script/cibuild +++ b/script/cibuild @@ -168,7 +168,7 @@ function runTests { if [ $LINT_RESULT -ne 0 ]; then echo ">>> LINTING FAILED! <<< Continuing on to tests..."; fi echo "Running specs..." - "$ATOM_SCRIPT_PATH" --test test + npm run test:coverage TEST_RESULT=$? echo "==================" From 83f8acb204a35fb7ba5042e11719fc03006cf9ac Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 14:35:22 -0400 Subject: [PATCH 0325/4847] Bust the Babel cache with .nycrc changes --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c19bfd86be..74fce82172 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ ".babelrc", "assert-messages-plugin.js", "graphql/schema.graphql", - "one-up" + ".nycrc.json" ], "setBabelEnv": false } From 819499b140f04fafe26db84173e685277f39cb9a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 14:35:33 -0400 Subject: [PATCH 0326/4847] Dev dependency on coveralls --- package-lock.json | 26 +++++++++++++++++++++++++- package.json | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index e70e743944..0b5d769d94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2416,6 +2416,19 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.0.tgz", "integrity": "sha1-VpwFCRi+ZIazg3VSAorgRmtxcIY=" }, + "coveralls": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.1.tgz", + "integrity": "sha512-FAzXwiDOYLGDWH+zgoIA+8GbWv50hlx+kpEJyvzLKOdnIBv9uWoVl4DhqGgyUHpiRjAlF8KYZSipWXYtllWH6Q==", + "dev": true, + "requires": { + "js-yaml": "^3.6.1", + "lcov-parse": "^0.0.10", + "log-driver": "^1.2.5", + "minimist": "^1.2.0", + "request": "^2.79.0" + } + }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -5018,6 +5031,12 @@ "invert-kv": "^1.0.0" } }, + "lcov-parse": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", + "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "dev": true + }, "less": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz", @@ -5071,7 +5090,6 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, - "optional": true, "requires": { "hoek": "2.x.x" } @@ -5465,6 +5483,12 @@ "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" }, + "log-driver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", + "dev": true + }, "lolex": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.0.tgz", diff --git a/package.json b/package.json index 74fce82172..cda4ad85c9 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "babel-plugin-istanbul": "4.1.6", "chai": "4.1.2", "chai-as-promised": "7.1.1", + "coveralls": "^3.0.1", "dedent-js": "1.0.1", "electron-devtools-installer": "2.2.4", "enzyme": "3.3.0", From 823a5d38609149aa958888ed5a3be871362773ac Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 14:38:03 -0400 Subject: [PATCH 0327/4847] Submit test coverage to Coveralls on Travis --- .travis.yml | 3 +++ package.json | 1 + 2 files changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 47f86aac25..821983cbf5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,3 +60,6 @@ before_script: script: - ./script/cibuild + +after_success: +- npm run coveralls diff --git a/package.json b/package.json index cda4ad85c9..de8db15bd9 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "scripts": { "test": "atom --test test", "test:coverage": "nyc script/capture-env", + "coveralls": "nyc report --reporter=text-lcov | coveralls", "lint": "eslint --max-warnings 0 test lib", "fetch-schema": "node script/fetch-schema", "relay": "relay-compiler --src ./lib --schema graphql/schema.graphql" From e4a52a7f0edcc3a07966340af032ae4115b11d0c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 14:38:13 -0400 Subject: [PATCH 0328/4847] Coveralls badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b12089041..59fe4dfe21 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Atom GitHub Package -[![Greenkeeper badge](https://badges.greenkeeper.io/atom/github.svg)](https://greenkeeper.io/) +[![Greenkeeper badge](https://badges.greenkeeper.io/atom/github.svg)](https://greenkeeper.io/) [![Coverage Status](https://coveralls.io/repos/github/atom/github/badge.svg?branch=master)](https://coveralls.io/github/atom/github?branch=master) | Windows | Mac | Linux | Dependency Status | |---------|-----|-------|-------------------| From acf45627e37ac94ff5a9948f0fe7d8717a426f92 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 15:08:04 -0400 Subject: [PATCH 0329/4847] Pin that dep --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index de8db15bd9..a88af9168e 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "mocha-junit-and-console-reporter": "1.6.0", "mocha-stress": "1.0.0", "node-fetch": "2.1.2", - "nyc": "^13.0.0", + "nyc": "13.0.0", "relay-compiler": "1.6.0", "sinon": "6.0.0", "test-until": "1.1.1" From 0cb84fb3aff97b996d1b6e857e74b4cb78a86f93 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Jun 2018 15:52:31 -0400 Subject: [PATCH 0330/4847] Use ATOM_GITHUB_BABEL_ENV to choose the babel environment --- package-lock.json | 13 ++++++------- package.json | 4 ++-- script/capture-env | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0b5d769d94..43f90a9cb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -471,9 +471,9 @@ "dev": true }, "atom-babel6-transpiler": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/atom-babel6-transpiler/-/atom-babel6-transpiler-1.1.3.tgz", - "integrity": "sha1-1wKxDpDrzx+R4apcSnm5zqmKm6Y=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/atom-babel6-transpiler/-/atom-babel6-transpiler-1.2.0.tgz", + "integrity": "sha512-lZucrjVyRtPAPPJxvICCEBsAC1qn48wUHaIlieriWCXTXLqtLC2PvkQU7vNvU2w1eZ7tw9m0lojZ8PbpVyWTvg==", "requires": { "babel-core": "6.x" } @@ -2419,7 +2419,7 @@ "coveralls": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.1.tgz", - "integrity": "sha512-FAzXwiDOYLGDWH+zgoIA+8GbWv50hlx+kpEJyvzLKOdnIBv9uWoVl4DhqGgyUHpiRjAlF8KYZSipWXYtllWH6Q==", + "integrity": "sha1-EuFZFOqikgTlaGml7Oe54UktKuI=", "dev": true, "requires": { "js-yaml": "^3.6.1", @@ -5486,7 +5486,7 @@ "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", - "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", + "integrity": "sha1-Y7lQIfBwL+36LJuwok53l9cYcdg=", "dev": true }, "lolex": { @@ -5774,8 +5774,7 @@ }, "stringstream": { "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "resolved": "", "dev": true } } diff --git a/package.json b/package.json index a88af9168e..963b6e22cd 100644 --- a/package.json +++ b/package.json @@ -29,12 +29,12 @@ "graphql/schema.graphql", ".nycrc.json" ], - "setBabelEnv": false + "setBabelEnv": "ATOM_GITHUB_BABEL_ENV" } } ], "dependencies": { - "atom-babel6-transpiler": "1.1.3", + "atom-babel6-transpiler": "1.2.0", "babel-generator": "6.26.1", "babel-plugin-chai-assert-async": "0.1.0", "babel-plugin-relay": "1.6.0", diff --git a/script/capture-env b/script/capture-env index 4ca5ec7a46..eac0ce59b1 100755 --- a/script/capture-env +++ b/script/capture-env @@ -3,7 +3,7 @@ const {spawnSync} = require('child_process'); const atomPath = process.env.ATOM_SCRIPT_PATH || 'atom'; -process.env.BABEL_ENV = 'coverage'; +process.env.ATOM_GITHUB_BABEL_ENV = 'coverage'; spawnSync(atomPath, ['--test', 'test'], { stdio: 'inherit', From bf45ae255385d50eec9177f4061cd3f095611a60 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 22 Jun 2018 15:42:06 +0900 Subject: [PATCH 0331/4847] Split messages into two parts --- lib/views/create-pull-request-tile.js | 43 +++++++++++++++++---------- styles/issueish-list-view.less | 13 ++++++++ 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/lib/views/create-pull-request-tile.js b/lib/views/create-pull-request-tile.js index 43cf8305c3..44776fe379 100644 --- a/lib/views/create-pull-request-tile.js +++ b/lib/views/create-pull-request-tile.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import Octicon from '../atom/octicon'; import {RemotePropType, BranchSetPropType} from '../prop-types'; @@ -25,16 +26,20 @@ export default class CreatePullRequestTile extends React.Component { return (
    Repository not found for the remote {this.props.remote.getName()}. - Do you need to update your remote URL? +
    + + Do you need to update your remote URL?
    ); } - + if (this.isDetachedHead()) { return (
    - You are not currently on any branch. -  Create a new branch  + You are not currently on any branch. +
    + + Create a new branch  to share your work with a pull request.
    ); @@ -43,8 +48,10 @@ export default class CreatePullRequestTile extends React.Component { if (this.hasNoDefaultRef()) { return (
    - The repository at remote {this.props.remote.getName()} is - empty. Push a main branch to begin sharing your work. + The repository at remote {this.props.remote.getName()} is empty. +
    + + Push a main branch to begin sharing your work.
    ); } @@ -52,8 +59,10 @@ export default class CreatePullRequestTile extends React.Component { if (this.isOnDefaultRef()) { return (
    - You are currently on your repository's default branch. -  Create a new branch  + You are currently on your repository's default branch. +
    + + Checkout or create a new branch  to share your work with a pull request.
    ); @@ -62,8 +71,10 @@ export default class CreatePullRequestTile extends React.Component { if (this.isSameAsDefaultRef()) { return (
    - Your current branch has not moved from the repository's default branch. -  Make some commits  + Your current branch has not moved from the repository's default branch. +
    + + Make some commits  to share your work with a pull request.
    ); @@ -85,19 +96,21 @@ export default class CreatePullRequestTile extends React.Component {
    {differentRemote &&
    - Your current branch is configured to push to the remote - {this.props.branches.getHeadBranch().getPush().getRemoteName()}. - Publish it to {this.props.remote.getName()} instead? + Your current branch is configured to push to the + remote {this.props.branches.getHeadBranch().getPush().getRemoteName()}. +
    + + Publish it to {this.props.remote.getName()} instead?
    } -

    +

    -

    +
    ); } diff --git a/styles/issueish-list-view.less b/styles/issueish-list-view.less index a4ebfc4fdf..9bee3602f4 100644 --- a/styles/issueish-list-view.less +++ b/styles/issueish-list-view.less @@ -92,6 +92,19 @@ text-align: center; margin-bottom: 0; } + &-message + .github-CreatePullRequestTile-controls { + border-top: 1px solid @base-border-color; + } + &-message .icon { + vertical-align: middle; + &:before { + width: auto; + } + } + &-divider { + margin: @component-padding/1.25 0; + border-color: @base-border-color; + } &-createPr { width: 100%; } From 66d149c6f9355077f0b1ef66075802a611f4faea Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 22 Jun 2018 16:13:23 +0900 Subject: [PATCH 0332/4847] Fix lint warning "Trailing spaces not allowed" --- lib/views/create-pull-request-tile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/create-pull-request-tile.js b/lib/views/create-pull-request-tile.js index 44776fe379..c14ae92a24 100644 --- a/lib/views/create-pull-request-tile.js +++ b/lib/views/create-pull-request-tile.js @@ -32,7 +32,7 @@ export default class CreatePullRequestTile extends React.Component {
    ); } - + if (this.isDetachedHead()) { return (
    From 45c358fb6b6403e35ee2efac92fabeda88eb2a8d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 10:37:24 -0400 Subject: [PATCH 0333/4847] Prepare Git and GitHub tab item components to be PaneItems --- lib/controllers/github-tab-controller.js | 8 +++++++- lib/items/git-tab-item.js | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/controllers/github-tab-controller.js b/lib/controllers/github-tab-controller.js index c09720789a..6ad6689ffe 100644 --- a/lib/controllers/github-tab-controller.js +++ b/lib/controllers/github-tab-controller.js @@ -16,6 +16,12 @@ export default class GithubTabController extends React.Component { loginModel: PropTypes.instanceOf(GithubLoginModel), } + static uriPattern = 'atom-github://dock-item/github'; + + static buildURI() { + return this.uriPattern; + } + constructor(props) { super(props); autobind(this, 'handleRemoteSelect'); @@ -155,7 +161,7 @@ export default class GithubTabController extends React.Component { } getURI() { - return 'atom-github://dock-item/github'; + return this.constructor.uriPattern; } getWorkingDirectory() { diff --git a/lib/items/git-tab-item.js b/lib/items/git-tab-item.js index ad5b775e9c..46ec3193d8 100644 --- a/lib/items/git-tab-item.js +++ b/lib/items/git-tab-item.js @@ -9,6 +9,12 @@ export default class GitTabItem extends React.Component { repository: PropTypes.object.isRequired, } + static uriPattern = 'atom-github://dock-item/git' + + static buildURI() { + return this.uriPattern; + } + constructor(props) { super(props); @@ -48,7 +54,7 @@ export default class GitTabItem extends React.Component { } getURI() { - return 'atom-github://dock-item/git'; + return this.constructor.uriPattern; } getWorkingDirectory() { From 427628a96a6b2cb799d4db0e73dd02cd186410b6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 11:13:34 -0400 Subject: [PATCH 0334/4847] Use tab URIs for the TabTracker --- lib/controllers/root-controller.js | 58 +++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index ab41c31706..4d7451c212 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -88,13 +88,11 @@ export default class RootController extends React.Component { this.gitTabTracker = new TabTracker('git', { uri: 'atom-github://dock-item/git', - getController: () => this.refGitTabItem.get(), getWorkspace: () => this.props.workspace, }); this.githubTabTracker = new TabTracker('github', { uri: 'atom-github://dock-item/github', - getController: () => this.refGithubTabController.get(), getWorkspace: () => this.props.workspace, }); @@ -725,25 +723,14 @@ export default class RootController extends React.Component { } class TabTracker { - constructor(name, {getController, getWorkspace, uri}) { + constructor(name, {getWorkspace, uri}) { autobind(this, 'toggle', 'toggleFocus', 'ensureVisible'); this.name = name; this.getWorkspace = getWorkspace; - this.getController = getController; this.uri = uri; } - getControllerComponent() { - const controller = this.getController(); - - if (controller.getWrappedComponent) { - return controller.getWrappedComponent(); - } - - return controller; - } - async toggle() { const focusToRestore = document.activeElement; let shouldRestoreFocus = false; @@ -800,7 +787,45 @@ class TabTracker { } focus() { - this.getControllerComponent().restoreFocus(); + this.getComponent().restoreFocus(); + } + + getItem() { + const pane = this.getWorkspace().paneForURI(this.uri); + if (!pane) { + return null; + } + + const paneItem = pane.itemForURI(this.uri); + if (!paneItem) { + return null; + } + + return paneItem; + } + + getComponent() { + const paneItem = this.getItem(); + if (!paneItem) { + return null; + } + if (((typeof paneItem.getRealItem) !== 'function')) { + return null; + } + + return paneItem.getRealItem(); + } + + getDOMElement() { + const paneItem = this.getItem(); + if (!paneItem) { + return null; + } + if (((typeof paneItem.getElement) !== 'function')) { + return null; + } + + return paneItem.getElement(); } isRendered() { @@ -818,6 +843,7 @@ class TabTracker { } hasFocus() { - return this.getControllerComponent().hasFocus(); + const root = this.getDOMElement(); + return root && root.contains(document.activeElement); } } From 7c8153bcfd0754490bc0cca3d2880989a0fdfb83 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 11:13:45 -0400 Subject: [PATCH 0335/4847] That method is autobound --- lib/controllers/root-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 4d7451c212..f38fb565d1 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -97,7 +97,7 @@ export default class RootController extends React.Component { }); this.subscription = new CompositeDisposable( - this.props.repository.onMergeError(() => this.gitTabTracker.ensureVisible()), + this.props.repository.onMergeError(this.gitTabTracker.ensureVisible), ); } From e9af9006eec4c672b2e131f580d6f810c65b7e48 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 11:14:05 -0400 Subject: [PATCH 0336/4847] Move GitTabItem and GithubTabController to PaneItems --- lib/controllers/root-controller.js | 90 +++++++++++++----------------- 1 file changed, 38 insertions(+), 52 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index f38fb565d1..6e92708463 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -8,7 +8,6 @@ import {CompositeDisposable} from 'event-kit'; import StatusBar from '../atom/status-bar'; import Panel from '../atom/panel'; import PaneItem from '../atom/pane-item'; -import DockItem from '../atom/dock-item'; import CloneDialog from '../views/clone-dialog'; import OpenIssueishDialog from '../views/open-issueish-dialog'; import InitDialog from '../views/init-dialog'; @@ -106,7 +105,6 @@ export default class RootController extends React.Component { {this.renderCommands()} {this.renderStatusBarTile()} - {this.renderDockItems()} {this.renderPaneItems()} {this.renderDialogs()} {this.renderConflictResolver()} @@ -170,56 +168,6 @@ export default class RootController extends React.Component { ); } - renderDockItems() { - return ( - - {this.props.gitTabStubItem && ( - - - - )} - {this.props.githubTabStubItem && ( - - - - )} - - ); - } - renderDialogs() { return ( @@ -315,6 +263,44 @@ export default class RootController extends React.Component { renderPaneItems() { return ( + + {({itemHolder}) => ( + + )} + + + {({itemHolder}) => { + ; + }} + From d948e8a724e2a302ecc3fd6bda1dd55b654f36f6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 11:18:19 -0400 Subject: [PATCH 0337/4847] Remove unused RefHolders --- lib/controllers/root-controller.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 6e92708463..260d08df3d 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -82,9 +82,6 @@ export default class RootController extends React.Component { credentialDialogQuery: null, }; - this.refGitTabItem = new RefHolder(); - this.refGitHubTabController = new RefHolder(); - this.gitTabTracker = new TabTracker('git', { uri: 'atom-github://dock-item/git', getWorkspace: () => this.props.workspace, @@ -449,9 +446,8 @@ export default class RootController extends React.Component { } surfaceFromFileAtPath(filePath, stagingStatus) { - this.refGitTabItem.map(c => { - return c.focusAndSelectStagingItem(filePath, stagingStatus); - }); + const gitTab = this.gitTabTracker.getComponent(); + return gitTab && gitTab.focusAndSelectStagingItem(filePath, stagingStatus); } destroyFilePatchPaneItems() { @@ -467,9 +463,8 @@ export default class RootController extends React.Component { } quietlySelectItem(filePath, stagingStatus) { - return this.refGitTabItem.map(c => { - return c.quietlySelectItem(filePath, stagingStatus); - }); + const gitTab = this.gitTabTracker.getComponent(); + return gitTab && gitTab.quietlySelectItem(filePath, stagingStatus); } async viewChangesForCurrentFile(stagingStatus) { From 6b6a0020c1905a632fea6deb0d5cd17a83fc23df Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 11:22:07 -0400 Subject: [PATCH 0338/4847] Tidy up some unused code --- test/controllers/root-controller.test.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/test/controllers/root-controller.test.js b/test/controllers/root-controller.test.js index cc91a6a482..9f1c36c666 100644 --- a/test/controllers/root-controller.test.js +++ b/test/controllers/root-controller.test.js @@ -115,7 +115,7 @@ describe('RootController', function() { ['git', 'github'].forEach(function(tabName) { describe(`${tabName} tab tracker`, function() { - let wrapper, tabTracker, mockDockItem; + let wrapper, tabTracker; beforeEach(async function() { const workdirPath = await cloneRepository('multiple-commits'); @@ -128,19 +128,7 @@ describe('RootController', function() { sinon.stub(tabTracker, 'focus'); sinon.spy(workspace.getActivePane(), 'activate'); - const FAKE_PANE_ITEM = Symbol('fake pane item'); - mockDockItem = { - getDockItem() { - return FAKE_PANE_ITEM; - }, - }; - - wrapper.instance()[`${tabName}DockItem`] = mockDockItem; - sinon.stub(workspace.getRightDock(), 'isVisible').returns(true); - sinon.stub(workspace.getRightDock(), 'getPanes').callsFake(() => [{ - getActiveItem() { return mockDockItem.active ? FAKE_PANE_ITEM : null; }, - }]); }); describe('reveal', function() { From 9ef5c07f57a6a78d30a3270ac1b96aef58e00ac5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 13:33:51 -0400 Subject: [PATCH 0339/4847] Return null if the holder isn't ready --- lib/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers.js b/lib/helpers.js index 4b9459f13b..6109ee9c0c 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -395,7 +395,7 @@ export function createItem(node, componentHolder = null, uri = null, extra = {}) const override = { getElement: () => node, - getRealItem: () => componentHolder.get(), + getRealItem: () => componentHolder.getOr(null), getRealItemPromise: () => componentHolder.getPromise(), From cba2c7474545b60d8c7ed0d53f6b1f06b5f15274 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 13:34:12 -0400 Subject: [PATCH 0340/4847] Rework initial visibility tests --- test/controllers/root-controller.test.js | 54 +++++++++--------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/test/controllers/root-controller.test.js b/test/controllers/root-controller.test.js index 9f1c36c666..b4413ef002 100644 --- a/test/controllers/root-controller.test.js +++ b/test/controllers/root-controller.test.js @@ -8,6 +8,8 @@ import dedent from 'dedent-js'; import {cloneRepository, buildRepository} from '../helpers'; import {GitError} from '../../lib/git-shell-out-strategy'; import Repository from '../../lib/models/repository'; +import GitTabItem from '../../lib/items/git-tab-item'; +import GithubTabController from '../../lib/controllers/github-tab-controller'; import ResolutionProgress from '../../lib/models/conflicts/resolution-progress'; import RootController from '../../lib/controllers/root-controller'; @@ -64,52 +66,34 @@ describe('RootController', function() { atomEnv.destroy(); }); - describe('initial panel visibility', function() { - let gitTabStubItem, githubTabStubItem; - beforeEach(function() { - const FAKE_PANE_ITEM = Symbol('fake pane item'); - gitTabStubItem = { - getDockItem() { - return FAKE_PANE_ITEM; - }, - }; - githubTabStubItem = { - getDockItem() { - return FAKE_PANE_ITEM; - }, - }; - }); - - it('is rendered but not activated when startOpen prop is false', async function() { + describe('initial dock item visibility', function() { + it('is not activated when startOpen prop is false', async function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); - app = React.cloneElement(app, {repository, gitTabStubItem, githubTabStubItem, startOpen: false}); - const wrapper = shallow(app); + app = React.cloneElement(app, {repository, startOpen: false}); + const wrapper = mount(app); - const gitDockItem = wrapper.find('DockItem').find({stubItem: gitTabStubItem}); - assert.isTrue(gitDockItem.exists()); - assert.isFalse(gitDockItem.prop('activate')); + assert.isFalse(wrapper.update().find('GitTabItem').exists()); + assert.isUndefined(workspace.paneForURI(GitTabItem.buildURI())); + assert.isFalse(wrapper.update().find('GithubTabController').exists()); + assert.isUndefined(workspace.paneForURI(GithubTabController.buildURI())); - const githubDockItem = wrapper.find('DockItem').find({stubItem: githubTabStubItem}); - assert.isTrue(githubDockItem.exists()); - assert.isNotTrue(githubDockItem.prop('activate')); + assert.isUndefined(workspace.getActivePaneItem()); + assert.isFalse(workspace.getRightDock().isVisible()); }); - it('is initially activated when the startOpen prop is true', async function() { + it('is initially visible, but not focused, when the startOpen prop is true', async function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); - app = React.cloneElement(app, {repository, gitTabStubItem, githubTabStubItem, startOpen: true}); - const wrapper = shallow(app); - - const gitDockItem = wrapper.find('DockItem').find({stubItem: gitTabStubItem}); - assert.isTrue(gitDockItem.exists()); - assert.isTrue(gitDockItem.prop('activate')); + app = React.cloneElement(app, {repository, startOpen: true}); + const wrapper = mount(app); - const githubDockItem = wrapper.find('DockItem').find({stubItem: githubTabStubItem}); - assert.isTrue(githubDockItem.exists()); - assert.isNotTrue(githubDockItem.prop('activate')); + await assert.async.isTrue(workspace.getRightDock().isVisible()); + assert.isTrue(wrapper.find('GitTabItem').exists()); + assert.isTrue(wrapper.find('GithubTabController').exists()); + assert.isUndefined(workspace.getActivePaneItem()); }); }); From bed5a93a1e1e58e1f194055667e3a982f7ba5468 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 13:34:27 -0400 Subject: [PATCH 0341/4847] Remove unused import --- lib/controllers/root-controller.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 260d08df3d..6818137e28 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -23,7 +23,6 @@ import RepositoryConflictController from './repository-conflict-controller'; import GithubLoginModel from '../models/github-login-model'; import GitCacheView from '../views/git-cache-view'; import Conflict from '../models/conflicts/conflict'; -import RefHolder from '../models/ref-holder'; import Switchboard from '../switchboard'; import {destroyFilePatchPaneItems, destroyEmptyFilePatchPaneItems, autobind} from '../helpers'; import {GitError} from '../git-shell-out-strategy'; From ebffd5d71b779411d37acd6d789bd018b25bbc7a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 13:34:36 -0400 Subject: [PATCH 0342/4847] Use buildURI() helpers --- lib/controllers/root-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 6818137e28..e9216ffeab 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -82,12 +82,12 @@ export default class RootController extends React.Component { }; this.gitTabTracker = new TabTracker('git', { - uri: 'atom-github://dock-item/git', + uri: GitTabItem.buildURI(), getWorkspace: () => this.props.workspace, }); this.githubTabTracker = new TabTracker('github', { - uri: 'atom-github://dock-item/github', + uri: GithubTabController.buildURI(), getWorkspace: () => this.props.workspace, }); From 6a0a5c5aef77f2a305102e4d47f3c7b3acecf86e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 13:34:49 -0400 Subject: [PATCH 0343/4847] Actually return the GithubTabController component --- lib/controllers/root-controller.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index e9216ffeab..3faa5e9f65 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -288,14 +288,14 @@ export default class RootController extends React.Component { - {({itemHolder}) => { + {({itemHolder}) => ( ; - }} + /> + )} Date: Fri, 22 Jun 2018 13:35:22 -0400 Subject: [PATCH 0344/4847] Open but don't focus Git and GitHub tabs on first run --- lib/controllers/root-controller.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 3faa5e9f65..7b60ed20ec 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -96,6 +96,10 @@ export default class RootController extends React.Component { ); } + componentDidMount() { + this.openTabs(); + } + render() { return ( @@ -342,6 +346,25 @@ export default class RootController extends React.Component { ); } + async openTabs() { + if (this.props.startOpen) { + await Promise.all([ + this.gitTabTracker.ensureRendered(false), + this.githubTabTracker.ensureRendered(false), + ]); + + const docks = new Set( + [GitTabItem.buildURI(), GithubTabController.buildURI()] + .map(uri => this.props.workspace.paneContainerForURI(uri)) + .filter(container => container && (typeof container.show) === 'function'), + ); + + for (const dock of docks) { + dock.show(); + } + } + } + installReactDevTools() { // Prevent electron-link from attempting to descend into electron-devtools-installer, which is not available // when we're bundled in Atom. @@ -758,6 +781,10 @@ class TabTracker { return false; } + ensureRendered(activated) { + return this.getWorkspace().open(this.uri, {searchAllPanes: true, activated, activatePane: false}); + } + reveal() { return this.getWorkspace().open(this.uri, {searchAllPanes: true, activateItem: true, activatePane: true}); } From 3a3ef5d36f21d22d6c193b9c6a1f753d99c42280 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 13:43:44 -0400 Subject: [PATCH 0345/4847] Use a PaneItem in the GitTabItem tests --- test/items/git-tab-item.test.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/test/items/git-tab-item.test.js b/test/items/git-tab-item.test.js index b0090a4151..da0a0ef1b2 100644 --- a/test/items/git-tab-item.test.js +++ b/test/items/git-tab-item.test.js @@ -1,10 +1,8 @@ import React from 'react'; import {mount} from 'enzyme'; -import until from 'test-until'; -import DockItem from '../../lib/atom/dock-item'; +import PaneItem from '../../lib/atom/pane-item'; import GitTabItem from '../../lib/items/git-tab-item'; -import RefHolder from '../../lib/models/ref-holder'; import {cloneRepository, buildRepository} from '../helpers'; import {gitTabItemProps} from '../fixtures/props/git-tab-props'; @@ -24,32 +22,34 @@ describe('GitTabItem', function() { function buildApp(overrideProps = {}) { const props = gitTabItemProps(atomEnv, repository, overrideProps); - const itemHolder = new RefHolder(); return ( - - - + + {({itemHolder}) => ( + + )} + ); } - it('forwards all props to the GitTabContainer', function() { + it('forwards all props to the GitTabContainer', async function() { const extraProp = Symbol('extra'); const wrapper = mount(buildApp({extraProp})); + await atomEnv.workspace.open(GitTabItem.buildURI()); - assert.strictEqual(wrapper.find('GitTabContainer').prop('extraProp'), extraProp); + assert.strictEqual(wrapper.update().find('GitTabContainer').prop('extraProp'), extraProp); }); it('renders within the dock with the component as its owner', async function() { mount(buildApp()); - let paneItem; - await until('the item is opened', () => { - paneItem = atomEnv.workspace.getRightDock().getPaneItems() - .find(item => item.getURI() === 'atom-github://dock-item/git'); - return paneItem !== undefined; - }); + await atomEnv.workspace.open(GitTabItem.buildURI()); + const paneItem = atomEnv.workspace.getRightDock().getPaneItems() + .find(item => item.getURI() === 'atom-github://dock-item/git'); assert.strictEqual(paneItem.getTitle(), 'Git'); }); }); From 20606933772913696e0534653e12f3a4eabdecdd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 13:43:54 -0400 Subject: [PATCH 0346/4847] Add missing prop to gitTabItem props --- test/fixtures/props/git-tab-props.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/fixtures/props/git-tab-props.js b/test/fixtures/props/git-tab-props.js index 1e949dc19a..daa570bcd5 100644 --- a/test/fixtures/props/git-tab-props.js +++ b/test/fixtures/props/git-tab-props.js @@ -1,10 +1,13 @@ import ResolutionProgress from '../../../lib/models/conflicts/resolution-progress'; +import {InMemoryStrategy} from '../../../lib/shared/keytar-strategy'; +import GithubLoginModel from '../../../lib/models/github-login-model'; function noop() {} export function gitTabItemProps(atomEnv, repository, overrides = {}) { return { repository, + loginModel: new GithubLoginModel(InMemoryStrategy), workspace: atomEnv.workspace, commandRegistry: atomEnv.commands, grammars: atomEnv.grammars, From 9bb89e73b818df231bcff88fe67c03cc24572035 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 13:59:51 -0400 Subject: [PATCH 0347/4847] Remote unused opener --- lib/github-package.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/github-package.js b/lib/github-package.js index 1223b648ae..7c83eb7a35 100644 --- a/lib/github-package.js +++ b/lib/github-package.js @@ -175,15 +175,6 @@ export default class GithubPackage { } `, ), - this.workspace.addOpener(uri => { - if (uri.startsWith('atom-github://dock-item/')) { - const item = this.createDockItemStub({uri}); - this.rerender(); - return item; - } else { - return null; - } - }), atom.contextMenu.add({ '.github-UnstagedChanges .github-FilePatchListView': [ { From 75927cf48a94e2f359632f2388ab558dc45d54d4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 14:23:06 -0400 Subject: [PATCH 0348/4847] Apply a className to a PaneItem's root DOM element --- lib/atom/pane-item.js | 11 +++++++++++ test/atom/pane-item.test.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/lib/atom/pane-item.js b/lib/atom/pane-item.js index 6e528185e8..dca80ee487 100644 --- a/lib/atom/pane-item.js +++ b/lib/atom/pane-item.js @@ -34,6 +34,7 @@ export default class PaneItem extends React.Component { workspace: PropTypes.object.isRequired, children: PropTypes.func.isRequired, uriPattern: PropTypes.string.isRequired, + className: PropTypes.string, } constructor(props) { @@ -76,6 +77,9 @@ export default class PaneItem extends React.Component { openItem.hydrateStub({ copy: () => this.copyOpenItem(openItem), }); + if (this.props.className) { + openItem.addClassName(this.props.className); + } } this.subs.add(this.props.workspace.addOpener(this.opener)); @@ -102,6 +106,9 @@ export default class PaneItem extends React.Component { } const openItem = new OpenItem(m); + if (this.props.className) { + openItem.addClassName(this.props.className); + } return new Promise(resolve => { this.setState(prevState => ({ @@ -184,6 +191,10 @@ class OpenItem { } } + addClassName(className) { + this.domNode.classList.add(className); + } + getKey() { return this.id; } diff --git a/test/atom/pane-item.test.js b/test/atom/pane-item.test.js index 83cda3d6d1..47cdac10d1 100644 --- a/test/atom/pane-item.test.js +++ b/test/atom/pane-item.test.js @@ -105,6 +105,17 @@ describe('PaneItem', function() { assert.strictEqual(item.getTitle(), 'Component with: a prop'); }); + it('adds a CSS class to the root element', async function() { + mount( + + {({itemHolder}) => } + , + ); + + const item = await workspace.open('atom-github://pattern'); + assert.isTrue(item.getElement().classList.contains('root')); + }); + it('renders a child item', async function() { const wrapper = mount( @@ -240,5 +251,22 @@ describe('PaneItem', function() { assert.strictEqual(stub.getText(), '10'); }); + + it('adds a CSS class to the stub root', function() { + const stub = StubItem.create( + 'some-component', + {title: 'Component'}, + 'atom-github://pattern/root/10', + ); + workspace.getActivePane().addItem(stub); + + mount( + + {({params, itemHolder}) => } + , + ); + + assert.isTrue(stub.getElement().classList.contains('added')); + }); }); }); From 0b100ec4743e1e459d1630e661cb5a99def5e328 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 14:24:03 -0400 Subject: [PATCH 0349/4847] Rename git-panel.less to match the component name --- styles/{git-panel.less => git-tab-item.less} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename styles/{git-panel.less => git-tab-item.less} (100%) diff --git a/styles/git-panel.less b/styles/git-tab-item.less similarity index 100% rename from styles/git-panel.less rename to styles/git-tab-item.less From da067cfc734b2acb3e23b3202d10a8b7eee921d2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Jun 2018 14:34:35 -0400 Subject: [PATCH 0350/4847] Set a CSS class on the stub or created DOM node --- lib/controllers/root-controller.js | 6 ++++-- styles/git-tab-item.less | 3 ++- styles/github-controller.less | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 7b60ed20ec..bf48f724f0 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -265,7 +265,8 @@ export default class RootController extends React.Component { + uriPattern={GitTabItem.uriPattern} + className="github-GitTabItem-root"> {({itemHolder}) => ( + uriPattern={GithubTabController.uriPattern} + className="github-GithubTabController-root"> {({itemHolder}) => ( Date: Fri, 22 Jun 2018 14:37:42 -0400 Subject: [PATCH 0351/4847] :fire: DockItem --- lib/atom/dock-item.js | 139 ------------------------------------------ 1 file changed, 139 deletions(-) delete mode 100644 lib/atom/dock-item.js diff --git a/lib/atom/dock-item.js b/lib/atom/dock-item.js deleted file mode 100644 index 1fb149b017..0000000000 --- a/lib/atom/dock-item.js +++ /dev/null @@ -1,139 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import PropTypes from 'prop-types'; -import {CompositeDisposable} from 'event-kit'; - -import {createItem} from '../helpers'; -import {RefHolderPropType} from '../prop-types'; - -/** - * `DockItem` adds its child to an Atom dock when rendered. When the item is closed, the component's `onDidCloseItem` is - * called. You should use this callback to set state so that the `DockItem` is no longer rendered; you will get an error - * in your console if you forget. - * - * Unmounting the component when the item is open will close the item. - */ -export default class DockItem extends React.Component { - static propTypes = { - workspace: PropTypes.object.isRequired, - children: PropTypes.element.isRequired, - onDidCloseItem: PropTypes.func, - stubItem: PropTypes.object, - itemHolder: RefHolderPropType, - activate: PropTypes.bool, - } - - static defaultProps = { - onDidCloseItem: () => {}, - } - - constructor(props) { - super(props); - - this.subscriptions = new CompositeDisposable(); - this.dockItem = null; - this.didCloseItem = false; - if (props.stubItem) { - this.domNode = this.props.stubItem.getElement(); - } else { - this.domNode = document.createElement('div'); - this.domNode.className = 'react-atom-dockitem'; - } - } - - componentDidMount() { - this.setupDockItem(); - } - - componentDidUpdate() { - if (this.didCloseItem) { - // eslint-disable-next-line no-console - console.error('Unexpected update in `DockItem`: the contained item has been closed'); - } - } - - render() { - return ReactDOM.createPortal( - this.props.children, - this.domNode, - ); - } - - setupDockItem() { - if (this.dockItem) { return; } - - const itemToAdd = createItem(this.domNode, this.props.itemHolder); - - if (itemToAdd.wasActivated) { - this.subscriptions.add( - this.props.workspace.onDidChangeActivePaneItem(activeItem => { - if (activeItem === this.dockItem) { - itemToAdd.wasActivated(() => { - return this.props.workspace.getActivePaneItem() === this.dockItem; - }); - } - }), - ); - } - - const stub = this.props.stubItem; - if (stub) { - stub.setRealItem(itemToAdd); - this.dockItem = stub; - if (this.props.activate) { - this.activate(); - } - } else { - Promise.resolve(this.props.workspace.open(itemToAdd, {activatePane: false})) - .then(item => { - this.dockItem = item; - if (this.props.activate) { this.activate(); } - }); - } - - this.subscriptions.add( - this.props.workspace.onDidDestroyPaneItem(({item}) => { - if (item === this.dockItem) { - this.didCloseItem = true; - this.props.onDidCloseItem(this.dockItem); - } - }), - ); - } - - componentWillUnmount() { - this.subscriptions.dispose(); - - if (this.dockItem && !this.didCloseItem) { - const pane = this.props.workspace.paneForItem(this.dockItem); - if (this.dockItem.destroy) { - this.dockItem.destroy(); - } - pane.destroyItem(this.dockItem); - } - } - - getDockItem() { - return this.dockItem; - } - - activate() { - setTimeout(() => { - if (!this.dockItem || this.didCloseItem || this.props.workspace.isDestroyed()) { - return; - } - - const pane = this.props.workspace.paneForItem(this.dockItem); - if (pane) { - pane.activateItem(this.dockItem); - const dock = this.props.workspace.getPaneContainers() - .find(container => container.getPanes().find(p => p.getItems().includes(this.dockItem))); - if (dock && dock.show) { - dock.show(); - } - } else if (this.dockItem && !this.didCloseItem) { - throw new Error('Could not find pane for a non-destroyed DockItem'); - } - }); - } -} From e137eeb01b9c6345d938110014292ab1863e545a Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sat, 23 Jun 2018 16:21:38 +0000 Subject: [PATCH 0352/4847] chore(package): update babel-eslint to version 8.2.5 Closes #1548 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 963b6e22cd..dddc3e5afa 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "devDependencies": { "@smashwilson/enzyme-adapter-react-16": "1.0.2", "atom-mocha-test-runner": "1.2.0", - "babel-eslint": "8.2.3", + "babel-eslint": "8.2.5", "babel-plugin-istanbul": "4.1.6", "chai": "4.1.2", "chai-as-promised": "7.1.1", From 9f6ac03cec9f47cef31956315926ec57e566af89 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sun, 24 Jun 2018 19:05:59 +0000 Subject: [PATCH 0353/4847] chore(package): update sinon to version 6.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 963b6e22cd..e58ae43530 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "node-fetch": "2.1.2", "nyc": "13.0.0", "relay-compiler": "1.6.0", - "sinon": "6.0.0", + "sinon": "6.0.1", "test-until": "1.1.1" }, "consumedServices": { From d5779102af1d3235d490fdf86cbd35cc16eb899e Mon Sep 17 00:00:00 2001 From: simurai Date: Mon, 25 Jun 2018 13:03:09 +0900 Subject: [PATCH 0354/4847] Rename PrPaneItem -> IssueishPaneItemView Same as JS class --- lib/containers/issueish-pane-item-container.js | 4 ++-- styles/_global.less | 1 - styles/{pr-pane-item.less => issueish-pane-item-view.less} | 6 +++++- 3 files changed, 7 insertions(+), 4 deletions(-) rename styles/{pr-pane-item.less => issueish-pane-item-view.less} (97%) diff --git a/lib/containers/issueish-pane-item-container.js b/lib/containers/issueish-pane-item-container.js index eac4c49228..3e8e7091a4 100644 --- a/lib/containers/issueish-pane-item-container.js +++ b/lib/containers/issueish-pane-item-container.js @@ -91,8 +91,8 @@ export class IssueishPaneItemView extends React.Component { pullRequest: issueish.__typename === 'PullRequest' ? issueish : null, }; return ( -
    -
    +
    +
    diff --git a/styles/_global.less b/styles/_global.less index 691318a366..68b39b5be3 100644 --- a/styles/_global.less +++ b/styles/_global.less @@ -3,7 +3,6 @@ // Styles for things that are sprinkled throuout various places // vertical align the text with the icon -.github-PrPaneItem, .tooltip { .badge .icon:before { vertical-align: text-top; diff --git a/styles/pr-pane-item.less b/styles/issueish-pane-item-view.less similarity index 97% rename from styles/pr-pane-item.less rename to styles/issueish-pane-item-view.less index ceba84b91d..0b895a2fc4 100644 --- a/styles/pr-pane-item.less +++ b/styles/issueish-pane-item-view.less @@ -1,6 +1,6 @@ @import 'variables'; -.github-PrPaneItem { +.github-IssueishPaneItemView { padding: @component-padding * 3; overflow: auto; position: absolute; @@ -165,6 +165,10 @@ // Elements ------------------------ + .badge .icon:before { + vertical-align: text-top; + } + blockquote { font-size: inherit; padding-top: 0; From 94349d47dc779fd4f7028cdeef328c3b673f9fc9 Mon Sep 17 00:00:00 2001 From: simurai Date: Mon, 25 Jun 2018 17:57:38 +0900 Subject: [PATCH 0355/4847] Rename header classes --- .../issueish-pane-item-container.js | 38 +++++----- styles/issueish-pane-item-view.less | 71 +++++++++++-------- 2 files changed, 61 insertions(+), 48 deletions(-) diff --git a/lib/containers/issueish-pane-item-container.js b/lib/containers/issueish-pane-item-container.js index 3e8e7091a4..85ca18d2e1 100644 --- a/lib/containers/issueish-pane-item-container.js +++ b/lib/containers/issueish-pane-item-container.js @@ -93,28 +93,30 @@ export class IssueishPaneItemView extends React.Component { return (
    -
    - - - {repo.owner.login}/{repo.name}#{issueish.number} - - {isPr && - - } - +
    + +
    - -
    -
    - - - -

    {issueish.title}

    -
    +
    +
    + + + +

    {issueish.title}

    +
    + No description provided.'} switchToIssueish={this.props.switchToIssueish} diff --git a/styles/issueish-pane-item-view.less b/styles/issueish-pane-item-view.less index 0b895a2fc4..2595cae05e 100644 --- a/styles/issueish-pane-item-view.less +++ b/styles/issueish-pane-item-view.less @@ -22,62 +22,73 @@ margin: 0 auto; } - // Badge and link ------------------------ - .issueish-badge-and-link { + + // Header ------------------------ + + &-header { + display: flex; // TODO: Use grid + justify-content: space-between; + flex-wrap: wrap; + border-bottom: 1px solid @base-border-color; + margin-bottom: @component-padding; + } + + &-headerGroup { display: flex; align-items: center; - margin-bottom: @component-padding * 2; + margin-bottom: @component-padding; - :last-child { - flex: 1; - text-align: right; + &.is-fullWidth { + flex: 1 1 100%; } } - .issueish-link a { + &-headerLink { color: @text-color-subtle; } - .pr-build-status-icon { + &-headerStatus { margin-left: @component-padding; } - .refresh-button { - .icon { - color: @text-color-subtle; - cursor: pointer; - &.refreshing::before { - @keyframes github-RefreshButton-animation { - 100% { transform: rotate(360deg); } - } - animation: github-RefreshButton-animation 2s linear 30; // limit to 1min in case something gets stuck + // Refresh Button ------------------------ + + &-headerRefreshButton { + color: @text-color-subtle; + cursor: pointer; + + &::before { + display: block; + width: 16px; + height: 16px; + line-height: .9; + margin-right: 0; + text-align: center; + } + &.refreshing::before { + @keyframes github-IssueishPaneItemView-headerRefreshButtonAnimation { + 100% { transform: rotate(360deg); } } + animation: github-IssueishPaneItemView-headerRefreshButtonAnimation 2s linear 30; // limit to 1min in case something gets stuck } } // Avatar and title ------------------------ - .issueish-avatar-and-title { - display: flex; - align-items: center; - margin-bottom: @component-padding * 2; - padding-bottom: @component-padding; - border-bottom: 1px solid @base-border-color; - } - - .author-avatar-link { + &-avatar { margin-right: @component-padding; - align-self: flex-start; } - .author-avatar { - max-height: 32px; + &-avatarImage { + width: 32px; + height: 32px; border-radius: @component-border-radius; } - .issueish-title { + &-title { + display: inline-block; margin: 0; font-size: 1.5em; font-weight: 500; From 5e1cecdfe928e4c94ca990c364521257daad27c1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Jun 2018 14:54:22 -0400 Subject: [PATCH 0356/4847] Accept GithubPackage arguments via a destructured object --- lib/github-package.js | 14 +++++++++++--- lib/index.js | 21 ++++++++++++++++----- test/github-package.test.js | 27 ++++++++++++++------------- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/lib/github-package.js b/lib/github-package.js index 1223b648ae..99201d1211 100644 --- a/lib/github-package.js +++ b/lib/github-package.js @@ -26,8 +26,12 @@ const defaultState = { }; export default class GithubPackage { - constructor(workspace, project, commandRegistry, notificationManager, tooltips, styles, grammars, confirm, config, - deserializers, configDirPath, getLoadSettings) { + constructor({ + workspace, project, commandRegistry, notificationManager, tooltips, styles, grammars, config, deserializers, + confirm, getLoadSettings, + configDirPath, + renderFn, + }) { autobind( this, 'consumeStatusBar', 'createGitTimingsView', 'createIssueishPaneItemStub', 'createDockItemStub', @@ -71,6 +75,10 @@ export default class GithubPackage { this.switchboard = new Switchboard(); + this.renderFn = renderFn || ((component, node, callback) => { + return ReactDom.render(component, node, callback); + }); + // Handle events from all resident contexts. this.subscriptions = new CompositeDisposable( this.contextPool.onDidChangeWorkdirOrHead(context => { @@ -264,7 +272,7 @@ export default class GithubPackage { })); } - ReactDom.render( + this.renderFn( { this.controller = c; }} workspace={this.workspace} diff --git a/lib/index.js b/lib/index.js index c463e6843e..499e6996ca 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,11 +3,22 @@ import GithubPackage from './github-package'; let pack; const entry = { initialize() { - pack = new GithubPackage( - atom.workspace, atom.project, atom.commands, atom.notifications, atom.tooltips, - atom.styles, atom.grammars, atom.confirm.bind(atom), atom.config, atom.deserializers, atom.getConfigDirPath(), - atom.getLoadSettings.bind(atom), - ); + pack = new GithubPackage({ + workspace: atom.workspace, + project: atom.project, + commandRegistry: atom.commands, + notificationManager: atom.notificationManager, + tooltips: atom.tooltips, + styles: atom.styles, + grammars: atom.grammars, + config: atom.config, + deserializers: atom.deserializers, + + confirm: atom.confirm.bind(atom), + getLoadSettings: atom.getLoadSettings.bind(atom), + + configDirPath: atom.getConfigDirPath(), + }); }, }; diff --git a/test/github-package.test.js b/test/github-package.test.js index 44b1f57e64..40ac35b40a 100644 --- a/test/github-package.test.js +++ b/test/github-package.test.js @@ -29,15 +29,15 @@ describe('GithubPackage', function() { getLoadSettings = atomEnv.getLoadSettings.bind(atomEnv); configDirPath = path.join(__dirname, 'fixtures', 'atomenv-config'); - githubPackage = new GithubPackage( - workspace, project, commandRegistry, notificationManager, tooltips, styles, grammars, confirm, config, - deserializers, configDirPath, getLoadSettings, - ); - - sinon.stub(githubPackage, 'rerender').callsFake(callback => { - if (callback) { - process.nextTick(callback); - } + githubPackage = new GithubPackage({ + workspace, project, commandRegistry, notificationManager, tooltips, styles, grammars, config, deserializers, + confirm, getLoadSettings, + configDirPath, + renderFn: sinon.stub().callsFake(callback => { + if (callback) { + process.nextTick(callback); + } + }), }); contextPool = githubPackage.getContextPool(); @@ -72,10 +72,11 @@ describe('GithubPackage', function() { project.setPaths(realProjectPaths); const getLoadSettings1 = () => ({initialPaths}); - githubPackage1 = new GithubPackage( - workspace, project, commandRegistry, notificationManager, tooltips, styles, grammars, confirm, config, - deserializers, configDirPath, getLoadSettings1, - ); + githubPackage1 = new GithubPackage({ + workspace, project, commandRegistry, notificationManager, tooltips, styles, grammars, config, deserializers, + confirm, getLoadSettings1, + configDirPath, + }); } function assertAbsentLike() { From da8c7b4a65375da40b280d37d8614d468864419e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Jun 2018 15:02:48 -0400 Subject: [PATCH 0357/4847] Expect correct arguments in render mock --- test/github-package.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/github-package.test.js b/test/github-package.test.js index 40ac35b40a..170ca9823f 100644 --- a/test/github-package.test.js +++ b/test/github-package.test.js @@ -33,7 +33,7 @@ describe('GithubPackage', function() { workspace, project, commandRegistry, notificationManager, tooltips, styles, grammars, config, deserializers, confirm, getLoadSettings, configDirPath, - renderFn: sinon.stub().callsFake(callback => { + renderFn: sinon.stub().callsFake((component, element, callback) => { if (callback) { process.nextTick(callback); } From a9af2995bbb8472922dabf22ebc9430e30fec0ee Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Jun 2018 15:18:10 -0400 Subject: [PATCH 0358/4847] Stub out launch tests --- test/integration/helpers.js | 63 +++++++++++++++++++++++++++++++++ test/integration/launch.test.js | 51 ++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 test/integration/helpers.js create mode 100644 test/integration/launch.test.js diff --git a/test/integration/helpers.js b/test/integration/helpers.js new file mode 100644 index 0000000000..0c1a992808 --- /dev/null +++ b/test/integration/helpers.js @@ -0,0 +1,63 @@ +import {mount} from 'enzyme'; + +import GithubPackage from '../../lib/github-package'; + +/** + * Perform shared setup for integration tests. + * + * Usage: + * ```js + * beforeEach(function() { + * context = setup(this.currentTest); + * wrapper = context.wrapper; + * }) + * + * afterEach(function() { + * teardown(context) + * }) + * ``` + * + */ +export function setup(currentTest) { + const atomEnv = global.buildAtomEnvironment(); + + let domRoot = null; + let wrapper = null; + + const githubPackage = new GithubPackage({ + workspace: atomEnv.workspace, + project: atomEnv.projects, + commandRegistry: atomEnv.commands, + notificationManager: atomEnv.notifications, + tooltips: atomEnv.tooltips, + styles: atomEnv.styles, + grammars: atomEnv.grammars, + config: atomEnv.config, + deserializers: atomEnv.deserializers, + confirm: atomEnv.confirm.bind(atomEnv), + getLoadSettings: atom.getLoadSettings.bind(atomEnv), + configDirPath: atom.getConfigDirPath(), + renderFn: (component, node, callback) => { + if (!domRoot && node) { + domRoot = node; + } + wrapper = mount(component, { + attachTo: node, + }); + process.nextTick(callback); + }, + }); + + return { + atomEnv, + githubPackage, + wrapper, + domRoot, + }; +} + +export async function teardown(context) { + context.atomEnv.destroy(); + + await context.githubPackage.deactivate(); +} diff --git a/test/integration/launch.test.js b/test/integration/launch.test.js new file mode 100644 index 0000000000..be1c73c3c8 --- /dev/null +++ b/test/integration/launch.test.js @@ -0,0 +1,51 @@ +import {setup, teardown} from './helpers'; + +describe('Package initialization', function() { + let context, wrapper, atom; + + beforeEach(function() { + context = setup(this.currentTest); + wrapper = context.wrapper; + atom = context.atom; + }); + + afterEach(async function() { + await teardown(this.currentTest); + }); + + describe('on the very first run with the GitHub package present', function() { + describe('with no serialized project state', function() { + describe('with the welcome package active', function() { + it('places the git and github tabs into the right dock'); + + it('hides the right dock'); + }); + + describe('with the welcome package dismissed', function() { + it('places the git and github tabs into the right dock'); + + it('reveals the right dock'); + }); + }); + + describe('with serialized project state', function() { + it('keeps previously closed git and github tabs closed'); + + it('keeps previously open git and github tabs opened'); + }); + }); + + describe('on a run when the GitHub package was present before', function() { + describe('with no serialized project state', function() { + it('places the git and github tabs into the right dock'); + + it('hides the right dock'); + }); + + describe('with serialized project state', function() { + it('keeps previously closed git and github tabs closed'); + + it('keeps previously open git and github tabs opened'); + }); + }); +}); From c52f2ea39c185ef7acc468b1b29a25a29a2d6553 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Jun 2018 15:19:08 -0400 Subject: [PATCH 0359/4847] Passing arguments is hard --- test/github-package.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/github-package.test.js b/test/github-package.test.js index 170ca9823f..badb23d242 100644 --- a/test/github-package.test.js +++ b/test/github-package.test.js @@ -74,7 +74,7 @@ describe('GithubPackage', function() { githubPackage1 = new GithubPackage({ workspace, project, commandRegistry, notificationManager, tooltips, styles, grammars, config, deserializers, - confirm, getLoadSettings1, + confirm, getLoadSettings: getLoadSettings1, configDirPath, }); } From b4c1e8818a60501c80100881fe5f201345a03b29 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Jun 2018 10:28:02 +0900 Subject: [PATCH 0360/4847] Fix linter warnings --- lib/containers/issueish-pane-item-container.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/containers/issueish-pane-item-container.js b/lib/containers/issueish-pane-item-container.js index 85ca18d2e1..5560aeac1f 100644 --- a/lib/containers/issueish-pane-item-container.js +++ b/lib/containers/issueish-pane-item-container.js @@ -106,13 +106,16 @@ export class IssueishPaneItemView extends React.Component {
    - +

    {issueish.title}

    From 4168ec364ab1081e8f034550aa9a0c6a25a6770f Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Jun 2018 10:32:54 +0900 Subject: [PATCH 0361/4847] :fire: Remove issueish-body Seems un-used --- styles/issueish-pane-item-view.less | 9 --------- 1 file changed, 9 deletions(-) diff --git a/styles/issueish-pane-item-view.less b/styles/issueish-pane-item-view.less index 2595cae05e..59a8a99fe1 100644 --- a/styles/issueish-pane-item-view.less +++ b/styles/issueish-pane-item-view.less @@ -99,15 +99,6 @@ // Body ------------------------ - .issueish-body { - padding-top: @component-padding; - border-top: 1px solid @base-border-color; - - & > *:first-child { - margin-top: 0; - } - } - .github-DotComMarkdownHtml { a { color: @text-color-info; From b3b9dc8269e3b7a91d062818ebd0e13916e9d89b Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Jun 2018 10:56:08 +0900 Subject: [PATCH 0362/4847] Add some space To easier see what belongs together --- lib/containers/issueish-pane-item-container.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/containers/issueish-pane-item-container.js b/lib/containers/issueish-pane-item-container.js index 5560aeac1f..d8908035d0 100644 --- a/lib/containers/issueish-pane-item-container.js +++ b/lib/containers/issueish-pane-item-container.js @@ -93,6 +93,7 @@ export class IssueishPaneItemView extends React.Component { return (
    +
    @@ -120,10 +121,12 @@ export class IssueishPaneItemView extends React.Component {

    {issueish.title}

    + No description provided.'} switchToIssueish={this.props.switchToIssueish} /> +
    {issueish.reactionGroups.map(group => ( group.users.totalCount > 0 @@ -133,6 +136,7 @@ export class IssueishPaneItemView extends React.Component { : null ))}
    + {isPr ? } + {isPr &&
    } +
    ); From 4b2f809ca7fe446581f8b46fc3b30bc8c3b7991c Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Jun 2018 10:57:08 +0900 Subject: [PATCH 0363/4847] Move .github-DotComMarkdownHtml into its own file Since it's its own "component" --- styles/_global.less | 10 ------ styles/github-dotcom-markdown.less | 49 +++++++++++++++++++++++++++++ styles/issueish-pane-item-view.less | 42 ------------------------- 3 files changed, 49 insertions(+), 52 deletions(-) create mode 100644 styles/github-dotcom-markdown.less diff --git a/styles/_global.less b/styles/_global.less index 68b39b5be3..00196e9b03 100644 --- a/styles/_global.less +++ b/styles/_global.less @@ -9,16 +9,6 @@ } } -// indent task lists -.github-DotComMarkdownHtml .task-list-item { - list-style: none; - .task-list-item-checkbox { - position: absolute; - margin-left: -20px; - } -} - - .issueish-badge, .issueish-badge.badge { align-self: flex-start; flex-shrink: 0; diff --git a/styles/github-dotcom-markdown.less b/styles/github-dotcom-markdown.less new file mode 100644 index 0000000000..d47d338733 --- /dev/null +++ b/styles/github-dotcom-markdown.less @@ -0,0 +1,49 @@ +// This styles Markdown used in issueish panes. + +.github-DotComMarkdownHtml { + a { + color: @text-color-info; + } + + p { + line-height: 1.5; + } + + hr { + margin-top: 5px; + margin-bottom: 5px; + border-top: 1px solid @text-color; + width: 100% + } + + ul { + margin-left: -10px; + } + + ol { + margin-left: -20px; + } + + li { + font-size: .9em; + padding-top: .1em; + padding-bottom: .1em; + + li { + font-size: 1em; + } + } + + pre > code { + white-space: pre; + } + + // indent task lists + .task-list-item { + list-style: none; + .task-list-item-checkbox { + position: absolute; + margin-left: -20px; + } + } +} diff --git a/styles/issueish-pane-item-view.less b/styles/issueish-pane-item-view.less index 59a8a99fe1..7de53a5248 100644 --- a/styles/issueish-pane-item-view.less +++ b/styles/issueish-pane-item-view.less @@ -97,48 +97,6 @@ } - // Body ------------------------ - - .github-DotComMarkdownHtml { - a { - color: @text-color-info; - } - - p { - line-height: 1.5; - } - - hr { - margin-top: 5px; - margin-bottom: 5px; - border-top: 1px solid @text-color; - width: 100% - } - - ul { - margin-left: -10px; - } - - ol { - margin-left: -20px; - } - - li { - font-size: .9em; - padding-top: .1em; - padding-bottom: .1em; - - li { - font-size: 1em; - } - } - - pre > code { - white-space: pre; - } - } - - // Reactions ------------------------ .reactions { From b856bc9ac028d9dc84db8bee2cddbe860e79596b Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Jun 2018 13:24:50 +0900 Subject: [PATCH 0364/4847] Fix more linter warnings --- lib/containers/issueish-pane-item-container.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/containers/issueish-pane-item-container.js b/lib/containers/issueish-pane-item-container.js index d8908035d0..eefb796822 100644 --- a/lib/containers/issueish-pane-item-container.js +++ b/lib/containers/issueish-pane-item-container.js @@ -97,7 +97,7 @@ export class IssueishPaneItemView extends React.Component {
    - {repo.owner.login}/{repo.name}#{issueish.number} {isPr && From d401fd50c4a886a4f34179f1565fea82f73ecabc Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Jun 2018 13:59:59 +0900 Subject: [PATCH 0365/4847] Move github-IssueishBadge styles to its own file --- .../issueish-pane-item-container.js | 5 ++- lib/views/issueish-badge.js | 2 +- styles/_global.less | 31 --------------- styles/issueish-badge.less | 39 +++++++++++++++++++ styles/issueish-pane-item-view.less | 4 ++ styles/issueish-tooltip.less | 4 ++ 6 files changed, 52 insertions(+), 33 deletions(-) create mode 100644 styles/issueish-badge.less diff --git a/lib/containers/issueish-pane-item-container.js b/lib/containers/issueish-pane-item-container.js index eefb796822..28ff60d3e4 100644 --- a/lib/containers/issueish-pane-item-container.js +++ b/lib/containers/issueish-pane-item-container.js @@ -96,7 +96,10 @@ export class IssueishPaneItemView extends React.Component {
    - + {repo.owner.login}/{repo.name}#{issueish.number} diff --git a/lib/views/issueish-badge.js b/lib/views/issueish-badge.js index 42e50d76b9..fe337b7988 100644 --- a/lib/views/issueish-badge.js +++ b/lib/views/issueish-badge.js @@ -22,7 +22,7 @@ export default function IssueishBadge({type, state, ...others}) { const {className, ...otherProps} = others; return ( - + {state.toLowerCase()} diff --git a/styles/_global.less b/styles/_global.less index 00196e9b03..27f0a86e74 100644 --- a/styles/_global.less +++ b/styles/_global.less @@ -2,37 +2,6 @@ // Styles for things that are sprinkled throuout various places -// vertical align the text with the icon -.tooltip { - .badge .icon:before { - vertical-align: text-top; - } -} - -.issueish-badge, .issueish-badge.badge { - align-self: flex-start; - flex-shrink: 0; - margin-right: @component-padding; - font-weight: bold; - text-transform: capitalize; - border-radius: @component-border-radius; - - &.open { - color: contrast(@gh-background-color-green, black, white, 50%); - background-color: @gh-background-color-green; - } - - &.closed { - color: contrast(@gh-background-color-red, black, white, 50%); - background-color: @gh-background-color-red; - } - - &.merged { - color: contrast(@gh-background-color-purple, black, white, 50%); - background-color: @gh-background-color-purple; - } -} - .status-warning { color: @gh-background-color-yellow; } diff --git a/styles/issueish-badge.less b/styles/issueish-badge.less new file mode 100644 index 0000000000..33f920b392 --- /dev/null +++ b/styles/issueish-badge.less @@ -0,0 +1,39 @@ +@import 'variables'; + +// Issueish Badge +// Shows the [Open], [Closed], [Merged] state + +.github-IssueishBadge { + @space: .4em; + + display: inline-block; + padding: @space/1.5 @space; + font-size: .9em; + font-weight: 500; + line-height: 1; + text-transform: capitalize; + border-radius: @component-border-radius; + white-space: nowrap; + + .icon::before { + font-size: inherit; + width: auto; + height: auto; + margin-right: @space/2; + } + + &.open { + color: contrast(@gh-background-color-green, black, white, 50%); + background-color: @gh-background-color-green; + } + + &.closed { + color: contrast(@gh-background-color-red, black, white, 50%); + background-color: @gh-background-color-red; + } + + &.merged { + color: contrast(@gh-background-color-purple, black, white, 50%); + background-color: @gh-background-color-purple; + } +} diff --git a/styles/issueish-pane-item-view.less b/styles/issueish-pane-item-view.less index 7de53a5248..263320b1a0 100644 --- a/styles/issueish-pane-item-view.less +++ b/styles/issueish-pane-item-view.less @@ -43,6 +43,10 @@ } } + &-headerBadge { + margin-right: @component-padding; + } + &-headerLink { color: @text-color-subtle; } diff --git a/styles/issueish-tooltip.less b/styles/issueish-tooltip.less index 70107f5762..96e8dbb47b 100644 --- a/styles/issueish-tooltip.less +++ b/styles/issueish-tooltip.less @@ -30,6 +30,10 @@ color: contrast(@gh-background-color-purple, black, white, 50%); background-color: @gh-background-color-purple; } + + .icon:before { + vertical-align: text-top; + } } .issueish-title { From 0fb5eed817729b9cd54ad1f711dcb7988e3fa8b4 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Tue, 26 Jun 2018 05:59:10 +0000 Subject: [PATCH 0366/4847] chore(package): update eslint to version 5.0.1 Closes #1549 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 963b6e22cd..d9481d79f8 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "dedent-js": "1.0.1", "electron-devtools-installer": "2.2.4", "enzyme": "3.3.0", - "eslint": "4.19.1", + "eslint": "5.0.1", "eslint-config-fbjs-opensource": "1.0.0", "hock": "1.3.2", "lodash.isequal": "4.5.0", From e1c8d0ba91e03c97220b038836bc1e91d10ab5a4 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Jun 2018 15:04:03 +0900 Subject: [PATCH 0367/4847] Rename reactions --- lib/containers/issueish-pane-item-container.js | 4 ++-- styles/issueish-pane-item-view.less | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/containers/issueish-pane-item-container.js b/lib/containers/issueish-pane-item-container.js index 28ff60d3e4..c2ec166b2b 100644 --- a/lib/containers/issueish-pane-item-container.js +++ b/lib/containers/issueish-pane-item-container.js @@ -130,10 +130,10 @@ export class IssueishPaneItemView extends React.Component { switchToIssueish={this.props.switchToIssueish} /> -
    +
    {issueish.reactionGroups.map(group => ( group.users.totalCount > 0 - ? + ? {reactionTypeToEmoji[group.content]}   {group.users.totalCount} : null diff --git a/styles/issueish-pane-item-view.less b/styles/issueish-pane-item-view.less index 263320b1a0..c39fa58684 100644 --- a/styles/issueish-pane-item-view.less +++ b/styles/issueish-pane-item-view.less @@ -103,18 +103,20 @@ // Reactions ------------------------ - .reactions { - width: fit-content; - padding-top: @component-padding; - .reaction-group { + &-reactions { + margin-top: @component-padding; + + &:empty { + display: none; + } + + &Group { + display: inline-block; margin-right: @component-padding; - padding: @component-padding; + padding: @component-padding/2 @component-padding; border: 1px solid @base-border-color; border-radius: @component-border-radius; } - &:empty { - all: unset; - } } // Statuses ------------------------ From 318849c521f4977ad139d5f7faceee681a865eb0 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Jun 2018 15:33:33 +0900 Subject: [PATCH 0368/4847] Rename buildStatus --- lib/containers/issueish-pane-item-container.js | 2 +- styles/issueish-pane-item-view.less | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/containers/issueish-pane-item-container.js b/lib/containers/issueish-pane-item-container.js index c2ec166b2b..a5d0727c96 100644 --- a/lib/containers/issueish-pane-item-container.js +++ b/lib/containers/issueish-pane-item-container.js @@ -151,7 +151,7 @@ export class IssueishPaneItemView extends React.Component { /> } - {isPr &&
    + {isPr &&
    } diff --git a/styles/issueish-pane-item-view.less b/styles/issueish-pane-item-view.less index c39fa58684..dc62c86676 100644 --- a/styles/issueish-pane-item-view.less +++ b/styles/issueish-pane-item-view.less @@ -119,9 +119,10 @@ } } - // Statuses ------------------------ - .github-PrStatuses { + // Build Status ------------------------ + + &-buildStatus { margin-top: @component-padding * 4; padding: @component-padding; border: 1px solid @base-border-color; From 58cf6363de49d2fb9788dd0b2dcab731b3224bcf Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Jun 2018 16:02:13 +0900 Subject: [PATCH 0369/4847] More cleanup --- styles/github-dotcom-markdown.less | 7 +++++++ styles/issueish-pane-item-view.less | 20 -------------------- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/styles/github-dotcom-markdown.less b/styles/github-dotcom-markdown.less index d47d338733..abc1c08dfe 100644 --- a/styles/github-dotcom-markdown.less +++ b/styles/github-dotcom-markdown.less @@ -34,6 +34,13 @@ } } + blockquote { + font-size: .9em; + padding: .4em .8em; + color: @text-color-subtle; + border-left: 2px solid @base-border-color; + } + pre > code { white-space: pre; } diff --git a/styles/issueish-pane-item-view.less b/styles/issueish-pane-item-view.less index dc62c86676..d2188d4a66 100644 --- a/styles/issueish-pane-item-view.less +++ b/styles/issueish-pane-item-view.less @@ -12,11 +12,6 @@ line-height: 1.5; background-color: @base-background-color; - * { - user-select: text; - -webkit-user-select: text; - } - &-container { max-width: 48em; margin: 0 auto; @@ -129,19 +124,4 @@ border-radius: @component-border-radius; } - - // Elements ------------------------ - - .badge .icon:before { - vertical-align: text-top; - } - - blockquote { - font-size: inherit; - padding-top: 0; - padding-left: @component-padding; - padding-bottom: 0; - color: @text-color-subtle; - border-left: 2px solid @text-color-subtle; - } } From a4228b8ee0f052754c6b0f12e658917fb9536c95 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Jun 2018 16:32:01 +0900 Subject: [PATCH 0370/4847] Move PR status colors --- lib/containers/pr-statuses-container.js | 10 +++++----- styles/_global.less | 15 --------------- styles/pr-statuses.less | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 20 deletions(-) delete mode 100644 styles/_global.less diff --git a/lib/containers/pr-statuses-container.js b/lib/containers/pr-statuses-container.js index 28751be8b7..e69fdaa357 100644 --- a/lib/containers/pr-statuses-container.js +++ b/lib/containers/pr-statuses-container.js @@ -10,11 +10,11 @@ import PeriodicRefresher from '../periodic-refresher'; import {RelayConnectionPropType} from '../prop-types'; export const stateToIconAndStyle = { - EXPECTED: {category: 'PENDING', icon: 'primitive-dot', style: 'status-warning'}, - PENDING: {category: 'PENDING', icon: 'primitive-dot', style: 'status-warning'}, - SUCCESS: {category: 'SUCCESS', icon: 'check', style: 'status-success'}, - ERROR: {category: 'FAILURE', icon: 'alert', style: 'status-error'}, - FAILURE: {category: 'FAILURE', icon: 'x', style: 'status-error'}, + EXPECTED: {category: 'PENDING', icon: 'primitive-dot', style: 'github-PrStatuses--warning'}, + PENDING: {category: 'PENDING', icon: 'primitive-dot', style: 'github-PrStatuses--warning'}, + SUCCESS: {category: 'SUCCESS', icon: 'check', style: 'github-PrStatuses--success'}, + ERROR: {category: 'FAILURE', icon: 'alert', style: 'github-PrStatuses--error'}, + FAILURE: {category: 'FAILURE', icon: 'x', style: 'github-PrStatuses--error'}, }; export function category(state) { diff --git a/styles/_global.less b/styles/_global.less deleted file mode 100644 index 27f0a86e74..0000000000 --- a/styles/_global.less +++ /dev/null @@ -1,15 +0,0 @@ -@import "variables"; - -// Styles for things that are sprinkled throuout various places - -.status-warning { - color: @gh-background-color-yellow; -} - -.status-success { - color: @gh-background-color-green; -} - -.status-error { - color: @gh-background-color-red; -} diff --git a/styles/pr-statuses.less b/styles/pr-statuses.less index 7172ae8fdc..7b8838a193 100644 --- a/styles/pr-statuses.less +++ b/styles/pr-statuses.less @@ -48,4 +48,19 @@ margin-left: 5px; } } + + + // States -------------------- + + &--warning { + color: @gh-background-color-yellow; + } + + &--success { + color: @gh-background-color-green; + } + + &--error { + color: @gh-background-color-red; + } } From 48131e3fd1a8687f1dc5ddcd2b09e0c4e792c417 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Jun 2018 17:21:28 +0900 Subject: [PATCH 0371/4847] Fix lint warning --- lib/containers/issueish-pane-item-container.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/containers/issueish-pane-item-container.js b/lib/containers/issueish-pane-item-container.js index a5d0727c96..3165aafc90 100644 --- a/lib/containers/issueish-pane-item-container.js +++ b/lib/containers/issueish-pane-item-container.js @@ -133,7 +133,8 @@ export class IssueishPaneItemView extends React.Component {
    {issueish.reactionGroups.map(group => ( group.users.totalCount > 0 - ? + ? {reactionTypeToEmoji[group.content]}   {group.users.totalCount} : null From a2c2e76a853c62f68b7deaf876356f13efaa1fbf Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 10:44:49 -0400 Subject: [PATCH 0372/4847] Integration test harness work --- test/integration/helpers.js | 82 ++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 14 deletions(-) diff --git a/test/integration/helpers.js b/test/integration/helpers.js index 0c1a992808..e551e17319 100644 --- a/test/integration/helpers.js +++ b/test/integration/helpers.js @@ -1,32 +1,70 @@ import {mount} from 'enzyme'; +import {getTempDir} from '../../lib/helpers'; +import {cloneRepository} from '../helpers'; import GithubPackage from '../../lib/github-package'; +import metadata from '../../package.json'; /** * Perform shared setup for integration tests. * * Usage: * ```js - * beforeEach(function() { - * context = setup(this.currentTest); + * beforeEach(async function() { + * context = await setup(this.currentTest); * wrapper = context.wrapper; * }) * - * afterEach(function() { - * teardown(context) + * afterEach(async function() { + * await teardown(context) * }) * ``` * + * Options: + * * initialRoots - Describe the root folders that should be open in the Atom environment's project before the package + * is initialized. Array elements are passed to `cloneRepository` directly. + * * initAtomEnv - Callback invoked with the Atom environment before the package is created. + * * initConfigDir - Callback invoked with the config dir path for this Atom environment. + * * isolateConfigDir - Use a temporary directory for the package configDir used by this test. Implied if initConfigDir + * is defined. + * * state - Simulate package state serialized by a previous Atom run. */ -export function setup(currentTest) { +export async function setup(currentTest, options = {}) { + const opts = { + initialRoots: [], + isolateConfigDir: options.initAtomEnv !== undefined, + initConfigDir: () => Promise.resolve(), + initAtomEnv: () => Promise.resolve(), + state: {}, + ...options, + }; + const atomEnv = global.buildAtomEnvironment(); + await opts.initAtomEnv(atomEnv); + + const projectDirs = await Promise.all( + opts.initialRoots.map(fixture => { + return cloneRepository(fixture); + }), + ); + + atomEnv.project.setPaths(projectDirs, {mustExist: true, exact: true}); + + let configDirPath = null; + if (opts.isolateConfigDir) { + configDirPath = await getTempDir(); + } else { + configDirPath = atomEnv.getConfigDirPath(); + } + await opts.initConfigDir(configDirPath); + let domRoot = null; let wrapper = null; const githubPackage = new GithubPackage({ workspace: atomEnv.workspace, - project: atomEnv.projects, + project: atomEnv.project, commandRegistry: atomEnv.commands, notificationManager: atomEnv.notifications, tooltips: atomEnv.tooltips, @@ -35,19 +73,35 @@ export function setup(currentTest) { config: atomEnv.config, deserializers: atomEnv.deserializers, confirm: atomEnv.confirm.bind(atomEnv), - getLoadSettings: atom.getLoadSettings.bind(atomEnv), - configDirPath: atom.getConfigDirPath(), + getLoadSettings: atomEnv.getLoadSettings.bind(atomEnv), + configDirPath, renderFn: (component, node, callback) => { if (!domRoot && node) { domRoot = node; } - wrapper = mount(component, { - attachTo: node, - }); - process.nextTick(callback); + if (!wrapper) { + wrapper = mount(component, { + attachTo: node, + }); + } else { + wrapper.setProps(component.props); + } + if (callback) { + process.nextTick(callback); + } }, }); + for (const deserializerName in metadata.deserializers) { + const methodName = metadata.deserializers[deserializerName]; + atomEnv.deserializers.add({ + name: deserializerName, + deserialize: githubPackage[methodName], + }); + } + + await githubPackage.activate(opts.state); + return { atomEnv, githubPackage, @@ -57,7 +111,7 @@ export function setup(currentTest) { } export async function teardown(context) { - context.atomEnv.destroy(); - await context.githubPackage.deactivate(); + + context.atomEnv.destroy(); } From 92289248161e8f2b76b8fda1ae9c03cfc8565db9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 10:45:11 -0400 Subject: [PATCH 0373/4847] Flesh out launch tests --- test/integration/launch.test.js | 134 +++++++++++++++++++++++++++----- 1 file changed, 115 insertions(+), 19 deletions(-) diff --git a/test/integration/launch.test.js b/test/integration/launch.test.js index be1c73c3c8..981e5a6b5b 100644 --- a/test/integration/launch.test.js +++ b/test/integration/launch.test.js @@ -1,51 +1,147 @@ +import fs from 'fs-extra'; +import path from 'path'; + import {setup, teardown} from './helpers'; describe('Package initialization', function() { - let context, wrapper, atom; - - beforeEach(function() { - context = setup(this.currentTest); - wrapper = context.wrapper; - atom = context.atom; - }); + let context, atomEnv; afterEach(async function() { - await teardown(this.currentTest); + context && await teardown(context); }); + // beforeEach helpers + // Pass these to the initAtomEnv or initConfigDir arguments of setup() to assert a common pre-launch state. + + function welcomePackageActive(env) { + env.config.set('welcome.showOnStartup', true); + } + + function welcomePackageDismissed(env) { + env.config.set('welcome.showOnStartup', false); + } + + async function onFirstRun(configDirPath) { + await fs.remove(path.join(configDirPath, 'github.cson')); + } + + async function onLaterRuns(configDirPath) { + await fs.writeFile(path.join(configDirPath, 'github.cson'), '#'); + } + + // test body helpers + + function placesGitAndGitHubTabsIntoRightDock() { + const paneItemURIs = atomEnv.workspace.getRightDock().getPaneItems().map(paneItem => { + return (typeof paneItem.getURI === 'function') ? paneItem.getURI() : null; + }); + + assert.includeMembers( + paneItemURIs, ['atom-github://dock-item/git', 'atom-github://dock-item/github'], + 'Git and GitHub pane items present in the right dock', + ); + } + + function hidesRightDock() { + assert.isFalse(atomEnv.workspace.getRightDock().isVisible()); + } + + function revealsRightDock() { + assert.isTrue(atomEnv.workspace.getRightDock().isVisible()); + } + + async function keepsPreviouslyClosedGitAndGitHubTabsClosed() { + const prevContext = await setup(this.currentTest); + for (const uri of ['atom-github://dock-item/git', 'atom-github://dock-item/github']) { + prevContext.atomEnv.workspace.hide(uri); + } + const prevState = prevContext.atomEnv.serialize(); + await teardown(prevContext); + + context = await setup(this.currentTest, { + initAtomEnv: env => env.deserialize(prevState), + }); + + const paneItems = context.atomEnv.workspace.getRightDock().getPaneItems(); + assert.lengthOf(paneItems, 0); + + const paneItemURIs = context.atomEnv.workspace.getPaneItems().map(paneItem => { + return (typeof paneItem.getURI === 'function') ? paneItem.getURI() : null; + }); + + for (const uri of ['atom-github://dock-item/git', 'atom-github://dock-item/github']) { + assert.notInclude(paneItemURIs, uri, `Tab ${uri} should not be present`); + } + } + + async function keepsPreviouslyOpenGitAndGitHubTabsOpened() { + const prevContext = await setup(this.currentTest); + await prevContext.atomEnv.workspace.open('atom-github://dock-item/git', {searchAllPanes: true}); + await prevContext.atomEnv.workspace.open('atom-github://dock-item/github', {searchAllPanes: true}); + const prevState = prevContext.atomEnv.serialize(); + await teardown(prevContext); + + context = await setup(this.currentTest); + atomEnv = context.atomEnv; + await atomEnv.deserialize(prevState); + + placesGitAndGitHubTabsIntoRightDock(); + } + describe('on the very first run with the GitHub package present', function() { describe('with no serialized project state', function() { describe('with the welcome package active', function() { - it('places the git and github tabs into the right dock'); + beforeEach(async function() { + context = await setup(this.currentTest, { + initAtomEnv: welcomePackageActive, + initConfigDir: onFirstRun, + }); + atomEnv = context.atomEnv; + }); - it('hides the right dock'); + it('places the git and github tabs into the right dock', placesGitAndGitHubTabsIntoRightDock); + + it('hides the right dock', hidesRightDock); }); describe('with the welcome package dismissed', function() { - it('places the git and github tabs into the right dock'); + beforeEach(async function() { + context = await setup(this.currentTest, { + initAtomEnv: welcomePackageDismissed, + initConfigDir: onFirstRun, + }); + atomEnv = context.atomEnv; + }); + + it('places the git and github tabs into the right dock', placesGitAndGitHubTabsIntoRightDock); - it('reveals the right dock'); + it('reveals the right dock', revealsRightDock); }); }); describe('with serialized project state', function() { - it('keeps previously closed git and github tabs closed'); - - it('keeps previously open git and github tabs opened'); + // }); }); describe('on a run when the GitHub package was present before', function() { describe('with no serialized project state', function() { - it('places the git and github tabs into the right dock'); + beforeEach(async function() { + context = await setup(this.currentTest, { + initConfigDir: onLaterRuns, + }); + atomEnv = context.atomEnv; + }); + + it('places the git and github tabs into the right dock', placesGitAndGitHubTabsIntoRightDock); - it('hides the right dock'); + it('hides the right dock', hidesRightDock); }); describe('with serialized project state', function() { - it('keeps previously closed git and github tabs closed'); + it('keeps previously closed git and github tabs closed', keepsPreviouslyClosedGitAndGitHubTabsClosed); - it('keeps previously open git and github tabs opened'); + it('keeps previously open git and github tabs opened', keepsPreviouslyOpenGitAndGitHubTabsOpened); }); }); }); From 5fb7734e678ffae61fdee993e4ba2badea5df0f3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 10:45:22 -0400 Subject: [PATCH 0374/4847] Prevent dock item from activating too early --- lib/atom/dock-item.js | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/lib/atom/dock-item.js b/lib/atom/dock-item.js index 1fb149b017..ee825a19e5 100644 --- a/lib/atom/dock-item.js +++ b/lib/atom/dock-item.js @@ -81,13 +81,13 @@ export default class DockItem extends React.Component { stub.setRealItem(itemToAdd); this.dockItem = stub; if (this.props.activate) { - this.activate(); + this.scheduleActivation(); } } else { Promise.resolve(this.props.workspace.open(itemToAdd, {activatePane: false})) .then(item => { this.dockItem = item; - if (this.props.activate) { this.activate(); } + if (this.props.activate) { this.scheduleActivation(); } }); } @@ -117,23 +117,32 @@ export default class DockItem extends React.Component { return this.dockItem; } + scheduleActivation() { + this.subscriptions.add( + this.props.workspace.onDidAddPaneItem(({item}) => { + if (item === this.dockItem) { + this.activate(); + } + }), + ); + } + activate() { - setTimeout(() => { - if (!this.dockItem || this.didCloseItem || this.props.workspace.isDestroyed()) { - return; - } + if (!this.dockItem || this.didCloseItem || this.props.workspace.isDestroyed()) { + return; + } - const pane = this.props.workspace.paneForItem(this.dockItem); - if (pane) { - pane.activateItem(this.dockItem); - const dock = this.props.workspace.getPaneContainers() - .find(container => container.getPanes().find(p => p.getItems().includes(this.dockItem))); - if (dock && dock.show) { - dock.show(); - } - } else if (this.dockItem && !this.didCloseItem) { - throw new Error('Could not find pane for a non-destroyed DockItem'); + const pane = this.props.workspace.paneForItem(this.dockItem); + if (pane) { + pane.activateItem(this.dockItem); + const dock = this.props.workspace.getPaneContainers() + .find(container => container.getPanes().find(p => p.getItems().includes(this.dockItem))); + if (dock && dock.show) { + dock.show(); } - }); + } else if (this.dockItem && !this.didCloseItem) { + debugger; + throw new Error('Could not find pane for a non-destroyed DockItem'); + } } } From 3866c2de6983c36c6ef8509fcc660ed5a34d6ff4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 12:34:44 -0400 Subject: [PATCH 0375/4847] Use distinct startOpen and startRevealed state --- lib/controllers/root-controller.js | 6 +++--- lib/github-package.js | 17 ++++++++++++++--- test/controllers/root-controller.test.js | 8 ++++---- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index ab41c31706..47442216ad 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -47,7 +47,7 @@ export default class RootController extends React.Component { resolutionProgress: PropTypes.object.isRequired, statusBar: PropTypes.object, switchboard: PropTypes.instanceOf(Switchboard), - startOpen: PropTypes.bool, + startRevealed: PropTypes.bool, gitTabStubItem: PropTypes.object, githubTabStubItem: PropTypes.object, destroyGitTabItem: PropTypes.func.isRequired, @@ -57,7 +57,7 @@ export default class RootController extends React.Component { static defaultProps = { switchboard: new Switchboard(), - startOpen: true, + startRevealed: false, } constructor(props, context) { @@ -181,7 +181,7 @@ export default class RootController extends React.Component { onDidCloseItem={this.props.destroyGitTabItem} stubItem={this.props.gitTabStubItem} itemHolder={this.refGitTabItem} - activate={this.props.startOpen}> + activate={this.props.startRevealed}> Date: Tue, 26 Jun 2018 12:34:50 -0400 Subject: [PATCH 0376/4847] :fire: debugger --- lib/atom/dock-item.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/atom/dock-item.js b/lib/atom/dock-item.js index ee825a19e5..ece79237c8 100644 --- a/lib/atom/dock-item.js +++ b/lib/atom/dock-item.js @@ -141,7 +141,6 @@ export default class DockItem extends React.Component { dock.show(); } } else if (this.dockItem && !this.didCloseItem) { - debugger; throw new Error('Could not find pane for a non-destroyed DockItem'); } } From 9548d00ce6b39181cc68d9ceff9314d0fb36c0a1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 12:36:54 -0400 Subject: [PATCH 0377/4847] Flatten launch scenarios --- test/integration/launch.test.js | 177 ++++++++++++-------------------- 1 file changed, 64 insertions(+), 113 deletions(-) diff --git a/test/integration/launch.test.js b/test/integration/launch.test.js index 981e5a6b5b..02d3945c94 100644 --- a/test/integration/launch.test.js +++ b/test/integration/launch.test.js @@ -4,144 +4,95 @@ import path from 'path'; import {setup, teardown} from './helpers'; describe('Package initialization', function() { - let context, atomEnv; + let context; afterEach(async function() { context && await teardown(context); }); - // beforeEach helpers - // Pass these to the initAtomEnv or initConfigDir arguments of setup() to assert a common pre-launch state. - - function welcomePackageActive(env) { - env.config.set('welcome.showOnStartup', true); - } - - function welcomePackageDismissed(env) { - env.config.set('welcome.showOnStartup', false); - } - - async function onFirstRun(configDirPath) { - await fs.remove(path.join(configDirPath, 'github.cson')); - } - - async function onLaterRuns(configDirPath) { - await fs.writeFile(path.join(configDirPath, 'github.cson'), '#'); - } + it.only('reveals the tabs on first run when the welcome package has been dismissed', async function() { + context = await setup(this.currentTest, { + initConfigDir: configDirPath => fs.remove(path.join(configDirPath, 'github.cson')), + initAtomEnv: env => env.config.set('welcome.showOnStartup', false), + }); - // test body helpers + const rightDock = context.atomEnv.workspace.getRightDock(); + const paneItemURIs = rightDock.getPaneItems().map(i => i.getURI()); + assert.includeMembers(paneItemURIs, ['atom-github://dock-item/git', 'atom-github://dock-item/github']); + assert.isTrue(rightDock.isVisible()); + }); - function placesGitAndGitHubTabsIntoRightDock() { - const paneItemURIs = atomEnv.workspace.getRightDock().getPaneItems().map(paneItem => { - return (typeof paneItem.getURI === 'function') ? paneItem.getURI() : null; + it('renders but does not reveal the tabs on first run when the welcome package has not been dismissed', async function() { + context = await setup(this.currentTest, { + initConfigDir: configDirPath => fs.remove(path.join(configDirPath, 'github.cson')), + initAtomEnv: env => env.config.set('welcome.showOnStartup', true), }); - assert.includeMembers( - paneItemURIs, ['atom-github://dock-item/git', 'atom-github://dock-item/github'], - 'Git and GitHub pane items present in the right dock', - ); - } - - function hidesRightDock() { - assert.isFalse(atomEnv.workspace.getRightDock().isVisible()); - } - - function revealsRightDock() { - assert.isTrue(atomEnv.workspace.getRightDock().isVisible()); - } - - async function keepsPreviouslyClosedGitAndGitHubTabsClosed() { - const prevContext = await setup(this.currentTest); - for (const uri of ['atom-github://dock-item/git', 'atom-github://dock-item/github']) { - prevContext.atomEnv.workspace.hide(uri); - } - const prevState = prevContext.atomEnv.serialize(); - await teardown(prevContext); + const rightDock = context.atomEnv.workspace.getRightDock(); + const paneItemURIs = rightDock.getPaneItems().map(i => i.getURI()); + assert.includeMembers(paneItemURIs, ['atom-github://dock-item/git', 'atom-github://dock-item/github']); + assert.isFalse(rightDock.isVisible()); + }); + it('renders but does not reveal the tabs on new projects after the first run', async function() { context = await setup(this.currentTest, { - initAtomEnv: env => env.deserialize(prevState), + initConfigDir: configDirPath => fs.writeFile(path.join(configDirPath, 'github.cson'), '#', {encoding: 'utf8'}), + state: {}, }); - const paneItems = context.atomEnv.workspace.getRightDock().getPaneItems(); - assert.lengthOf(paneItems, 0); + const rightDock = context.atomEnv.workspace.getRightDock(); + const paneItemURIs = rightDock.getPaneItems().map(i => i.getURI()); + assert.includeMembers(paneItemURIs, ['atom-github://dock-item/git', 'atom-github://dock-item/github']); + assert.isFalse(rightDock.isVisible()); + }); + + it('respects serialized state on existing projects after the first run', async function() { + const nonFirstRun = { + initConfigDir: configDirPath => fs.writeFile(path.join(configDirPath, 'github.cson'), '#', {encoding: 'utf8'}), + state: {newProject: false}, + }; - const paneItemURIs = context.atomEnv.workspace.getPaneItems().map(paneItem => { - return (typeof paneItem.getURI === 'function') ? paneItem.getURI() : null; - }); + const prevContext = await setup(this.currentTest, nonFirstRun); - for (const uri of ['atom-github://dock-item/git', 'atom-github://dock-item/github']) { - assert.notInclude(paneItemURIs, uri, `Tab ${uri} should not be present`); - } - } + const prevWorkspace = prevContext.atomEnv.workspace; + await prevWorkspace.open('atom-github://dock-item/github', {searchAllPanes: true}); - async function keepsPreviouslyOpenGitAndGitHubTabsOpened() { - const prevContext = await setup(this.currentTest); - await prevContext.atomEnv.workspace.open('atom-github://dock-item/git', {searchAllPanes: true}); - await prevContext.atomEnv.workspace.open('atom-github://dock-item/github', {searchAllPanes: true}); const prevState = prevContext.atomEnv.serialize(); + await teardown(prevContext); - context = await setup(this.currentTest); - atomEnv = context.atomEnv; - await atomEnv.deserialize(prevState); - - placesGitAndGitHubTabsIntoRightDock(); - } - - describe('on the very first run with the GitHub package present', function() { - describe('with no serialized project state', function() { - describe('with the welcome package active', function() { - beforeEach(async function() { - context = await setup(this.currentTest, { - initAtomEnv: welcomePackageActive, - initConfigDir: onFirstRun, - }); - atomEnv = context.atomEnv; - }); - - it('places the git and github tabs into the right dock', placesGitAndGitHubTabsIntoRightDock); - - it('hides the right dock', hidesRightDock); - }); - - describe('with the welcome package dismissed', function() { - beforeEach(async function() { - context = await setup(this.currentTest, { - initAtomEnv: welcomePackageDismissed, - initConfigDir: onFirstRun, - }); - atomEnv = context.atomEnv; - }); - - it('places the git and github tabs into the right dock', placesGitAndGitHubTabsIntoRightDock); - - it('reveals the right dock', revealsRightDock); - }); - }); + context = await setup(this.currentTest, nonFirstRun); + await context.atomEnv.deserialize(prevState); - describe('with serialized project state', function() { - // - }); + const paneItemURIs = context.atomEnv.workspace.getPaneItems().map(i => i.getURI()); + assert.include(paneItemURIs, 'atom-github://dock-item/github'); + assert.notInclude(paneItemURIs, 'atom-github://dock-item/git'); }); - describe('on a run when the GitHub package was present before', function() { - describe('with no serialized project state', function() { - beforeEach(async function() { - context = await setup(this.currentTest, { - initConfigDir: onLaterRuns, - }); - atomEnv = context.atomEnv; - }); + it('honors firstRun from legacy serialized state', async function() { + // Previous versions of this package used a {firstRun} key in their serialized state to determine whether or not + // the tabs should be open by default. I've renamed it to {newProject} to distinguish it from the firstRun prop + // we're setting based on the presence or absence of `${ATOM_HOME}/github.cson`. - it('places the git and github tabs into the right dock', placesGitAndGitHubTabsIntoRightDock); + const nonFirstRun = { + initConfigDir: configDirPath => fs.writeFile(path.join(configDirPath, 'github.cson'), '#', {encoding: 'utf8'}), + state: {firstRun: false}, + }; - it('hides the right dock', hidesRightDock); - }); + const prevContext = await setup(this.currentTest, nonFirstRun); - describe('with serialized project state', function() { - it('keeps previously closed git and github tabs closed', keepsPreviouslyClosedGitAndGitHubTabsClosed); + const prevWorkspace = prevContext.atomEnv.workspace; + await prevWorkspace.open('atom-github://dock-item/github', {searchAllPanes: true}); - it('keeps previously open git and github tabs opened', keepsPreviouslyOpenGitAndGitHubTabsOpened); - }); + const prevState = prevContext.atomEnv.serialize(); + + await teardown(prevContext); + + context = await setup(this.currentTest, nonFirstRun); + await context.atomEnv.deserialize(prevState); + + const paneItemURIs = context.atomEnv.workspace.getPaneItems().map(i => i.getURI()); + assert.include(paneItemURIs, 'atom-github://dock-item/github'); + assert.notInclude(paneItemURIs, 'atom-github://dock-item/git'); }); }); From 861583eb130bc22d8a2f9fbb42934cf2af8d930d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 13:40:17 -0400 Subject: [PATCH 0378/4847] Separate startOpen and startRevealed props --- lib/controllers/root-controller.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 8efdc44a79..a6509e763e 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -45,6 +45,7 @@ export default class RootController extends React.Component { resolutionProgress: PropTypes.object.isRequired, statusBar: PropTypes.object, switchboard: PropTypes.instanceOf(Switchboard), + startOpen: PropTypes.bool, startRevealed: PropTypes.bool, gitTabStubItem: PropTypes.object, githubTabStubItem: PropTypes.object, @@ -55,6 +56,7 @@ export default class RootController extends React.Component { static defaultProps = { switchboard: new Switchboard(), + startOpen: false, startRevealed: false, } @@ -354,7 +356,9 @@ export default class RootController extends React.Component { this.gitTabTracker.ensureRendered(false), this.githubTabTracker.ensureRendered(false), ]); + } + if (this.props.startRevealed) { const docks = new Set( [GitTabItem.buildURI(), GithubTabController.buildURI()] .map(uri => this.props.workspace.paneContainerForURI(uri)) From d35eafd52460ffaa70e4641a7b3e27ea0d1248d1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 13:40:27 -0400 Subject: [PATCH 0379/4847] Boolean logic is hard --- lib/github-package.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/github-package.js b/lib/github-package.js index 7023f26d70..54205ac8d8 100644 --- a/lib/github-package.js +++ b/lib/github-package.js @@ -156,10 +156,10 @@ export default class GithubPackage { this.savedState = {...defaultState, ...state}; const firstRun = !await fileExists(this.configPath); - const newProject = this.savedState.newProject || this.savedState.firstRun; + const newProject = this.savedState.firstRun !== undefined ? this.savedState.firstRun : this.savedState.newProject; this.startOpen = firstRun || newProject; - this.startRevealed = this.startOpen && !this.config.get('welcome.showOnStartup'); + this.startRevealed = firstRun && !this.config.get('welcome.showOnStartup'); if (firstRun) { await fs.writeFile(this.configPath, '# Store non-visible GitHub package state.\n', {encoding: 'utf8'}); @@ -236,12 +236,6 @@ export default class GithubPackage { }), ); - if (this.startOpen) { - for (const uri of ['atom-github://dock-item/git', 'atom-github://dock-item/github']) { - this.workspace.open(uri); - } - } - this.activated = true; this.scheduleActiveContextUpdate(this.savedState); this.rerender(); @@ -292,6 +286,7 @@ export default class GithubPackage { createRepositoryForProjectPath={this.createRepositoryForProjectPath} cloneRepositoryForProjectPath={this.cloneRepositoryForProjectPath} switchboard={this.switchboard} + startOpen={this.startOpen} startRevealed={this.startRevealed} gitTabStubItem={this.gitTabStubItem} githubTabStubItem={this.githubTabStubItem} From 4784623f2257f249b8a4fa27ee91ac2d1bbeef1f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 13:40:43 -0400 Subject: [PATCH 0380/4847] Account for async opening --- test/integration/launch.test.js | 60 ++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/test/integration/launch.test.js b/test/integration/launch.test.js index 02d3945c94..38b97807ec 100644 --- a/test/integration/launch.test.js +++ b/test/integration/launch.test.js @@ -2,6 +2,8 @@ import fs from 'fs-extra'; import path from 'path'; import {setup, teardown} from './helpers'; +import GitTabItem from '../../lib/items/git-tab-item'; +import GithubTabController from '../../lib/controllers/github-tab-controller'; describe('Package initialization', function() { let context; @@ -10,15 +12,18 @@ describe('Package initialization', function() { context && await teardown(context); }); - it.only('reveals the tabs on first run when the welcome package has been dismissed', async function() { + it('reveals the tabs on first run when the welcome package has been dismissed', async function() { context = await setup(this.currentTest, { initConfigDir: configDirPath => fs.remove(path.join(configDirPath, 'github.cson')), initAtomEnv: env => env.config.set('welcome.showOnStartup', false), }); const rightDock = context.atomEnv.workspace.getRightDock(); - const paneItemURIs = rightDock.getPaneItems().map(i => i.getURI()); - assert.includeMembers(paneItemURIs, ['atom-github://dock-item/git', 'atom-github://dock-item/github']); + const getPaneItemURIs = () => { + return rightDock.getPaneItems().map(i => i.getURI()); + }; + + await assert.async.includeMembers(getPaneItemURIs(), [GitTabItem.buildURI(), GithubTabController.buildURI()]); assert.isTrue(rightDock.isVisible()); }); @@ -29,8 +34,11 @@ describe('Package initialization', function() { }); const rightDock = context.atomEnv.workspace.getRightDock(); - const paneItemURIs = rightDock.getPaneItems().map(i => i.getURI()); - assert.includeMembers(paneItemURIs, ['atom-github://dock-item/git', 'atom-github://dock-item/github']); + const getPaneItemURIs = () => { + return rightDock.getPaneItems().map(i => i.getURI()); + }; + + await assert.async.includeMembers(getPaneItemURIs(), [GitTabItem.buildURI(), GithubTabController.buildURI()]); assert.isFalse(rightDock.isVisible()); }); @@ -41,8 +49,11 @@ describe('Package initialization', function() { }); const rightDock = context.atomEnv.workspace.getRightDock(); - const paneItemURIs = rightDock.getPaneItems().map(i => i.getURI()); - assert.includeMembers(paneItemURIs, ['atom-github://dock-item/git', 'atom-github://dock-item/github']); + const getPaneItemURIs = () => { + return rightDock.getPaneItems().map(i => i.getURI()); + }; + + await assert.async.includeMembers(getPaneItemURIs(), [GitTabItem.buildURI(), GithubTabController.buildURI()]); assert.isFalse(rightDock.isVisible()); }); @@ -55,7 +66,8 @@ describe('Package initialization', function() { const prevContext = await setup(this.currentTest, nonFirstRun); const prevWorkspace = prevContext.atomEnv.workspace; - await prevWorkspace.open('atom-github://dock-item/github', {searchAllPanes: true}); + await prevWorkspace.open(GithubTabController.buildURI(), {searchAllPanes: true}); + prevWorkspace.hide(GitTabItem.buildURI()); const prevState = prevContext.atomEnv.serialize(); @@ -65,8 +77,8 @@ describe('Package initialization', function() { await context.atomEnv.deserialize(prevState); const paneItemURIs = context.atomEnv.workspace.getPaneItems().map(i => i.getURI()); - assert.include(paneItemURIs, 'atom-github://dock-item/github'); - assert.notInclude(paneItemURIs, 'atom-github://dock-item/git'); + assert.include(paneItemURIs, GithubTabController.buildURI()); + assert.notInclude(paneItemURIs, GitTabItem.buildURI()); }); it('honors firstRun from legacy serialized state', async function() { @@ -74,25 +86,33 @@ describe('Package initialization', function() { // the tabs should be open by default. I've renamed it to {newProject} to distinguish it from the firstRun prop // we're setting based on the presence or absence of `${ATOM_HOME}/github.cson`. - const nonFirstRun = { + const getPaneItemURIs = ctx => ctx.atomEnv.workspace.getPaneItems().map(i => i.getURI()); + + const prevContext = await setup(this.currentTest, { initConfigDir: configDirPath => fs.writeFile(path.join(configDirPath, 'github.cson'), '#', {encoding: 'utf8'}), - state: {firstRun: false}, - }; + state: {firstRun: true}, + }); - const prevContext = await setup(this.currentTest, nonFirstRun); + await assert.async.includeMembers( + getPaneItemURIs(prevContext), + [GitTabItem.buildURI(), GithubTabController.buildURI()], + ); const prevWorkspace = prevContext.atomEnv.workspace; - await prevWorkspace.open('atom-github://dock-item/github', {searchAllPanes: true}); + const item = prevWorkspace.getPaneItems().find(i => i.getURI() === GitTabItem.buildURI()); + const pane = prevWorkspace.paneForURI(GitTabItem.buildURI()); + pane.destroyItem(item); const prevState = prevContext.atomEnv.serialize(); - await teardown(prevContext); - context = await setup(this.currentTest, nonFirstRun); + context = await setup(this.currentTest, { + initConfigDir: configDirPath => fs.writeFile(path.join(configDirPath, 'github.cson'), '#', {encoding: 'utf8'}), + state: {firstRun: false}, + }); await context.atomEnv.deserialize(prevState); - const paneItemURIs = context.atomEnv.workspace.getPaneItems().map(i => i.getURI()); - assert.include(paneItemURIs, 'atom-github://dock-item/github'); - assert.notInclude(paneItemURIs, 'atom-github://dock-item/git'); + await assert.async.include(getPaneItemURIs(context), GithubTabController.buildURI()); + assert.notInclude(getPaneItemURIs(context), GitTabItem.buildURI()); }); }); From 459484140ee190f6c4350832f3284e028fc80f98 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 13:58:27 -0400 Subject: [PATCH 0381/4847] Remove unused props --- lib/controllers/root-controller.js | 4 ---- lib/github-package.js | 4 ---- test/controllers/root-controller.test.js | 9 +-------- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index a6509e763e..5926d73f25 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -47,10 +47,6 @@ export default class RootController extends React.Component { switchboard: PropTypes.instanceOf(Switchboard), startOpen: PropTypes.bool, startRevealed: PropTypes.bool, - gitTabStubItem: PropTypes.object, - githubTabStubItem: PropTypes.object, - destroyGitTabItem: PropTypes.func.isRequired, - destroyGithubTabItem: PropTypes.func.isRequired, pipelineManager: PropTypes.object, } diff --git a/lib/github-package.js b/lib/github-package.js index 54205ac8d8..2937a9992d 100644 --- a/lib/github-package.js +++ b/lib/github-package.js @@ -288,10 +288,6 @@ export default class GithubPackage { switchboard={this.switchboard} startOpen={this.startOpen} startRevealed={this.startRevealed} - gitTabStubItem={this.gitTabStubItem} - githubTabStubItem={this.githubTabStubItem} - destroyGitTabItem={this.destroyGitTabItem} - destroyGithubTabItem={this.destroyGithubTabItem} removeFilePatchItem={this.removeFilePatchItem} getRepositoryForWorkdir={this.getRepositoryForWorkdir} />, this.element, callback, diff --git a/test/controllers/root-controller.test.js b/test/controllers/root-controller.test.js index 79e3fe27aa..a1cef4b3d5 100644 --- a/test/controllers/root-controller.test.js +++ b/test/controllers/root-controller.test.js @@ -17,7 +17,7 @@ import RootController from '../../lib/controllers/root-controller'; describe('RootController', function() { let atomEnv, app; let workspace, commandRegistry, notificationManager, tooltips, config, confirm, deserializers, grammars, project; - let getRepositoryForWorkdir, destroyGitTabItem, destroyGithubTabItem, removeFilePatchItem; + let getRepositoryForWorkdir; beforeEach(function() { atomEnv = global.buildAtomEnvironment(); @@ -31,9 +31,6 @@ describe('RootController', function() { project = atomEnv.project; getRepositoryForWorkdir = sinon.stub(); - destroyGitTabItem = sinon.spy(); - destroyGithubTabItem = sinon.spy(); - removeFilePatchItem = sinon.spy(); const absentRepository = Repository.absent(); const emptyResolutionProgress = new ResolutionProgress(); @@ -53,11 +50,7 @@ describe('RootController', function() { repository={absentRepository} resolutionProgress={emptyResolutionProgress} startOpen={false} - filePatchItems={[]} getRepositoryForWorkdir={getRepositoryForWorkdir} - destroyGitTabItem={destroyGitTabItem} - destroyGithubTabItem={destroyGithubTabItem} - removeFilePatchItem={removeFilePatchItem} /> ); }); From 2cd984fd449ca243770d13a5ca9a5993c8c1cb7f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 13:58:40 -0400 Subject: [PATCH 0382/4847] Update GithubPackage and RootController tests --- test/controllers/root-controller.test.js | 5 +++-- test/github-package.test.js | 26 +++++++++++++++++------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/test/controllers/root-controller.test.js b/test/controllers/root-controller.test.js index a1cef4b3d5..8036b83584 100644 --- a/test/controllers/root-controller.test.js +++ b/test/controllers/root-controller.test.js @@ -50,6 +50,7 @@ describe('RootController', function() { repository={absentRepository} resolutionProgress={emptyResolutionProgress} startOpen={false} + startRevealed={false} getRepositoryForWorkdir={getRepositoryForWorkdir} /> ); @@ -64,7 +65,7 @@ describe('RootController', function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); - app = React.cloneElement(app, {repository, startRevealed: false}); + app = React.cloneElement(app, {repository, startOpen: false, startRevealed: false}); const wrapper = mount(app); assert.isFalse(wrapper.update().find('GitTabItem').exists()); @@ -80,7 +81,7 @@ describe('RootController', function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); - app = React.cloneElement(app, {repository, startRevealed: true}); + app = React.cloneElement(app, {repository, startOpen: true, startRevealed: true}); const wrapper = mount(app); await assert.async.isTrue(workspace.getRightDock().isVisible()); diff --git a/test/github-package.test.js b/test/github-package.test.js index badb23d242..9495555f43 100644 --- a/test/github-package.test.js +++ b/test/github-package.test.js @@ -283,7 +283,7 @@ describe('GithubPackage', function() { assert.equal(githubPackage.getActiveResolutionProgress().getRemaining('modified-on-both-ours.txt'), 3); }); - describe('startOpen', function() { + describe('startOpen and startRevealed', function() { let confFile; beforeEach(async function() { @@ -291,27 +291,39 @@ describe('GithubPackage', function() { await fs.remove(confFile); }); - it('renders with startOpen on the first run', async function() { + it('renders with startOpen and startRevealed on the first run with the welcome package dismissed', async function() { config.set('welcome.showOnStartup', false); await githubPackage.activate(); assert.isTrue(githubPackage.startOpen); + assert.isTrue(githubPackage.startRevealed); assert.isTrue(await fileExists(confFile)); }); - it('renders without startOpen on non-first runs', async function() { - await fs.writeFile(confFile, '', {encoding: 'utf8'}); + it('renders with startOpen but not startRevealed on the first run with the welcome package undismissed', async function() { + config.set('welcome.showOnStartup', true); await githubPackage.activate(); - assert.isFalse(githubPackage.startOpen); + assert.isTrue(githubPackage.startOpen); + assert.isFalse(githubPackage.startRevealed); assert.isTrue(await fileExists(confFile)); }); - it('renders without startOpen on the first run if the welcome pane is shown', async function() { - config.set('welcome.showOnStartup', true); + it('renders with startOpen but not startRevealed on non-first runs on new projects', async function() { + await fs.writeFile(confFile, '', {encoding: 'utf8'}); await githubPackage.activate(); + assert.isTrue(githubPackage.startOpen); + assert.isFalse(githubPackage.startRevealed); + assert.isTrue(await fileExists(confFile)); + }); + + it('renders without startOpen or startRevealed on non-first runs on existing projects', async function() { + await fs.writeFile(confFile, '', {encoding: 'utf8'}); + await githubPackage.activate({newProject: false}); + assert.isFalse(githubPackage.startOpen); + assert.isFalse(githubPackage.startRevealed); assert.isTrue(await fileExists(confFile)); }); }); From 81dd4d71b4e4ea0499c5d233161d5b3cd50fe566 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 15:46:39 -0400 Subject: [PATCH 0383/4847] Attach integration env workspaces to the DOM --- test/integration/helpers.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/integration/helpers.js b/test/integration/helpers.js index e551e17319..304b22d816 100644 --- a/test/integration/helpers.js +++ b/test/integration/helpers.js @@ -41,6 +41,15 @@ export async function setup(currentTest, options = {}) { const atomEnv = global.buildAtomEnvironment(); + let suiteRoot = document.getElementById('github-IntegrationSuite'); + if (!suiteRoot) { + suiteRoot = document.createElement('div'); + suiteRoot.id = 'github-IntegrationSuite'; + document.body.appendChild(suiteRoot); + } + suiteRoot.appendChild(atomEnv.workspace.getElement()); + atomEnv.workspace.getElement().focus(); + await opts.initAtomEnv(atomEnv); const projectDirs = await Promise.all( @@ -78,6 +87,7 @@ export async function setup(currentTest, options = {}) { renderFn: (component, node, callback) => { if (!domRoot && node) { domRoot = node; + document.body.appendChild(domRoot); } if (!wrapper) { wrapper = mount(component, { @@ -107,11 +117,13 @@ export async function setup(currentTest, options = {}) { githubPackage, wrapper, domRoot, + suiteRoot, }; } export async function teardown(context) { await context.githubPackage.deactivate(); + context.suiteRoot.removeChild(context.atomEnv.workspace.getElement()); context.atomEnv.destroy(); } From 6a461e484e65ad899b70b2c0002df720976e1ec9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 15:46:52 -0400 Subject: [PATCH 0384/4847] "activated" isn't a thing --- lib/controllers/root-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 5926d73f25..bae8b35400 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -783,8 +783,8 @@ class TabTracker { return false; } - ensureRendered(activated) { - return this.getWorkspace().open(this.uri, {searchAllPanes: true, activated, activatePane: false}); + ensureRendered() { + return this.getWorkspace().open(this.uri, {searchAllPanes: true, activateItem: false, activatePane: false}); } reveal() { From 7a071931ccc54ab241dc94fa8002e0e3c49f22eb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 15:47:01 -0400 Subject: [PATCH 0385/4847] workingDirectoryPath is absent while loading --- lib/controllers/git-tab-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index 9a5708fcae..0d4344480a 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -28,7 +28,7 @@ export default class GitTabController extends React.Component { unstagedChanges: PropTypes.arrayOf(FilePatchItemPropType).isRequired, stagedChanges: PropTypes.arrayOf(FilePatchItemPropType).isRequired, mergeConflicts: PropTypes.arrayOf(MergeConflictItemPropType).isRequired, - workingDirectoryPath: PropTypes.string.isRequired, + workingDirectoryPath: PropTypes.string, mergeMessage: PropTypes.string, fetchInProgress: PropTypes.bool.isRequired, From 0c3d69d1fdee3103f8e7dda096b3e7981c71b317 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Jun 2018 15:47:20 -0400 Subject: [PATCH 0386/4847] Test the open and focus commands --- test/integration/open.test.js | 110 ++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 test/integration/open.test.js diff --git a/test/integration/open.test.js b/test/integration/open.test.js new file mode 100644 index 0000000000..dfaae4cf83 --- /dev/null +++ b/test/integration/open.test.js @@ -0,0 +1,110 @@ +import fs from 'fs-extra'; +import path from 'path'; + +import {setup, teardown} from './helpers'; + +describe('opening and closing tabs', function() { + let context, wrapper, atomEnv, commands, workspaceElement; + + beforeEach(async function() { + context = await setup(this.currentTest, { + initialRoots: ['three-files'], + initConfigDir: configDirPath => fs.writeFile(path.join(configDirPath, 'github.cson'), ''), + state: {newProject: false}, + }); + + wrapper = context.wrapper; + atomEnv = context.atomEnv; + commands = atomEnv.commands; + + workspaceElement = atomEnv.views.getView(atomEnv.workspace); + }); + + afterEach(async function() { + await teardown(context); + }); + + it('opens but does not focus the git tab on github:toggle-git-tab', async function() { + const editor = await atomEnv.workspace.open(__filename); + assert.isFalse(wrapper.find('.github-Panel').exists()); + + await commands.dispatch(workspaceElement, 'github:toggle-git-tab'); + + wrapper.update(); + assert.isTrue(wrapper.find('.github-Panel').exists()); + + assert.isTrue(atomEnv.workspace.getRightDock().isVisible()); + await assert.async.strictEqual(atomEnv.workspace.getActivePaneItem(), editor); + }); + + it('reveals an open but hidden git tab on github:toggle-git-tab', async function() { + await commands.dispatch(workspaceElement, 'github:toggle-git-tab'); + atomEnv.workspace.getRightDock().hide(); + wrapper.update(); + assert.isTrue(wrapper.find('.github-Panel').exists()); + + await commands.dispatch(workspaceElement, 'github:toggle-git-tab'); + wrapper.update(); + + assert.isTrue(wrapper.find('.github-Panel').exists()); + assert.isTrue(atomEnv.workspace.getRightDock().isVisible()); + }); + + it('hides an open git tab on github:toggle-git-tab', async function() { + await commands.dispatch(workspaceElement, 'github:toggle-git-tab'); + wrapper.update(); + + assert.isTrue(wrapper.find('.github-Panel').exists()); + assert.isTrue(atomEnv.workspace.getRightDock().isVisible()); + + await commands.dispatch(workspaceElement, 'github:toggle-git-tab'); + wrapper.update(); + + assert.isTrue(wrapper.find('.github-Panel').exists()); + assert.isFalse(atomEnv.workspace.getRightDock().isVisible()); + }); + + it('opens and focuses the git tab on github:toggle-git-tab-focus', async function() { + await atomEnv.workspace.open(__filename); + + await commands.dispatch(workspaceElement, 'github:toggle-git-tab-focus'); + wrapper.update(); + + assert.isTrue(wrapper.find('.github-Panel').exists()); + assert.isTrue(atomEnv.workspace.getRightDock().isVisible()); + assert.isTrue(wrapper.find('.github-Panel[tabIndex]').getDOMNode().contains(document.activeElement)); + }); + + it('focuses a blurred git tab on github:toggle-git-tab-focus', async function() { + await commands.dispatch(workspaceElement, 'github:toggle-git-tab'); + wrapper.update(); + + assert.isTrue(wrapper.find('.github-Panel').exists()); + assert.isTrue(atomEnv.workspace.getRightDock().isVisible()); + assert.isFalse(wrapper.find('.github-Panel[tabIndex]').getDOMNode().contains(document.activeElement)); + + await commands.dispatch(workspaceElement, 'github:toggle-git-tab-focus'); + wrapper.update(); + + assert.isTrue(wrapper.find('.github-StagingView').getDOMNode().contains(document.activeElement)); + }); + + it('blurs an open and focused git tab on github:toggle-git-tab-focus', async function() { + const editor = await atomEnv.workspace.open(__filename); + + await commands.dispatch(workspaceElement, 'github:toggle-git-tab-focus'); + wrapper.update(); + + assert.isTrue(atomEnv.workspace.getRightDock().isVisible()); + assert.isTrue(wrapper.find('.github-StagingView').getDOMNode().contains(document.activeElement)); + + await commands.dispatch(workspaceElement, 'github:toggle-git-tab-focus'); + wrapper.update(); + + assert.isTrue(atomEnv.workspace.getRightDock().isVisible()); + assert.isTrue(wrapper.find('.github-StagingView').exists()); + assert.isFalse(wrapper.find('.github-StagingView').getDOMNode().contains(document.activeElement)); + assert.strictEqual(atomEnv.workspace.getActivePaneItem(), editor); + }); + +}); From 864668ffd36250d8d3d6a10b32e86c245855cd3f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 09:38:26 -0400 Subject: [PATCH 0387/4847] npm script to generate lcov data --- .gitignore | 1 + package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index bc032629fb..a09e392918 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ spec/fixtures/a/ spec/fixtures/b/ .tern-project .nyc_output/ +coverage/ diff --git a/package.json b/package.json index 963b6e22cd..a58f6f7df7 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "scripts": { "test": "atom --test test", "test:coverage": "nyc script/capture-env", + "test:coverage:lcov": "npm run test:coverage && nyc report --reporter=lcovonly", "coveralls": "nyc report --reporter=text-lcov | coveralls", "lint": "eslint --max-warnings 0 test lib", "fetch-schema": "node script/fetch-schema", From 297f75ccfb7c4c8b9509884883f214a59c4545db Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 09:39:12 -0400 Subject: [PATCH 0388/4847] Backfill IssueishPaneItem tests --- lib/items/issueish-pane-item.js | 21 ++-- test/fixtures/props/issueish-pane-props.js | 3 + test/items/issueish-pane-item.test.js | 116 +++++++++++++++++++++ 3 files changed, 127 insertions(+), 13 deletions(-) create mode 100644 test/fixtures/props/issueish-pane-props.js create mode 100644 test/items/issueish-pane-item.test.js diff --git a/lib/items/issueish-pane-item.js b/lib/items/issueish-pane-item.js index 162e9731d9..92e502827c 100644 --- a/lib/items/issueish-pane-item.js +++ b/lib/items/issueish-pane-item.js @@ -8,14 +8,13 @@ import GithubLoginModel from '../models/github-login-model'; export default class IssueishPaneItem extends Component { static propTypes = { - uri: PropTypes.string.isRequired, host: PropTypes.string.isRequired, owner: PropTypes.string.isRequired, repo: PropTypes.string.isRequired, issueishNumber: PropTypes.number.isRequired, } - static uriPattern = 'atom-github://issueish/{host}/{owner}/{repo}/{number}' + static uriPattern = 'atom-github://issueish/{host}/{owner}/{repo}/{issueishNumber}' static buildURI(host, owner, repo, number) { return 'atom-github://issueish/' + @@ -34,15 +33,11 @@ export default class IssueishPaneItem extends Component { this.loginModel = GithubLoginModel.get(); this.hasTerminatedPendingState = false; - this.state = {}; - } - - static getDerivedStateFromProps(nextProps, prevState) { - return { - host: nextProps.host, - owner: nextProps.owner, - repo: nextProps.repo, - issueishNumber: nextProps.issueishNumber, + this.state = { + host: this.props.host, + owner: this.props.owner, + repo: this.props.repo, + issueishNumber: this.props.issueishNumber, }; } @@ -92,13 +87,13 @@ export default class IssueishPaneItem extends Component { serialize() { return { - uri: this.props.uri, + uri: this.getURI(), deserializer: 'IssueishPaneItem', }; } getURI() { - return this.props.uri; + return this.constructor.buildURI(this.props.host, this.props.owner, this.props.repo, this.props.issueishNumber); } getTitle() { diff --git a/test/fixtures/props/issueish-pane-props.js b/test/fixtures/props/issueish-pane-props.js new file mode 100644 index 0000000000..586fb20122 --- /dev/null +++ b/test/fixtures/props/issueish-pane-props.js @@ -0,0 +1,3 @@ +export function issueishPaneItemProps(overrides = {}) { + return overrides; +} diff --git a/test/items/issueish-pane-item.test.js b/test/items/issueish-pane-item.test.js new file mode 100644 index 0000000000..e1c484ebe0 --- /dev/null +++ b/test/items/issueish-pane-item.test.js @@ -0,0 +1,116 @@ +import React from 'react'; +import {mount} from 'enzyme'; +import {CompositeDisposable} from 'event-kit'; + +import IssueishPaneItem from '../../lib/items/issueish-pane-item'; +import PaneItem from '../../lib/atom/pane-item'; +import {issueishPaneItemProps} from '../fixtures/props/issueish-pane-props'; + +describe('IssueishPaneItem', function() { + let atomEnv, subs; + + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + subs = new CompositeDisposable(); + }); + + afterEach(function() { + subs.dispose(); + atomEnv.destroy(); + }); + + function buildApp(overrideProps = {}) { + const props = issueishPaneItemProps(overrideProps); + + return ( + + {({itemHolder, params}) => ( + + )} + + ); + } + + it('renders within the workspace center', async function() { + const wrapper = mount(buildApp({})); + + const uri = IssueishPaneItem.buildURI('one.com', 'me', 'code', 400); + const item = await atomEnv.workspace.open(uri); + + assert.lengthOf(wrapper.update().find('IssueishPaneItem'), 1); + + const centerPaneItems = atomEnv.workspace.getCenter().getPaneItems(); + assert.include(centerPaneItems.map(i => i.getURI()), uri); + + assert.strictEqual(item.getURI(), uri); + assert.strictEqual(item.getTitle(), 'me/code#400'); + }); + + it('switches to a different issueish', async function() { + const wrapper = mount(buildApp({})); + await atomEnv.workspace.open(IssueishPaneItem.buildURI('host.com', 'me', 'original', 1)); + + const before = wrapper.update().find('IssueishPaneItemController'); + assert.strictEqual(before.prop('host'), 'host.com'); + assert.strictEqual(before.prop('owner'), 'me'); + assert.strictEqual(before.prop('repo'), 'original'); + assert.strictEqual(before.prop('issueishNumber'), 1); + + wrapper.find('IssueishPaneItemController').prop('switchToIssueish')('you', 'switched', 2); + + const after = wrapper.update().find('IssueishPaneItemController'); + assert.strictEqual(after.prop('host'), 'host.com'); + assert.strictEqual(after.prop('owner'), 'you'); + assert.strictEqual(after.prop('repo'), 'switched'); + assert.strictEqual(after.prop('issueishNumber'), 2); + }); + + it('reconstitutes its original URI', async function() { + const wrapper = mount(buildApp({})); + + const uri = IssueishPaneItem.buildURI('host.com', 'me', 'original', 1); + const item = await atomEnv.workspace.open(uri); + assert.strictEqual(item.getURI(), uri); + assert.strictEqual(item.serialize().uri, uri); + + wrapper.update().find('IssueishPaneItemController').prop('switchToIssueish')('you', 'switched', 2); + + assert.strictEqual(item.getURI(), uri); + assert.strictEqual(item.serialize().uri, uri); + }); + + it('broadcasts title changes', async function() { + const wrapper = mount(buildApp({})); + const item = await atomEnv.workspace.open(IssueishPaneItem.buildURI('host.com', 'user', 'repo', 1)); + assert.strictEqual(item.getTitle(), 'user/repo#1'); + + const handler = sinon.stub(); + subs.add(item.onDidChangeTitle(handler)); + + wrapper.update().find('IssueishPaneItemController').prop('onTitleChange')('SUP'); + assert.strictEqual(handler.callCount, 1); + assert.strictEqual(item.getTitle(), 'SUP'); + + wrapper.update().find('IssueishPaneItemController').prop('onTitleChange')('SUP'); + assert.strictEqual(handler.callCount, 1); + }); + + it('tracks pending state termination', async function() { + mount(buildApp({})); + const item = await atomEnv.workspace.open(IssueishPaneItem.buildURI('host.com', 'user', 'repo', 1)); + + const handler = sinon.stub(); + subs.add(item.onDidTerminatePendingState(handler)); + + item.terminatePendingState(); + assert.strictEqual(handler.callCount, 1); + + item.terminatePendingState(); + assert.strictEqual(handler.callCount, 1); + }); +}); From d958d72198d0e381b2b04965482e868bfe476c89 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 09:39:23 -0400 Subject: [PATCH 0389/4847] Use uriPattern static property --- test/items/git-tab-item.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/items/git-tab-item.test.js b/test/items/git-tab-item.test.js index da0a0ef1b2..4fa74cfa5a 100644 --- a/test/items/git-tab-item.test.js +++ b/test/items/git-tab-item.test.js @@ -24,7 +24,7 @@ describe('GitTabItem', function() { const props = gitTabItemProps(atomEnv, repository, overrideProps); return ( - + {({itemHolder}) => ( Date: Wed, 27 Jun 2018 09:39:31 -0400 Subject: [PATCH 0390/4847] URI prop is no longer used --- lib/controllers/root-controller.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index bae8b35400..007443f727 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -325,14 +325,13 @@ export default class RootController extends React.Component { )} - {({itemHolder, params, uri}) => ( + {({itemHolder, params}) => ( )} From 6e7ad7f2d97a320a1e8b32ac74b54764457d59b2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 10:13:53 -0400 Subject: [PATCH 0391/4847] Accept loginModel as a prop --- lib/controllers/root-controller.js | 3 +++ lib/items/issueish-pane-item.js | 9 ++++++--- lib/prop-types.js | 8 ++++++++ test/fixtures/props/issueish-pane-props.js | 8 +++++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 007443f727..70ebe14aab 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -328,10 +328,13 @@ export default class RootController extends React.Component { {({itemHolder, params}) => ( )} diff --git a/lib/items/issueish-pane-item.js b/lib/items/issueish-pane-item.js index 92e502827c..1cf65f3faa 100644 --- a/lib/items/issueish-pane-item.js +++ b/lib/items/issueish-pane-item.js @@ -3,8 +3,8 @@ import PropTypes from 'prop-types'; import {Emitter} from 'event-kit'; import {autobind} from '../helpers'; +import {GithubLoginModelPropType} from '../prop-types'; import IssueishPaneItemController from '../controllers/issueish-pane-item-controller'; -import GithubLoginModel from '../models/github-login-model'; export default class IssueishPaneItem extends Component { static propTypes = { @@ -12,6 +12,8 @@ export default class IssueishPaneItem extends Component { owner: PropTypes.string.isRequired, repo: PropTypes.string.isRequired, issueishNumber: PropTypes.number.isRequired, + + loginModel: GithubLoginModelPropType.isRequired, } static uriPattern = 'atom-github://issueish/{host}/{owner}/{repo}/{issueishNumber}' @@ -30,7 +32,6 @@ export default class IssueishPaneItem extends Component { this.emitter = new Emitter(); this.title = `${this.props.owner}/${this.props.repo}#${this.props.issueishNumber}`; - this.loginModel = GithubLoginModel.get(); this.hasTerminatedPendingState = false; this.state = { @@ -48,7 +49,9 @@ export default class IssueishPaneItem extends Component { owner={this.state.owner} repo={this.state.repo} issueishNumber={this.state.issueishNumber} - loginModel={this.loginModel} + + loginModel={this.props.loginModel} + onTitleChange={this.handleTitleChanged} switchToIssueish={this.switchToIssueish} /> diff --git a/lib/prop-types.js b/lib/prop-types.js index e4aa34754f..46c279bdfb 100644 --- a/lib/prop-types.js +++ b/lib/prop-types.js @@ -10,6 +10,14 @@ export const DOMNodePropType = (props, propName, componentName) => { } }; +export const GithubLoginModelPropType = PropTypes.shape({ + getToken: PropTypes.func.isRequired, + setToken: PropTypes.func.isRequired, + removeToken: PropTypes.func.isRequired, + getScopes: PropTypes.func.isRequired, + onDidUpdate: PropTypes.func.isRequired, +}); + export const RemotePropType = PropTypes.shape({ getName: PropTypes.func.isRequired, getUrl: PropTypes.func.isRequired, diff --git a/test/fixtures/props/issueish-pane-props.js b/test/fixtures/props/issueish-pane-props.js index 586fb20122..ab151259da 100644 --- a/test/fixtures/props/issueish-pane-props.js +++ b/test/fixtures/props/issueish-pane-props.js @@ -1,3 +1,9 @@ +import GithubLoginModel from '../../../lib/models/github-login-model'; +import {InMemoryStrategy} from '../../../lib/shared/keytar-strategy'; + export function issueishPaneItemProps(overrides = {}) { - return overrides; + return { + loginModel: new GithubLoginModel(InMemoryStrategy), + ...overrides, + }; } From edf36d6ea27d57c0dcda570dae3b66a0f4b81d28 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 10:19:07 -0400 Subject: [PATCH 0392/4847] Rename IssueishPaneItemController to IssueishDetailContainer --- .../issueish-detail-container.js} | 12 +++++++----- lib/items/issueish-pane-item.js | 4 ++-- test/items/issueish-pane-item.test.js | 12 ++++++------ 3 files changed, 15 insertions(+), 13 deletions(-) rename lib/{controllers/issueish-pane-item-controller.js => containers/issueish-detail-container.js} (95%) diff --git a/lib/controllers/issueish-pane-item-controller.js b/lib/containers/issueish-detail-container.js similarity index 95% rename from lib/controllers/issueish-pane-item-controller.js rename to lib/containers/issueish-detail-container.js index 22606855af..c8d67beaaa 100644 --- a/lib/controllers/issueish-pane-item-controller.js +++ b/lib/containers/issueish-detail-container.js @@ -4,7 +4,7 @@ import yubikiri from 'yubikiri'; import {QueryRenderer, graphql} from 'react-relay'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; -import GithubLoginModel from '../models/github-login-model'; +import {GithubLoginModelPropType} from '../prop-types'; import {UNAUTHENTICATED} from '../shared/keytar-strategy'; import GithubLoginView from '../views/github-login-view'; import ObserveModel from '../views/observe-model'; @@ -12,15 +12,17 @@ import IssueishLookupByNumberContainer from '../containers/issueish-lookup-by-nu import RelayEnvironment from '../views/relay-environment'; import {autobind} from '../helpers'; -export default class IssueishPaneItemController extends React.Component { +export default class IssueishDetailContainer extends React.Component { static propTypes = { - onTitleChange: PropTypes.func.isRequired, + host: PropTypes.string, owner: PropTypes.string.isRequired, repo: PropTypes.string.isRequired, issueishNumber: PropTypes.number.isRequired, + + loginModel: GithubLoginModelPropType.isRequired, + switchToIssueish: PropTypes.func.isRequired, - host: PropTypes.string, - loginModel: PropTypes.instanceOf(GithubLoginModel).isRequired, + onTitleChange: PropTypes.func.isRequired, } static defaultProps = { diff --git a/lib/items/issueish-pane-item.js b/lib/items/issueish-pane-item.js index 1cf65f3faa..4a1d7e809b 100644 --- a/lib/items/issueish-pane-item.js +++ b/lib/items/issueish-pane-item.js @@ -4,7 +4,7 @@ import {Emitter} from 'event-kit'; import {autobind} from '../helpers'; import {GithubLoginModelPropType} from '../prop-types'; -import IssueishPaneItemController from '../controllers/issueish-pane-item-controller'; +import IssueishDetailContainer from '../containers/issueish-detail-container'; export default class IssueishPaneItem extends Component { static propTypes = { @@ -44,7 +44,7 @@ export default class IssueishPaneItem extends Component { render() { return ( - Date: Wed, 27 Jun 2018 10:59:57 -0400 Subject: [PATCH 0393/4847] Relay compiler run --- .../issueishDetailContainerQuery.graphql.js} | 18 +- .../prInfoContainerRefetchQuery.graphql.js | 526 --------------- .../prInfoContainer_pullRequest.graphql.js | 283 -------- ...ionByBranchContainer_repository.graphql.js | 164 ----- ...electionByUrlContainer_resource.graphql.js | 56 -- .../prInfoControllerByBranchQuery.graphql.js | 621 ------------------ .../prInfoControllerByUrlQuery.graphql.js | 527 --------------- 7 files changed, 9 insertions(+), 2186 deletions(-) rename lib/{controllers/__generated__/issueishPaneItemControllerQuery.graphql.js => containers/__generated__/issueishDetailContainerQuery.graphql.js} (82%) delete mode 100644 lib/containers/__generated__/prInfoContainerRefetchQuery.graphql.js delete mode 100644 lib/containers/__generated__/prInfoContainer_pullRequest.graphql.js delete mode 100644 lib/containers/__generated__/prSelectionByBranchContainer_repository.graphql.js delete mode 100644 lib/containers/__generated__/prSelectionByUrlContainer_resource.graphql.js delete mode 100644 lib/controllers/__generated__/prInfoControllerByBranchQuery.graphql.js delete mode 100644 lib/controllers/__generated__/prInfoControllerByUrlQuery.graphql.js diff --git a/lib/controllers/__generated__/issueishPaneItemControllerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js similarity index 82% rename from lib/controllers/__generated__/issueishPaneItemControllerQuery.graphql.js rename to lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index f3728829cd..b4e8c3f15b 100644 --- a/lib/controllers/__generated__/issueishPaneItemControllerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash f7a9c17fe7c1412f5447671f9a581b0f + * @relayHash dda68fe91f45e497e6bd30d50b212830 */ /* eslint-disable */ @@ -10,14 +10,14 @@ /*:: import type { ConcreteRequest } from 'relay-runtime'; type issueishLookupByNumberContainer_repository$ref = any; -export type issueishPaneItemControllerQueryVariables = {| +export type issueishDetailContainerQueryVariables = {| repoOwner: string, repoName: string, issueishNumber: number, timelineCount: number, timelineCursor?: ?string, |}; -export type issueishPaneItemControllerQueryResponse = {| +export type issueishDetailContainerQueryResponse = {| +repository: ?{| +$fragmentRefs: issueishLookupByNumberContainer_repository$ref |} @@ -26,7 +26,7 @@ export type issueishPaneItemControllerQueryResponse = {| /* -query issueishPaneItemControllerQuery( +query issueishDetailContainerQuery( $repoOwner: String! $repoName: String! $issueishNumber: Int! @@ -896,13 +896,13 @@ v30 = { return { "kind": "Request", "operationKind": "query", - "name": "issueishPaneItemControllerQuery", + "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishPaneItemControllerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishLookupByNumberContainer_repository\n id\n }\n}\n\nfragment issueishLookupByNumberContainer_repository on Repository {\n ...issueishPaneItemContainer_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishPaneItemContainer_issueish\n }\n ... on PullRequest {\n title\n number\n ...issueishPaneItemContainer_issueish\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishPaneItemContainer_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishPaneItemContainer_issueish on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishLookupByNumberContainer_repository\n id\n }\n}\n\nfragment issueishLookupByNumberContainer_repository on Repository {\n ...issueishPaneItemContainer_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishPaneItemContainer_issueish\n }\n ... on PullRequest {\n title\n number\n ...issueishPaneItemContainer_issueish\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishPaneItemContainer_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishPaneItemContainer_issueish on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", - "name": "issueishPaneItemControllerQuery", + "name": "issueishDetailContainerQuery", "type": "Query", "metadata": null, "argumentDefinitions": v0, @@ -927,7 +927,7 @@ return { }, "operation": { "kind": "Operation", - "name": "issueishPaneItemControllerQuery", + "name": "issueishDetailContainerQuery", "argumentDefinitions": v0, "selections": [ { @@ -1342,5 +1342,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '1e85b50242815146b6a1e948e8b8a47d'; +(node/*: any*/).hash = 'a07360f886e4eb663defa81c3f6c8d65'; module.exports = node; diff --git a/lib/containers/__generated__/prInfoContainerRefetchQuery.graphql.js b/lib/containers/__generated__/prInfoContainerRefetchQuery.graphql.js deleted file mode 100644 index aceb369972..0000000000 --- a/lib/containers/__generated__/prInfoContainerRefetchQuery.graphql.js +++ /dev/null @@ -1,526 +0,0 @@ -/** - * @flow - * @relayHash 52a8f3e234b61e95dabaad1a37132167 - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteRequest } from 'relay-runtime'; -type prInfoContainer_pullRequest$ref = any; -export type prInfoContainerRefetchQueryVariables = {| - id: string -|}; -export type prInfoContainerRefetchQueryResponse = {| - +pullRequest: ?{| - +$fragmentRefs: prInfoContainer_pullRequest$ref - |} -|}; -*/ - - -/* -query prInfoContainerRefetchQuery( - $id: ID! -) { - pullRequest: node(id: $id) { - __typename - ... on PullRequest { - ...prInfoContainer_pullRequest - } - id - } -} - -fragment prInfoContainer_pullRequest on PullRequest { - ...prStatusesContainer_pullRequest - id - url - number - title - state - createdAt - author { - __typename - login - avatarUrl - ... on User { - url - } - ... on Bot { - url - } - ... on Node { - id - } - } - repository { - name - owner { - __typename - login - id - } - id - } - reactionGroups { - content - users { - totalCount - } - } - commitsCount: commits { - totalCount - } - labels(first: 100) { - edges { - node { - name - color - id - } - } - } -} - -fragment prStatusesContainer_pullRequest on PullRequest { - id - commits(last: 1) { - edges { - node { - commit { - status { - state - contexts { - id - state - ...prStatusContextContainer_context - } - id - } - id - } - id - } - } - } -} - -fragment prStatusContextContainer_context on StatusContext { - context - description - state - targetUrl -} -*/ - -const node/*: ConcreteRequest*/ = (function(){ -var v0 = [ - { - "kind": "LocalArgument", - "name": "id", - "type": "ID!", - "defaultValue": null - } -], -v1 = [ - { - "kind": "Variable", - "name": "id", - "variableName": "id", - "type": "ID!" - } -], -v2 = { - "kind": "ScalarField", - "alias": null, - "name": "__typename", - "args": null, - "storageKey": null -}, -v3 = { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null -}, -v4 = { - "kind": "ScalarField", - "alias": null, - "name": "url", - "args": null, - "storageKey": null -}, -v5 = { - "kind": "ScalarField", - "alias": null, - "name": "state", - "args": null, - "storageKey": null -}, -v6 = { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null -}, -v7 = [ - v4 -], -v8 = { - "kind": "ScalarField", - "alias": null, - "name": "name", - "args": null, - "storageKey": null -}, -v9 = [ - { - "kind": "ScalarField", - "alias": null, - "name": "totalCount", - "args": null, - "storageKey": null - } -]; -return { - "kind": "Request", - "operationKind": "query", - "name": "prInfoContainerRefetchQuery", - "id": null, - "text": "query prInfoContainerRefetchQuery(\n $id: ID!\n) {\n pullRequest: node(id: $id) {\n __typename\n ... on PullRequest {\n ...prInfoContainer_pullRequest\n }\n id\n }\n}\n\nfragment prInfoContainer_pullRequest on PullRequest {\n ...prStatusesContainer_pullRequest\n id\n url\n number\n title\n state\n createdAt\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n commitsCount: commits {\n totalCount\n }\n labels(first: 100) {\n edges {\n node {\n name\n color\n id\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", - "metadata": {}, - "fragment": { - "kind": "Fragment", - "name": "prInfoContainerRefetchQuery", - "type": "Query", - "metadata": null, - "argumentDefinitions": v0, - "selections": [ - { - "kind": "LinkedField", - "alias": "pullRequest", - "name": "node", - "storageKey": null, - "args": v1, - "concreteType": null, - "plural": false, - "selections": [ - { - "kind": "InlineFragment", - "type": "PullRequest", - "selections": [ - { - "kind": "FragmentSpread", - "name": "prInfoContainer_pullRequest", - "args": null - } - ] - } - ] - } - ] - }, - "operation": { - "kind": "Operation", - "name": "prInfoContainerRefetchQuery", - "argumentDefinitions": v0, - "selections": [ - { - "kind": "LinkedField", - "alias": "pullRequest", - "name": "node", - "storageKey": null, - "args": v1, - "concreteType": null, - "plural": false, - "selections": [ - v2, - v3, - { - "kind": "InlineFragment", - "type": "PullRequest", - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - }, - v4, - { - "kind": "ScalarField", - "alias": null, - "name": "number", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "title", - "args": null, - "storageKey": null - }, - v5, - { - "kind": "LinkedField", - "alias": null, - "name": "commits", - "storageKey": "commits(last:1)", - "args": [ - { - "kind": "Literal", - "name": "last", - "value": 1, - "type": "Int" - } - ], - "concreteType": "PullRequestCommitConnection", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "edges", - "storageKey": null, - "args": null, - "concreteType": "PullRequestCommitEdge", - "plural": true, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "node", - "storageKey": null, - "args": null, - "concreteType": "PullRequestCommit", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "status", - "storageKey": null, - "args": null, - "concreteType": "Status", - "plural": false, - "selections": [ - v5, - { - "kind": "LinkedField", - "alias": null, - "name": "contexts", - "storageKey": null, - "args": null, - "concreteType": "StatusContext", - "plural": true, - "selections": [ - v3, - v5, - { - "kind": "ScalarField", - "alias": null, - "name": "context", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "description", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "targetUrl", - "args": null, - "storageKey": null - } - ] - }, - v3 - ] - }, - v3 - ] - }, - v3 - ] - } - ] - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v2, - v6, - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - }, - v3, - { - "kind": "InlineFragment", - "type": "Bot", - "selections": v7 - }, - { - "kind": "InlineFragment", - "type": "User", - "selections": v7 - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "repository", - "storageKey": null, - "args": null, - "concreteType": "Repository", - "plural": false, - "selections": [ - v8, - { - "kind": "LinkedField", - "alias": null, - "name": "owner", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v2, - v6, - v3 - ] - }, - v3 - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "reactionGroups", - "storageKey": null, - "args": null, - "concreteType": "ReactionGroup", - "plural": true, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "content", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "users", - "storageKey": null, - "args": null, - "concreteType": "ReactingUserConnection", - "plural": false, - "selections": v9 - } - ] - }, - { - "kind": "LinkedField", - "alias": "commitsCount", - "name": "commits", - "storageKey": null, - "args": null, - "concreteType": "PullRequestCommitConnection", - "plural": false, - "selections": v9 - }, - { - "kind": "LinkedField", - "alias": null, - "name": "labels", - "storageKey": "labels(first:100)", - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 100, - "type": "Int" - } - ], - "concreteType": "LabelConnection", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "edges", - "storageKey": null, - "args": null, - "concreteType": "LabelEdge", - "plural": true, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "node", - "storageKey": null, - "args": null, - "concreteType": "Label", - "plural": false, - "selections": [ - v8, - { - "kind": "ScalarField", - "alias": null, - "name": "color", - "args": null, - "storageKey": null - }, - v3 - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } -}; -})(); -// prettier-ignore -(node/*: any*/).hash = 'ef75b0c0aad4b29aad4e7759ffc27a76'; -module.exports = node; diff --git a/lib/containers/__generated__/prInfoContainer_pullRequest.graphql.js b/lib/containers/__generated__/prInfoContainer_pullRequest.graphql.js deleted file mode 100644 index b39928c2f4..0000000000 --- a/lib/containers/__generated__/prInfoContainer_pullRequest.graphql.js +++ /dev/null @@ -1,283 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -type prStatusesContainer_pullRequest$ref = any; -export type PullRequestState = "CLOSED" | "MERGED" | "OPEN" | "%future added value"; -export type ReactionContent = "CONFUSED" | "HEART" | "HOORAY" | "LAUGH" | "THUMBS_DOWN" | "THUMBS_UP" | "%future added value"; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type prInfoContainer_pullRequest$ref: FragmentReference; -export type prInfoContainer_pullRequest = {| - +id: string, - +url: any, - +number: number, - +title: string, - +state: PullRequestState, - +createdAt: any, - +author: ?{| - +login: string, - +avatarUrl: any, - +url?: any, - |}, - +repository: {| - +name: string, - +owner: {| - +login: string - |}, - |}, - +reactionGroups: ?$ReadOnlyArray<{| - +content: ReactionContent, - +users: {| - +totalCount: number - |}, - |}>, - +commitsCount: {| - +totalCount: number - |}, - +labels: ?{| - +edges: ?$ReadOnlyArray - |}, - +$fragmentRefs: prStatusesContainer_pullRequest$ref, - +$refType: prInfoContainer_pullRequest$ref, -|}; -*/ - - -const node/*: ConcreteFragment*/ = (function(){ -var v0 = { - "kind": "ScalarField", - "alias": null, - "name": "url", - "args": null, - "storageKey": null -}, -v1 = { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null -}, -v2 = [ - v0 -], -v3 = { - "kind": "ScalarField", - "alias": null, - "name": "name", - "args": null, - "storageKey": null -}, -v4 = [ - { - "kind": "ScalarField", - "alias": null, - "name": "totalCount", - "args": null, - "storageKey": null - } -]; -return { - "kind": "Fragment", - "name": "prInfoContainer_pullRequest", - "type": "PullRequest", - "metadata": null, - "argumentDefinitions": [], - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - }, - { - "kind": "FragmentSpread", - "name": "prStatusesContainer_pullRequest", - "args": null - }, - v0, - { - "kind": "ScalarField", - "alias": null, - "name": "number", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "title", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "state", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v1, - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - }, - { - "kind": "InlineFragment", - "type": "Bot", - "selections": v2 - }, - { - "kind": "InlineFragment", - "type": "User", - "selections": v2 - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "repository", - "storageKey": null, - "args": null, - "concreteType": "Repository", - "plural": false, - "selections": [ - v3, - { - "kind": "LinkedField", - "alias": null, - "name": "owner", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v1 - ] - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "reactionGroups", - "storageKey": null, - "args": null, - "concreteType": "ReactionGroup", - "plural": true, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "content", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "users", - "storageKey": null, - "args": null, - "concreteType": "ReactingUserConnection", - "plural": false, - "selections": v4 - } - ] - }, - { - "kind": "LinkedField", - "alias": "commitsCount", - "name": "commits", - "storageKey": null, - "args": null, - "concreteType": "PullRequestCommitConnection", - "plural": false, - "selections": v4 - }, - { - "kind": "LinkedField", - "alias": null, - "name": "labels", - "storageKey": "labels(first:100)", - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 100, - "type": "Int" - } - ], - "concreteType": "LabelConnection", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "edges", - "storageKey": null, - "args": null, - "concreteType": "LabelEdge", - "plural": true, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "node", - "storageKey": null, - "args": null, - "concreteType": "Label", - "plural": false, - "selections": [ - v3, - { - "kind": "ScalarField", - "alias": null, - "name": "color", - "args": null, - "storageKey": null - } - ] - } - ] - } - ] - } - ] -}; -})(); -// prettier-ignore -(node/*: any*/).hash = 'c65b180836c0f22ff0492dd3d18276d0'; -module.exports = node; diff --git a/lib/containers/__generated__/prSelectionByBranchContainer_repository.graphql.js b/lib/containers/__generated__/prSelectionByBranchContainer_repository.graphql.js deleted file mode 100644 index 00013792a7..0000000000 --- a/lib/containers/__generated__/prSelectionByBranchContainer_repository.graphql.js +++ /dev/null @@ -1,164 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -type prInfoContainer_pullRequest$ref = any; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type prSelectionByBranchContainer_repository$ref: FragmentReference; -export type prSelectionByBranchContainer_repository = {| - +defaultBranchRef: ?{| - +prefix: string, - +name: string, - |}, - +pullRequests: {| - +totalCount: number, - +edges: ?$ReadOnlyArray, - |}, - +$refType: prSelectionByBranchContainer_repository$ref, -|}; -*/ - - -const node/*: ConcreteFragment*/ = { - "kind": "Fragment", - "name": "prSelectionByBranchContainer_repository", - "type": "Repository", - "metadata": null, - "argumentDefinitions": [ - { - "kind": "RootArgument", - "name": "branchName", - "type": "String" - } - ], - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "defaultBranchRef", - "storageKey": null, - "args": null, - "concreteType": "Ref", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "prefix", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "name", - "args": null, - "storageKey": null - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "pullRequests", - "storageKey": null, - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 30, - "type": "Int" - }, - { - "kind": "Variable", - "name": "headRefName", - "variableName": "branchName", - "type": "String" - } - ], - "concreteType": "PullRequestConnection", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "totalCount", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "edges", - "storageKey": null, - "args": null, - "concreteType": "PullRequestEdge", - "plural": true, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "node", - "storageKey": null, - "args": null, - "concreteType": "PullRequest", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "number", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "title", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "url", - "args": null, - "storageKey": null - }, - { - "kind": "FragmentSpread", - "name": "prInfoContainer_pullRequest", - "args": null - } - ] - } - ] - } - ] - } - ] -}; -// prettier-ignore -(node/*: any*/).hash = '5563c813ad25fad3aaf8cf2c1974f88d'; -module.exports = node; diff --git a/lib/containers/__generated__/prSelectionByUrlContainer_resource.graphql.js b/lib/containers/__generated__/prSelectionByUrlContainer_resource.graphql.js deleted file mode 100644 index dd80b1b1c0..0000000000 --- a/lib/containers/__generated__/prSelectionByUrlContainer_resource.graphql.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -type prInfoContainer_pullRequest$ref = any; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type prSelectionByUrlContainer_resource$ref: FragmentReference; -export type prSelectionByUrlContainer_resource = {| - +__typename: "PullRequest", - +$fragmentRefs: prInfoContainer_pullRequest$ref, - +$refType: prSelectionByUrlContainer_resource$ref, -|} | {| - // This will never be '%other', but we need some - // value in case none of the concrete values match. - +__typename: "%other", - +$refType: prSelectionByUrlContainer_resource$ref, -|}; -*/ - - -const node/*: ConcreteFragment*/ = { - "kind": "Fragment", - "name": "prSelectionByUrlContainer_resource", - "type": "UniformResourceLocatable", - "metadata": null, - "argumentDefinitions": [], - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "__typename", - "args": null, - "storageKey": null - }, - { - "kind": "InlineFragment", - "type": "PullRequest", - "selections": [ - { - "kind": "FragmentSpread", - "name": "prInfoContainer_pullRequest", - "args": null - } - ] - } - ] -}; -// prettier-ignore -(node/*: any*/).hash = '40bb7b845477903ff9a23d9ea731c3c6'; -module.exports = node; diff --git a/lib/controllers/__generated__/prInfoControllerByBranchQuery.graphql.js b/lib/controllers/__generated__/prInfoControllerByBranchQuery.graphql.js deleted file mode 100644 index 7ab1057a1b..0000000000 --- a/lib/controllers/__generated__/prInfoControllerByBranchQuery.graphql.js +++ /dev/null @@ -1,621 +0,0 @@ -/** - * @flow - * @relayHash fa02aa04af62bcd905ec133838af7f82 - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteRequest } from 'relay-runtime'; -type prSelectionByBranchContainer_repository$ref = any; -export type prInfoControllerByBranchQueryVariables = {| - repoOwner: string, - repoName: string, - branchName: string, -|}; -export type prInfoControllerByBranchQueryResponse = {| - +repository: ?{| - +$fragmentRefs: prSelectionByBranchContainer_repository$ref - |} -|}; -*/ - - -/* -query prInfoControllerByBranchQuery( - $repoOwner: String! - $repoName: String! - $branchName: String! -) { - repository(owner: $repoOwner, name: $repoName) { - ...prSelectionByBranchContainer_repository - id - } -} - -fragment prSelectionByBranchContainer_repository on Repository { - defaultBranchRef { - prefix - name - id - } - pullRequests(first: 30, headRefName: $branchName) { - totalCount - edges { - node { - id - number - title - url - ...prInfoContainer_pullRequest - } - } - } -} - -fragment prInfoContainer_pullRequest on PullRequest { - ...prStatusesContainer_pullRequest - id - url - number - title - state - createdAt - author { - __typename - login - avatarUrl - ... on User { - url - } - ... on Bot { - url - } - ... on Node { - id - } - } - repository { - name - owner { - __typename - login - id - } - id - } - reactionGroups { - content - users { - totalCount - } - } - commitsCount: commits { - totalCount - } - labels(first: 100) { - edges { - node { - name - color - id - } - } - } -} - -fragment prStatusesContainer_pullRequest on PullRequest { - id - commits(last: 1) { - edges { - node { - commit { - status { - state - contexts { - id - state - ...prStatusContextContainer_context - } - id - } - id - } - id - } - } - } -} - -fragment prStatusContextContainer_context on StatusContext { - context - description - state - targetUrl -} -*/ - -const node/*: ConcreteRequest*/ = (function(){ -var v0 = [ - { - "kind": "LocalArgument", - "name": "repoOwner", - "type": "String!", - "defaultValue": null - }, - { - "kind": "LocalArgument", - "name": "repoName", - "type": "String!", - "defaultValue": null - }, - { - "kind": "LocalArgument", - "name": "branchName", - "type": "String!", - "defaultValue": null - } -], -v1 = [ - { - "kind": "Variable", - "name": "name", - "variableName": "repoName", - "type": "String!" - }, - { - "kind": "Variable", - "name": "owner", - "variableName": "repoOwner", - "type": "String!" - } -], -v2 = { - "kind": "ScalarField", - "alias": null, - "name": "name", - "args": null, - "storageKey": null -}, -v3 = { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null -}, -v4 = { - "kind": "ScalarField", - "alias": null, - "name": "totalCount", - "args": null, - "storageKey": null -}, -v5 = { - "kind": "ScalarField", - "alias": null, - "name": "url", - "args": null, - "storageKey": null -}, -v6 = { - "kind": "ScalarField", - "alias": null, - "name": "state", - "args": null, - "storageKey": null -}, -v7 = { - "kind": "ScalarField", - "alias": null, - "name": "__typename", - "args": null, - "storageKey": null -}, -v8 = { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null -}, -v9 = [ - v5 -], -v10 = [ - v4 -]; -return { - "kind": "Request", - "operationKind": "query", - "name": "prInfoControllerByBranchQuery", - "id": null, - "text": "query prInfoControllerByBranchQuery(\n $repoOwner: String!\n $repoName: String!\n $branchName: String!\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...prSelectionByBranchContainer_repository\n id\n }\n}\n\nfragment prSelectionByBranchContainer_repository on Repository {\n defaultBranchRef {\n prefix\n name\n id\n }\n pullRequests(first: 30, headRefName: $branchName) {\n totalCount\n edges {\n node {\n id\n number\n title\n url\n ...prInfoContainer_pullRequest\n }\n }\n }\n}\n\nfragment prInfoContainer_pullRequest on PullRequest {\n ...prStatusesContainer_pullRequest\n id\n url\n number\n title\n state\n createdAt\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n commitsCount: commits {\n totalCount\n }\n labels(first: 100) {\n edges {\n node {\n name\n color\n id\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", - "metadata": {}, - "fragment": { - "kind": "Fragment", - "name": "prInfoControllerByBranchQuery", - "type": "Query", - "metadata": null, - "argumentDefinitions": v0, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "repository", - "storageKey": null, - "args": v1, - "concreteType": "Repository", - "plural": false, - "selections": [ - { - "kind": "FragmentSpread", - "name": "prSelectionByBranchContainer_repository", - "args": null - } - ] - } - ] - }, - "operation": { - "kind": "Operation", - "name": "prInfoControllerByBranchQuery", - "argumentDefinitions": v0, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "repository", - "storageKey": null, - "args": v1, - "concreteType": "Repository", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "defaultBranchRef", - "storageKey": null, - "args": null, - "concreteType": "Ref", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "prefix", - "args": null, - "storageKey": null - }, - v2, - v3 - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "pullRequests", - "storageKey": null, - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 30, - "type": "Int" - }, - { - "kind": "Variable", - "name": "headRefName", - "variableName": "branchName", - "type": "String" - } - ], - "concreteType": "PullRequestConnection", - "plural": false, - "selections": [ - v4, - { - "kind": "LinkedField", - "alias": null, - "name": "edges", - "storageKey": null, - "args": null, - "concreteType": "PullRequestEdge", - "plural": true, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "node", - "storageKey": null, - "args": null, - "concreteType": "PullRequest", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - }, - v3, - { - "kind": "ScalarField", - "alias": null, - "name": "title", - "args": null, - "storageKey": null - }, - v5, - { - "kind": "LinkedField", - "alias": null, - "name": "commits", - "storageKey": "commits(last:1)", - "args": [ - { - "kind": "Literal", - "name": "last", - "value": 1, - "type": "Int" - } - ], - "concreteType": "PullRequestCommitConnection", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "edges", - "storageKey": null, - "args": null, - "concreteType": "PullRequestCommitEdge", - "plural": true, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "node", - "storageKey": null, - "args": null, - "concreteType": "PullRequestCommit", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "status", - "storageKey": null, - "args": null, - "concreteType": "Status", - "plural": false, - "selections": [ - v6, - { - "kind": "LinkedField", - "alias": null, - "name": "contexts", - "storageKey": null, - "args": null, - "concreteType": "StatusContext", - "plural": true, - "selections": [ - v3, - v6, - { - "kind": "ScalarField", - "alias": null, - "name": "context", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "description", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "targetUrl", - "args": null, - "storageKey": null - } - ] - }, - v3 - ] - }, - v3 - ] - }, - v3 - ] - } - ] - } - ] - }, - v6, - { - "kind": "ScalarField", - "alias": null, - "name": "number", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v7, - v8, - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - }, - v3, - { - "kind": "InlineFragment", - "type": "Bot", - "selections": v9 - }, - { - "kind": "InlineFragment", - "type": "User", - "selections": v9 - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "repository", - "storageKey": null, - "args": null, - "concreteType": "Repository", - "plural": false, - "selections": [ - v2, - { - "kind": "LinkedField", - "alias": null, - "name": "owner", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v7, - v8, - v3 - ] - }, - v3 - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "reactionGroups", - "storageKey": null, - "args": null, - "concreteType": "ReactionGroup", - "plural": true, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "content", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "users", - "storageKey": null, - "args": null, - "concreteType": "ReactingUserConnection", - "plural": false, - "selections": v10 - } - ] - }, - { - "kind": "LinkedField", - "alias": "commitsCount", - "name": "commits", - "storageKey": null, - "args": null, - "concreteType": "PullRequestCommitConnection", - "plural": false, - "selections": v10 - }, - { - "kind": "LinkedField", - "alias": null, - "name": "labels", - "storageKey": "labels(first:100)", - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 100, - "type": "Int" - } - ], - "concreteType": "LabelConnection", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "edges", - "storageKey": null, - "args": null, - "concreteType": "LabelEdge", - "plural": true, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "node", - "storageKey": null, - "args": null, - "concreteType": "Label", - "plural": false, - "selections": [ - v2, - { - "kind": "ScalarField", - "alias": null, - "name": "color", - "args": null, - "storageKey": null - }, - v3 - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - v3 - ] - } - ] - } -}; -})(); -// prettier-ignore -(node/*: any*/).hash = '58c9d065a2b85f41738684f246b82180'; -module.exports = node; diff --git a/lib/controllers/__generated__/prInfoControllerByUrlQuery.graphql.js b/lib/controllers/__generated__/prInfoControllerByUrlQuery.graphql.js deleted file mode 100644 index 5f4a2c1cf0..0000000000 --- a/lib/controllers/__generated__/prInfoControllerByUrlQuery.graphql.js +++ /dev/null @@ -1,527 +0,0 @@ -/** - * @flow - * @relayHash 839c1fd7991eda8a3422b7a2239f8065 - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteRequest } from 'relay-runtime'; -type prSelectionByUrlContainer_resource$ref = any; -export type prInfoControllerByUrlQueryVariables = {| - prUrl: any -|}; -export type prInfoControllerByUrlQueryResponse = {| - +resource: ?{| - +$fragmentRefs: prSelectionByUrlContainer_resource$ref - |} -|}; -*/ - - -/* -query prInfoControllerByUrlQuery( - $prUrl: URI! -) { - resource(url: $prUrl) { - __typename - ...prSelectionByUrlContainer_resource - ... on Node { - id - } - } -} - -fragment prSelectionByUrlContainer_resource on UniformResourceLocatable { - __typename - ... on PullRequest { - ...prInfoContainer_pullRequest - } -} - -fragment prInfoContainer_pullRequest on PullRequest { - ...prStatusesContainer_pullRequest - id - url - number - title - state - createdAt - author { - __typename - login - avatarUrl - ... on User { - url - } - ... on Bot { - url - } - ... on Node { - id - } - } - repository { - name - owner { - __typename - login - id - } - id - } - reactionGroups { - content - users { - totalCount - } - } - commitsCount: commits { - totalCount - } - labels(first: 100) { - edges { - node { - name - color - id - } - } - } -} - -fragment prStatusesContainer_pullRequest on PullRequest { - id - commits(last: 1) { - edges { - node { - commit { - status { - state - contexts { - id - state - ...prStatusContextContainer_context - } - id - } - id - } - id - } - } - } -} - -fragment prStatusContextContainer_context on StatusContext { - context - description - state - targetUrl -} -*/ - -const node/*: ConcreteRequest*/ = (function(){ -var v0 = [ - { - "kind": "LocalArgument", - "name": "prUrl", - "type": "URI!", - "defaultValue": null - } -], -v1 = [ - { - "kind": "Variable", - "name": "url", - "variableName": "prUrl", - "type": "URI!" - } -], -v2 = { - "kind": "ScalarField", - "alias": null, - "name": "__typename", - "args": null, - "storageKey": null -}, -v3 = { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null -}, -v4 = { - "kind": "ScalarField", - "alias": null, - "name": "url", - "args": null, - "storageKey": null -}, -v5 = { - "kind": "ScalarField", - "alias": null, - "name": "state", - "args": null, - "storageKey": null -}, -v6 = { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null -}, -v7 = [ - v4 -], -v8 = { - "kind": "ScalarField", - "alias": null, - "name": "name", - "args": null, - "storageKey": null -}, -v9 = [ - { - "kind": "ScalarField", - "alias": null, - "name": "totalCount", - "args": null, - "storageKey": null - } -]; -return { - "kind": "Request", - "operationKind": "query", - "name": "prInfoControllerByUrlQuery", - "id": null, - "text": "query prInfoControllerByUrlQuery(\n $prUrl: URI!\n) {\n resource(url: $prUrl) {\n __typename\n ...prSelectionByUrlContainer_resource\n ... on Node {\n id\n }\n }\n}\n\nfragment prSelectionByUrlContainer_resource on UniformResourceLocatable {\n __typename\n ... on PullRequest {\n ...prInfoContainer_pullRequest\n }\n}\n\nfragment prInfoContainer_pullRequest on PullRequest {\n ...prStatusesContainer_pullRequest\n id\n url\n number\n title\n state\n createdAt\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n commitsCount: commits {\n totalCount\n }\n labels(first: 100) {\n edges {\n node {\n name\n color\n id\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", - "metadata": {}, - "fragment": { - "kind": "Fragment", - "name": "prInfoControllerByUrlQuery", - "type": "Query", - "metadata": null, - "argumentDefinitions": v0, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "resource", - "storageKey": null, - "args": v1, - "concreteType": null, - "plural": false, - "selections": [ - { - "kind": "FragmentSpread", - "name": "prSelectionByUrlContainer_resource", - "args": null - } - ] - } - ] - }, - "operation": { - "kind": "Operation", - "name": "prInfoControllerByUrlQuery", - "argumentDefinitions": v0, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "resource", - "storageKey": null, - "args": v1, - "concreteType": null, - "plural": false, - "selections": [ - v2, - v3, - { - "kind": "InlineFragment", - "type": "PullRequest", - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - }, - v4, - { - "kind": "ScalarField", - "alias": null, - "name": "number", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "title", - "args": null, - "storageKey": null - }, - v5, - { - "kind": "LinkedField", - "alias": null, - "name": "commits", - "storageKey": "commits(last:1)", - "args": [ - { - "kind": "Literal", - "name": "last", - "value": 1, - "type": "Int" - } - ], - "concreteType": "PullRequestCommitConnection", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "edges", - "storageKey": null, - "args": null, - "concreteType": "PullRequestCommitEdge", - "plural": true, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "node", - "storageKey": null, - "args": null, - "concreteType": "PullRequestCommit", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "status", - "storageKey": null, - "args": null, - "concreteType": "Status", - "plural": false, - "selections": [ - v5, - { - "kind": "LinkedField", - "alias": null, - "name": "contexts", - "storageKey": null, - "args": null, - "concreteType": "StatusContext", - "plural": true, - "selections": [ - v3, - v5, - { - "kind": "ScalarField", - "alias": null, - "name": "context", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "description", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "targetUrl", - "args": null, - "storageKey": null - } - ] - }, - v3 - ] - }, - v3 - ] - }, - v3 - ] - } - ] - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v2, - v6, - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - }, - v3, - { - "kind": "InlineFragment", - "type": "Bot", - "selections": v7 - }, - { - "kind": "InlineFragment", - "type": "User", - "selections": v7 - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "repository", - "storageKey": null, - "args": null, - "concreteType": "Repository", - "plural": false, - "selections": [ - v8, - { - "kind": "LinkedField", - "alias": null, - "name": "owner", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v2, - v6, - v3 - ] - }, - v3 - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "reactionGroups", - "storageKey": null, - "args": null, - "concreteType": "ReactionGroup", - "plural": true, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "content", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "users", - "storageKey": null, - "args": null, - "concreteType": "ReactingUserConnection", - "plural": false, - "selections": v9 - } - ] - }, - { - "kind": "LinkedField", - "alias": "commitsCount", - "name": "commits", - "storageKey": null, - "args": null, - "concreteType": "PullRequestCommitConnection", - "plural": false, - "selections": v9 - }, - { - "kind": "LinkedField", - "alias": null, - "name": "labels", - "storageKey": "labels(first:100)", - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 100, - "type": "Int" - } - ], - "concreteType": "LabelConnection", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "edges", - "storageKey": null, - "args": null, - "concreteType": "LabelEdge", - "plural": true, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "node", - "storageKey": null, - "args": null, - "concreteType": "Label", - "plural": false, - "selections": [ - v8, - { - "kind": "ScalarField", - "alias": null, - "name": "color", - "args": null, - "storageKey": null - }, - v3 - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } -}; -})(); -// prettier-ignore -(node/*: any*/).hash = '38bb43fa32da4f8d97b3e8dbd1ac8626'; -module.exports = node; From e8332e981556a4bc2c2442c9742323eeae2e7d5a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 11:50:52 -0400 Subject: [PATCH 0394/4847] Schema :arrow_up: --- graphql/schema.graphql | 511 ++++++++++++++++++++++++----------------- 1 file changed, 297 insertions(+), 214 deletions(-) diff --git a/graphql/schema.graphql b/graphql/schema.graphql index bfc1bd958e..720f5e59bb 100644 --- a/graphql/schema.graphql +++ b/graphql/schema.graphql @@ -253,7 +253,7 @@ interface Assignable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -261,7 +261,7 @@ interface Assignable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserConnection! @@ -423,7 +423,7 @@ interface Closable { } """Represents a 'closed' event on any `Closable`.""" -type ClosedEvent implements Node { +type ClosedEvent implements Node & UniformResourceLocatable { """Identifies the actor who performed the event.""" actor: Actor @@ -439,6 +439,12 @@ type ClosedEvent implements Node { """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! + + """The HTTP path for this closed event.""" + resourcePath: URI! + + """The HTTP URL for this closed event.""" + url: URI! } """The object which triggered a `ClosedEvent`.""" @@ -503,6 +509,11 @@ interface Comment { editor: Actor id: ID! + """ + Check if this comment was edited and includes an edit with the creation data + """ + includesCreatedEdit: Boolean! + """The moment the editor made the last edit""" lastEditedAt: DateTime @@ -518,7 +529,7 @@ interface Comment { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -526,7 +537,7 @@ interface Comment { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserContentEditConnection @@ -626,7 +637,7 @@ type Commit implements Node & GitObject & Subscribable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -634,7 +645,7 @@ type Commit implements Node & GitObject & Subscribable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): CommitCommentConnection! @@ -665,7 +676,7 @@ type Commit implements Node & GitObject & Subscribable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -673,7 +684,7 @@ type Commit implements Node & GitObject & Subscribable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -719,7 +730,7 @@ type Commit implements Node & GitObject & Subscribable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -727,7 +738,7 @@ type Commit implements Node & GitObject & Subscribable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): CommitConnection! @@ -831,6 +842,11 @@ type CommitComment implements Node & Comment & Deletable & Updatable & Updatable editor: Actor id: ID! + """ + Check if this comment was edited and includes an edit with the creation data + """ + includesCreatedEdit: Boolean! + """The moment the editor made the last edit""" lastEditedAt: DateTime @@ -852,7 +868,7 @@ type CommitComment implements Node & Comment & Deletable & Updatable & Updatable first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -860,7 +876,7 @@ type CommitComment implements Node & Comment & Deletable & Updatable & Updatable last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -889,7 +905,7 @@ type CommitComment implements Node & Comment & Deletable & Updatable & Updatable first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -897,7 +913,7 @@ type CommitComment implements Node & Comment & Deletable & Updatable & Updatable last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserContentEditConnection @@ -950,7 +966,7 @@ type CommitCommentThread implements Node & RepositoryNode { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -958,7 +974,7 @@ type CommitCommentThread implements Node & RepositoryNode { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): CommitCommentConnection! @@ -1333,7 +1349,7 @@ type Deployment implements Node { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -1341,7 +1357,7 @@ type Deployment implements Node { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): DeploymentStatusConnection @@ -1593,7 +1609,7 @@ type Gist implements Node & Starrable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -1601,7 +1617,7 @@ type Gist implements Node & Starrable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): GistCommentConnection! @@ -1631,7 +1647,7 @@ type Gist implements Node & Starrable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -1639,7 +1655,7 @@ type Gist implements Node & Starrable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -1689,6 +1705,11 @@ type GistComment implements Node & Comment & Deletable & Updatable & UpdatableCo gist: Gist! id: ID! + """ + Check if this comment was edited and includes an edit with the creation data + """ + includesCreatedEdit: Boolean! + """The moment the editor made the last edit""" lastEditedAt: DateTime @@ -1704,7 +1725,7 @@ type GistComment implements Node & Comment & Deletable & Updatable & UpdatableCo first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -1712,7 +1733,7 @@ type GistComment implements Node & Comment & Deletable & Updatable & UpdatableCo last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserContentEditConnection @@ -2077,7 +2098,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2085,7 +2106,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserConnection! @@ -2119,7 +2140,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2127,7 +2148,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): IssueCommentConnection! @@ -2145,13 +2166,18 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat editor: Actor id: ID! + """ + Check if this comment was edited and includes an edit with the creation data + """ + includesCreatedEdit: Boolean! + """A list of labels associated with the object.""" labels( """Returns the first _n_ elements from the list.""" first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2159,7 +2185,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): LabelConnection @@ -2182,7 +2208,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2190,7 +2216,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserConnection! @@ -2201,7 +2227,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2209,7 +2235,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): ProjectCardConnection! @@ -2226,7 +2252,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2234,7 +2260,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -2260,7 +2286,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2268,7 +2294,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -2291,7 +2317,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2299,7 +2325,7 @@ type Issue implements Node & Assignable & Closable & Comment & Updatable & Updat last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserContentEditConnection @@ -2357,6 +2383,11 @@ type IssueComment implements Node & Comment & Deletable & Updatable & UpdatableC editor: Actor id: ID! + """ + Check if this comment was edited and includes an edit with the creation data + """ + includesCreatedEdit: Boolean! + """Identifies the issue associated with the comment.""" issue: Issue! @@ -2382,7 +2413,7 @@ type IssueComment implements Node & Comment & Deletable & Updatable & UpdatableC first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2390,7 +2421,7 @@ type IssueComment implements Node & Comment & Deletable & Updatable & UpdatableC last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -2419,7 +2450,7 @@ type IssueComment implements Node & Comment & Deletable & Updatable & UpdatableC first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2427,7 +2458,7 @@ type IssueComment implements Node & Comment & Deletable & Updatable & UpdatableC last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserContentEditConnection @@ -2591,7 +2622,7 @@ type Label implements Node { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2599,7 +2630,7 @@ type Label implements Node { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -2622,7 +2653,7 @@ type Label implements Node { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2630,7 +2661,7 @@ type Label implements Node { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -2671,7 +2702,7 @@ interface Labelable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -2679,7 +2710,7 @@ interface Labelable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): LabelConnection @@ -2777,8 +2808,8 @@ enum LanguageOrderField { SIZE } -"""A respository's open source license""" -type License { +"""A repository's open source license""" +type License implements Node { """The full text of the license""" body: String! @@ -2907,7 +2938,7 @@ enum LockReason { } """A public description of a Marketplace category.""" -type MarketplaceCategory { +type MarketplaceCategory implements Node { """The category's description.""" description: String @@ -2915,6 +2946,7 @@ type MarketplaceCategory { The technical description of how apps listed in this category work with GitHub. """ howItWorks: String + id: ID! """The category's name.""" name: String! @@ -3238,7 +3270,7 @@ type Milestone implements Node & Closable & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -3246,7 +3278,7 @@ type Milestone implements Node & Closable & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -3269,7 +3301,7 @@ type Milestone implements Node & Closable & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -3277,7 +3309,7 @@ type Milestone implements Node & Closable & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -3533,6 +3565,9 @@ type Mutation { """Submits a pending pull request review.""" submitPullRequestReview(input: SubmitPullRequestReviewInput!): SubmitPullRequestReviewPayload + """Unlock a lockable object""" + unlockLockable(input: UnlockLockableInput!): UnlockLockablePayload + """Updates an existing project.""" updateProject(input: UpdateProjectInput!): UpdateProjectPayload @@ -3604,7 +3639,7 @@ type Organization implements Node & Actor & ProjectOwner & RepositoryOwner & Uni first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -3612,7 +3647,7 @@ type Organization implements Node & Actor & ProjectOwner & RepositoryOwner & Uni last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserConnection! @@ -3635,7 +3670,7 @@ type Organization implements Node & Actor & ProjectOwner & RepositoryOwner & Uni first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -3643,7 +3678,7 @@ type Organization implements Node & Actor & ProjectOwner & RepositoryOwner & Uni last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -3674,7 +3709,7 @@ type Organization implements Node & Actor & ProjectOwner & RepositoryOwner & Uni first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -3682,7 +3717,7 @@ type Organization implements Node & Actor & ProjectOwner & RepositoryOwner & Uni last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -3708,7 +3743,7 @@ type Organization implements Node & Actor & ProjectOwner & RepositoryOwner & Uni first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -3716,7 +3751,7 @@ type Organization implements Node & Actor & ProjectOwner & RepositoryOwner & Uni last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -3764,7 +3799,7 @@ type Organization implements Node & Actor & ProjectOwner & RepositoryOwner & Uni first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -3772,7 +3807,7 @@ type Organization implements Node & Actor & ProjectOwner & RepositoryOwner & Uni last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -3869,7 +3904,7 @@ type OrganizationIdentityProvider implements Node { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -3877,7 +3912,7 @@ type OrganizationIdentityProvider implements Node { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): ExternalIdentityConnection! @@ -4015,7 +4050,7 @@ type Project implements Node & Closable & Updatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4023,7 +4058,7 @@ type Project implements Node & Closable & Updatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): ProjectColumnConnection! @@ -4055,7 +4090,7 @@ type Project implements Node & Closable & Updatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4063,7 +4098,7 @@ type Project implements Node & Closable & Updatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): ProjectCardConnection! @@ -4177,7 +4212,7 @@ type ProjectColumn implements Node { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4185,7 +4220,7 @@ type ProjectColumn implements Node { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): ProjectCardConnection! @@ -4298,7 +4333,7 @@ interface ProjectOwner { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4306,7 +4341,7 @@ interface ProjectOwner { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -4377,7 +4412,7 @@ type ProtectedBranch implements Node { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4385,7 +4420,7 @@ type ProtectedBranch implements Node { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): PushAllowanceConnection! @@ -4404,7 +4439,7 @@ type ProtectedBranch implements Node { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4412,7 +4447,7 @@ type ProtectedBranch implements Node { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): ReviewDismissalAllowanceConnection! @@ -4488,7 +4523,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4496,7 +4531,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserConnection! @@ -4544,7 +4579,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4552,7 +4587,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): IssueCommentConnection! @@ -4565,7 +4600,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4573,7 +4608,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): PullRequestCommitConnection! @@ -4615,6 +4650,11 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & headRepositoryOwner: RepositoryOwner id: ID! + """ + Check if this comment was edited and includes an edit with the creation data + """ + includesCreatedEdit: Boolean! + """The head and base repositories are different.""" isCrossRepository: Boolean! @@ -4624,7 +4664,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4632,7 +4672,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): LabelConnection @@ -4677,7 +4717,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4685,11 +4725,14 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserConnection! + """The permalink to the pull request.""" + permalink: URI! + """ The commit that GitHub automatically generated to test if this pull request could be merged. This field will not return a value if the pull request is @@ -4704,7 +4747,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4712,7 +4755,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): ProjectCardConnection! @@ -4729,7 +4772,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4737,7 +4780,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -4766,7 +4809,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4774,7 +4817,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): ReviewRequestConnection @@ -4785,7 +4828,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4793,7 +4836,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -4820,7 +4863,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4828,7 +4871,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -4851,7 +4894,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4859,7 +4902,7 @@ type PullRequest implements Node & Assignable & Closable & Comment & Updatable & last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserContentEditConnection @@ -4989,7 +5032,7 @@ type PullRequestReview implements Node & Comment & Deletable & Updatable & Updat first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -4997,7 +5040,7 @@ type PullRequestReview implements Node & Comment & Deletable & Updatable & Updat last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): PullRequestReviewCommentConnection! @@ -5018,6 +5061,11 @@ type PullRequestReview implements Node & Comment & Deletable & Updatable & Updat editor: Actor id: ID! + """ + Check if this comment was edited and includes an edit with the creation data + """ + includesCreatedEdit: Boolean! + """The moment the editor made the last edit""" lastEditedAt: DateTime @@ -5051,7 +5099,7 @@ type PullRequestReview implements Node & Comment & Deletable & Updatable & Updat first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -5059,7 +5107,7 @@ type PullRequestReview implements Node & Comment & Deletable & Updatable & Updat last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserContentEditConnection @@ -5116,6 +5164,11 @@ type PullRequestReviewComment implements Node & Comment & Deletable & Updatable editor: Actor id: ID! + """ + Check if this comment was edited and includes an edit with the creation data + """ + includesCreatedEdit: Boolean! + """The moment the editor made the last edit""" lastEditedAt: DateTime @@ -5149,7 +5202,7 @@ type PullRequestReviewComment implements Node & Comment & Deletable & Updatable first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -5157,7 +5210,7 @@ type PullRequestReviewComment implements Node & Comment & Deletable & Updatable last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -5189,7 +5242,7 @@ type PullRequestReviewComment implements Node & Comment & Deletable & Updatable first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -5197,7 +5250,7 @@ type PullRequestReviewComment implements Node & Comment & Deletable & Updatable last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserContentEditConnection @@ -5307,7 +5360,7 @@ type PullRequestReviewThread implements Node { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -5315,7 +5368,7 @@ type PullRequestReviewThread implements Node { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): PullRequestReviewCommentConnection! @@ -5430,12 +5483,18 @@ type Query { marketplaceCategories( """Exclude categories with no listings.""" excludeEmpty: Boolean + + """Exclude subcategories""" + excludeSubcategories: Boolean ): [MarketplaceCategory!]! """Look up a Marketplace category by its slug.""" marketplaceCategory( """The URL slug of the category.""" slug: String! + + """Also check topic aliases for the category slug""" + useTopicAliases: Boolean ): MarketplaceCategory """Look up a single Marketplace listing""" @@ -5452,7 +5511,7 @@ type Query { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -5460,13 +5519,16 @@ type Query { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String """Select only listings with the given category.""" categorySlug: String + """Also check topic aliases for the category slug""" + useTopicAliases: Boolean + """ Select listings to which user has admin access. If omitted, listings visible to the viewer are returned. @@ -5562,7 +5624,7 @@ type Query { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -5570,7 +5632,7 @@ type Query { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -5634,7 +5696,7 @@ interface Reactable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -5642,7 +5704,7 @@ interface Reactable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -5770,7 +5832,7 @@ type ReactionGroup { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -5778,7 +5840,7 @@ type ReactionGroup { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): ReactingUserConnection! @@ -5812,7 +5874,7 @@ type Ref implements Node { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -5820,7 +5882,7 @@ type Ref implements Node { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -5959,7 +6021,7 @@ type Release implements Node & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -5967,7 +6029,7 @@ type Release implements Node & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6211,7 +6273,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6219,7 +6281,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserConnection! @@ -6233,7 +6295,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6241,7 +6303,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6255,7 +6317,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6263,7 +6325,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): CommitCommentConnection! @@ -6283,7 +6345,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6291,7 +6353,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): DeployKeyConnection! @@ -6302,7 +6364,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6310,7 +6372,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6338,7 +6400,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6346,7 +6408,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6410,7 +6472,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6418,7 +6480,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6444,7 +6506,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6452,7 +6514,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6468,7 +6530,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6476,7 +6538,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6501,7 +6563,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6509,7 +6571,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserConnection! @@ -6529,7 +6591,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6537,7 +6599,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6587,7 +6649,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6595,7 +6657,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6621,7 +6683,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6629,7 +6691,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): ProtectedBranchConnection! @@ -6646,7 +6708,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6654,7 +6716,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6695,7 +6757,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6703,7 +6765,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6729,7 +6791,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6737,7 +6799,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6751,7 +6813,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6759,7 +6821,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): RepositoryTopicConnection! @@ -6787,7 +6849,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6795,7 +6857,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -6848,7 +6910,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -6856,7 +6918,7 @@ type Repository implements Node & ProjectOwner & Subscribable & Starrable & Unif last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): UserConnection! @@ -7130,7 +7192,7 @@ interface RepositoryOwner { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -7138,7 +7200,7 @@ interface RepositoryOwner { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -7163,7 +7225,7 @@ interface RepositoryOwner { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -7171,7 +7233,7 @@ interface RepositoryOwner { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -7593,7 +7655,7 @@ interface Starrable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -7601,7 +7663,7 @@ interface Starrable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -7819,7 +7881,7 @@ type Team implements Node & Subscribable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -7827,7 +7889,7 @@ type Team implements Node & Subscribable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): TeamConnection! @@ -7844,7 +7906,7 @@ type Team implements Node & Subscribable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -7852,7 +7914,7 @@ type Team implements Node & Subscribable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -7888,7 +7950,7 @@ type Team implements Node & Subscribable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -7896,7 +7958,7 @@ type Team implements Node & Subscribable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): OrganizationInvitationConnection @@ -7907,7 +7969,7 @@ type Team implements Node & Subscribable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -7915,7 +7977,7 @@ type Team implements Node & Subscribable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -7962,7 +8024,7 @@ type Team implements Node & Subscribable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -7970,7 +8032,7 @@ type Team implements Node & Subscribable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -8211,7 +8273,7 @@ type TextMatch { fragment: String! """Highlights within the matched fragment.""" - highlights: [TextMatchHighlight]! + highlights: [TextMatchHighlight!]! """The property matched on.""" property: String! @@ -8411,6 +8473,24 @@ type UnlockedEvent implements Node { lockable: Lockable! } +"""Autogenerated input type of UnlockLockable""" +input UnlockLockableInput { + """ID of the issue or pull request to be unlocked.""" + lockableId: ID! + + """A unique identifier for the client performing the mutation.""" + clientMutationId: String +} + +"""Autogenerated return type of UnlockLockable""" +type UnlockLockablePayload { + """A unique identifier for the client performing the mutation.""" + clientMutationId: String + + """The item that was unlocked.""" + unlockedRecord: Lockable +} + """Represents an 'unsubscribed' event on a given `Subscribable`.""" type UnsubscribedEvent implements Node { """Identifies the actor who performed the event.""" @@ -8442,7 +8522,7 @@ input UpdateProjectCardInput { projectCardId: ID! """The note of ProjectCard.""" - note: String! + note: String """A unique identifier for the client performing the mutation.""" clientMutationId: String @@ -8620,7 +8700,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8628,7 +8708,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): CommitCommentConnection! @@ -8645,7 +8725,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8653,7 +8733,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -8687,7 +8767,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8695,7 +8775,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): FollowerConnection! @@ -8706,7 +8786,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8714,7 +8794,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): FollowingConnection! @@ -8731,7 +8811,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8739,7 +8819,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): GistCommentConnection! @@ -8750,7 +8830,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8758,7 +8838,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -8801,7 +8881,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8809,7 +8889,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): IssueCommentConnection! @@ -8820,7 +8900,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8828,7 +8908,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -8863,7 +8943,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8871,7 +8951,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): OrganizationConnection! @@ -8882,7 +8962,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8890,7 +8970,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -8915,7 +8995,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8923,7 +9003,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String ): PublicKeyConnection! @@ -8934,7 +9014,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8942,7 +9022,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -8968,7 +9048,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -8976,7 +9056,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -9006,7 +9086,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -9014,7 +9094,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -9054,7 +9134,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -9062,7 +9142,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -9093,7 +9173,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { first: Int """ - Returns the elements in the list that come after the specified global ID. + Returns the elements in the list that come after the specified cursor. """ after: String @@ -9101,7 +9181,7 @@ type User implements Node & Actor & RepositoryOwner & UniformResourceLocatable { last: Int """ - Returns the elements in the list that come before the specified global ID. + Returns the elements in the list that come before the specified cursor. """ before: String @@ -9153,6 +9233,9 @@ type UserContentEdit implements Node { """A summary of the changes for this edit""" diff: String + """When this content was edited""" + editedAt: DateTime! + """The actor who edited this content""" editor: Actor id: ID! From 45f5d9f4b9e813e6e094f2c41542e0eec7b6589b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 11:51:13 -0400 Subject: [PATCH 0395/4847] Backfill tests for the IssueishDetailContainer --- lib/containers/issueish-detail-container.js | 137 ++++++++---------- .../issueish-detail-container.test.js | 119 +++++++++++++++ .../fixtures/factories/pull-request-result.js | 64 ++++++++ test/fixtures/props/issueish-pane-props.js | 16 ++ 4 files changed, 263 insertions(+), 73 deletions(-) create mode 100644 test/containers/issueish-detail-container.test.js diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index c8d67beaaa..c6f72d8cfb 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -5,8 +5,10 @@ import {QueryRenderer, graphql} from 'react-relay'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; import {GithubLoginModelPropType} from '../prop-types'; -import {UNAUTHENTICATED} from '../shared/keytar-strategy'; +import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; import GithubLoginView from '../views/github-login-view'; +import LoadingView from '../views/loading-view'; +import QueryErrorView from '../views/query-error-view'; import ObserveModel from '../views/observe-model'; import IssueishLookupByNumberContainer from '../containers/issueish-lookup-by-number-container'; import RelayEnvironment from '../views/relay-environment'; @@ -25,13 +27,9 @@ export default class IssueishDetailContainer extends React.Component { onTitleChange: PropTypes.func.isRequired, } - static defaultProps = { - host: 'api.github.com', - } - constructor(props) { super(props); - autobind(this, 'fetchData', 'renderWithToken', 'handleLogin', 'handleLogout'); + autobind(this, 'fetchData', 'renderWithToken', 'renderWithResult', 'handleLogin', 'handleLogout'); } fetchData(loginModel) { @@ -49,89 +47,82 @@ export default class IssueishDetailContainer extends React.Component { } renderWithToken(data) { - if (!data) { return null; } + if (!data) { + return ; + } + if (data.token === UNAUTHENTICATED) { return ; } + if (data.token === INSUFFICIENT) { + return ( + +

    + Your token no longer has sufficient authorizations. Please re-authenticate and generate a new one. +

    +
    + ); + } + const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, data.token); + const query = graphql` + query issueishDetailContainerQuery + ( + $repoOwner: String! + $repoName: String! + $issueishNumber: Int! + $timelineCount: Int! + $timelineCursor: String + ) { + repository(owner: $repoOwner, name: $repoName) { + ...issueishLookupByNumberContainer_repository + } + } + `; + const variables = { + repoOwner: this.props.owner, + repoName: this.props.repo, + issueishNumber: this.props.issueishNumber, + timelineCount: 100, + timelineCursor: null, + }; return ( { - if (error) { - if (error.response && error.response.status === 401) { - return ( -
    - -

    - The API endpoint returned a unauthorized error. Please try to re-authenticate with the endpoint. -

    -
    -
    - ); - } else { - return this.renderUnknownError(retry); - } - } else if (props) { - return ( - - ); - } else { - return ( -
    - -
    - ); - } - }} + query={query} + variables={variables} + render={this.renderWithResult} />
    ); } - renderUnknownError(retry) { + renderWithResult({error, props, retry}) { + if (error) { + return ( + + ); + } + + if (!props) { + return ; + } + return ( -
    -
    -

    Error

    -

    - An unknown error occurred -

    -
    - - -
    -
    -
    + ); } diff --git a/test/containers/issueish-detail-container.test.js b/test/containers/issueish-detail-container.test.js new file mode 100644 index 0000000000..7c55e95aa8 --- /dev/null +++ b/test/containers/issueish-detail-container.test.js @@ -0,0 +1,119 @@ +import React from 'react'; +import {mount} from 'enzyme'; + +import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; +import {issueishDetailContainerProps} from '../fixtures/props/issueish-pane-props'; +import {createPullRequestDetailResult} from '../fixtures/factories/pull-request-result'; +import GithubLoginModel from '../../lib/models/github-login-model'; +import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; +import IssueishDetailContainer from '../../lib/containers/issueish-detail-container'; + +describe('IssueishDetailContainer', function() { + let loginModel; + + beforeEach(function() { + loginModel = new GithubLoginModel(InMemoryStrategy); + }); + + function useResult() { + return expectRelayQuery({ + name: 'issueishDetailContainerQuery', + variables: { + repoOwner: 'owner', + repoName: 'repo', + issueishNumber: 1, + timelineCount: 100, + timelineCursor: null, + }, + }, { + repository: { + id: 'repository0', + name: 'repo', + owner: { + __typename: 'User', + login: 'owner', + id: 'user0', + }, + issueish: createPullRequestDetailResult(), + }, + }); + } + + function buildApp(overrideProps = {}) { + return ; + } + + it('renders a spinner while the token is being fetched', function() { + const wrapper = mount(buildApp()); + assert.isTrue(wrapper.find('LoadingView').exists()); + }); + + it('renders a login prompt if the user is unauthenticated', async function() { + const wrapper = mount(buildApp()); + await assert.async.isTrue(wrapper.update().find('GithubLoginView').exists()); + }); + + it("renders a login prompt if the user's token has insufficient scopes", async function() { + loginModel.setToken('https://api.github.com', '1234'); + sinon.stub(loginModel, 'getScopes').resolves(['not-enough']); + + const wrapper = mount(buildApp()); + await assert.async.isTrue(wrapper.update().find('GithubLoginView').exists()); + }); + + it('re-renders on login', async function() { + useResult(); + sinon.stub(loginModel, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); + + const wrapper = mount(buildApp()); + + await assert.async.isTrue(wrapper.update().find('GithubLoginView').exists()); + wrapper.find('GithubLoginView').prop('onLogin')('4321'); + + await assert.async.isTrue(wrapper.update().find('ReactRelayQueryRenderer').exists()); + }); + + it('renders a spinner while the GraphQL query is being performed', async function() { + useResult(); + + loginModel.setToken('https://api.github.com', '1234'); + sinon.spy(loginModel, 'getToken'); + sinon.stub(loginModel, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); + + const wrapper = mount(buildApp()); + await loginModel.getToken.returnValues[0]; + + assert.isTrue(wrapper.update().find('LoadingView').exists()); + }); + + it('renders an error view if the GraphQL query fails', async function() { + const {reject, promise} = useResult(); + + loginModel.setToken('https://api.github.com', '1234'); + sinon.stub(loginModel, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); + + const wrapper = mount(buildApp()); + const e = new Error('wat'); + e.rawStack = e.stack; + reject(e); + await promise.catch(() => {}); + + await assert.async.isTrue(wrapper.update().find('QueryErrorView').exists()); + assert.strictEqual(wrapper.find('QueryErrorView').prop('error'), e); + }); + + it('passes GraphQL query results to an IssueishDetailController', async function() { + const {resolve} = useResult(); + loginModel.setToken('https://api.github.com', '1234'); + sinon.stub(loginModel, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); + + const wrapper = mount(buildApp()); + resolve(); + + await assert.async.isTrue(wrapper.update().find('IssueishLookupByNumber').exists()); + + const controller = wrapper.find('IssueishLookupByNumber'); + assert.isDefined(controller.prop('repository')); + assert.strictEqual(controller.prop('issueishNumber'), 1); + }); +}); diff --git a/test/fixtures/factories/pull-request-result.js b/test/fixtures/factories/pull-request-result.js index aa18846853..d2c628ee31 100644 --- a/test/fixtures/factories/pull-request-result.js +++ b/test/fixtures/factories/pull-request-result.js @@ -49,5 +49,69 @@ export function createPullRequestResult(attrs = {}) { }, commits: {nodes: [{commit, id: 'node0'}]}, + } } + +export function createPullRequestDetailResult(attrs = {}) { + const o = { + number: 0, + title: 'title', + state: 'OPEN', + authorLogin: 'me', + authorAvatarURL: 'https://avatars3.githubusercontent.com/u/000?v=4', + headRefName: 'headref', + headRepositoryLogin: 'headlogin', + baseRepositoryLogin: 'baseLogin', + ...attrs, + }; + + const commit = { + id: 'commit0', + status: null, + }; + + return { + __typename: 'PullRequest', + id: `pullrequest${o.number}`, + title: o.title, + number: o.number, + state: o.state, + bodyHTML: '

    body

    ', + author: { + __typename: 'User', + id: `user${o.authorLogin}`, + login: o.authorLogin, + avatarUrl: o.authorAvatarURL, + url: `https://github.com/${o.authorLogin}`, + }, + url: `https://github.com/owner/repo/pull/${o.number}`, + reactionGroups: [], + commits: { + edges: [{ + node: {commit, id: 'node0'} + }], + }, + timeline: { + pageInfo: { + endCursor: 'end', + hasNextPage: false, + }, + edges: [], + }, + headRefName: o.headRefName, + headRepositoryOwner: { + __typename: 'User', + id: `user${o.headRepositoryLogin}`, + login: o.headRepositoryLogin, + }, + repository: { + owner: { + __typename: 'User', + id: `user${o.baseRepositoryLogin}`, + login: o.baseRepositoryLogin, + }, + id: 'baserepository', + } + }; +} diff --git a/test/fixtures/props/issueish-pane-props.js b/test/fixtures/props/issueish-pane-props.js index ab151259da..50cc72eb79 100644 --- a/test/fixtures/props/issueish-pane-props.js +++ b/test/fixtures/props/issueish-pane-props.js @@ -7,3 +7,19 @@ export function issueishPaneItemProps(overrides = {}) { ...overrides, }; } + +export function issueishDetailContainerProps(overrides = {}) { + return { + host: 'https://api.github.com', + owner: 'owner', + repo: 'repo', + issueishNumber: 1, + + loginModel: new GithubLoginModel(InMemoryStrategy), + + switchToIssueish: () => {}, + onTitleChange: () => {}, + + ...overrides, + }; +} From 0e0e7dff7c593f3f122dac4b3090eb0d610f8400 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 12:50:08 -0400 Subject: [PATCH 0396/4847] Use fragment arguments --- .../issueTimelineContainerQuery.graphql.js | 25 ++- .../issueTimelineContainer_issue.graphql.js | 12 +- .../issueishDetailContainerQuery.graphql.js | 211 +++++++++--------- ...shPaneItemContainerRefetchQuery.graphql.js | 33 ++- ...ueishPaneItemContainer_issueish.graphql.js | 37 ++- .../prTimelineContainerQuery.graphql.js | 38 +--- ...prTimelineContainer_pullRequest.graphql.js | 12 +- lib/containers/issue-timeline-container.js | 12 +- ...ishDetailController_repository.graphql.js} | 42 +++- 9 files changed, 236 insertions(+), 186 deletions(-) rename lib/{containers/__generated__/issueishLookupByNumberContainer_repository.graphql.js => controllers/__generated__/issueishDetailController_repository.graphql.js} (74%) diff --git a/lib/containers/__generated__/issueTimelineContainerQuery.graphql.js b/lib/containers/__generated__/issueTimelineContainerQuery.graphql.js index 3f5ccea8bb..398b331bdc 100644 --- a/lib/containers/__generated__/issueTimelineContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueTimelineContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash bb01afee3f1093e37d08cb06287dada6 + * @relayHash 85104935d05bb29ddc26ffbdb96ba4c7 */ /* eslint-disable */ @@ -32,7 +32,7 @@ query issueTimelineContainerQuery( resource(url: $url) { __typename ... on Issue { - ...issueTimelineContainer_issue + ...issueTimelineContainer_issue_3D8CP9 } ... on Node { id @@ -40,7 +40,7 @@ query issueTimelineContainerQuery( } } -fragment issueTimelineContainer_issue on Issue { +fragment issueTimelineContainer_issue_3D8CP9 on Issue { url timeline(first: $timelineCount, after: $timelineCursor) { pageInfo { @@ -281,7 +281,7 @@ return { "operationKind": "query", "name": "issueTimelineContainerQuery", "id": null, - "text": "query issueTimelineContainerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on Issue {\n ...issueTimelineContainer_issue\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueTimelineContainer_issue on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", + "text": "query issueTimelineContainerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on Issue {\n ...issueTimelineContainer_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueTimelineContainer_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -306,7 +306,20 @@ return { { "kind": "FragmentSpread", "name": "issueTimelineContainer_issue", - "args": null + "args": [ + { + "kind": "Variable", + "name": "timelineCount", + "variableName": "timelineCount", + "type": null + }, + { + "kind": "Variable", + "name": "timelineCursor", + "variableName": "timelineCursor", + "type": null + } + ] } ] } @@ -657,5 +670,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '5938b186499d2fe2c98067270f1fd03a'; +(node/*: any*/).hash = 'b1f3d85143779075e165dde0e8811da7'; module.exports = node; diff --git a/lib/containers/__generated__/issueTimelineContainer_issue.graphql.js b/lib/containers/__generated__/issueTimelineContainer_issue.graphql.js index b651404a16..55c9f57cee 100644 --- a/lib/containers/__generated__/issueTimelineContainer_issue.graphql.js +++ b/lib/containers/__generated__/issueTimelineContainer_issue.graphql.js @@ -51,14 +51,16 @@ const node/*: ConcreteFragment*/ = { }, "argumentDefinitions": [ { - "kind": "RootArgument", + "kind": "LocalArgument", "name": "timelineCount", - "type": "Int" + "type": "Int", + "defaultValue": null }, { - "kind": "RootArgument", + "kind": "LocalArgument", "name": "timelineCursor", - "type": "String" + "type": "String", + "defaultValue": null } ], "selections": [ @@ -159,5 +161,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = 'e476783c51f88e5e67a495eb8f4d188f'; +(node/*: any*/).hash = 'a5a1bce672bac668e82bcc9ab97ebc7e'; module.exports = node; diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index b4e8c3f15b..831b12007b 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash dda68fe91f45e497e6bd30d50b212830 + * @relayHash f746476b58e3b2c026b2609f9fd34880 */ /* eslint-disable */ @@ -9,7 +9,7 @@ /*:: import type { ConcreteRequest } from 'relay-runtime'; -type issueishLookupByNumberContainer_repository$ref = any; +type issueishDetailController_repository$ref = any; export type issueishDetailContainerQueryVariables = {| repoOwner: string, repoName: string, @@ -19,7 +19,7 @@ export type issueishDetailContainerQueryVariables = {| |}; export type issueishDetailContainerQueryResponse = {| +repository: ?{| - +$fragmentRefs: issueishLookupByNumberContainer_repository$ref + +$fragmentRefs: issueishDetailController_repository$ref |} |}; */ @@ -30,16 +30,14 @@ query issueishDetailContainerQuery( $repoOwner: String! $repoName: String! $issueishNumber: Int! - $timelineCount: Int! - $timelineCursor: String ) { repository(owner: $repoOwner, name: $repoName) { - ...issueishLookupByNumberContainer_repository + ...issueishDetailController_repository_146t2V id } } -fragment issueishLookupByNumberContainer_repository on Repository { +fragment issueishDetailController_repository_146t2V on Repository { ...issueishPaneItemContainer_repository name owner { @@ -52,12 +50,12 @@ fragment issueishLookupByNumberContainer_repository on Repository { ... on Issue { title number - ...issueishPaneItemContainer_issueish + ...issueishPaneItemContainer_issueish_1wZIw } ... on PullRequest { title number - ...issueishPaneItemContainer_issueish + ...issueishPaneItemContainer_issueish_1wZIw } ... on Node { id @@ -75,7 +73,7 @@ fragment issueishPaneItemContainer_repository on Repository { } } -fragment issueishPaneItemContainer_issueish on IssueOrPullRequest { +fragment issueishPaneItemContainer_issueish_1wZIw on IssueOrPullRequest { __typename ... on Node { id @@ -99,7 +97,7 @@ fragment issueishPaneItemContainer_issueish on IssueOrPullRequest { id } } - ...issueTimelineContainer_issue + ...issueTimelineContainer_issue_1wZIw } ... on PullRequest { ...prStatusesContainer_pullRequest @@ -121,7 +119,7 @@ fragment issueishPaneItemContainer_issueish on IssueOrPullRequest { id } } - ...prTimelineContainer_pullRequest + ...prTimelineContainer_pullRequest_1wZIw } ... on UniformResourceLocatable { url @@ -136,9 +134,9 @@ fragment issueishPaneItemContainer_issueish on IssueOrPullRequest { } } -fragment issueTimelineContainer_issue on Issue { +fragment issueTimelineContainer_issue_1wZIw on Issue { url - timeline(first: $timelineCount, after: $timelineCursor) { + timeline { pageInfo { endCursor hasNextPage @@ -181,10 +179,10 @@ fragment prStatusesContainer_pullRequest on PullRequest { } } -fragment prTimelineContainer_pullRequest on PullRequest { +fragment prTimelineContainer_pullRequest_1wZIw on PullRequest { url ...headRefForcePushedEventContainer_issueish - timeline(first: $timelineCount, after: $timelineCursor) { + timeline { pageInfo { endCursor hasNextPage @@ -522,21 +520,7 @@ v9 = { "args": null, "storageKey": null }, -v10 = [ - { - "kind": "Variable", - "name": "after", - "variableName": "timelineCursor", - "type": "String" - }, - { - "kind": "Variable", - "name": "first", - "variableName": "timelineCount", - "type": "Int" - } -], -v11 = { +v10 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -561,41 +545,41 @@ v11 = { } ] }, -v12 = { +v11 = { "kind": "ScalarField", "alias": null, "name": "cursor", "args": null, "storageKey": null }, -v13 = { +v12 = { "kind": "ScalarField", "alias": null, "name": "avatarUrl", "args": null, "storageKey": null }, -v14 = [ +v13 = [ v4, v5, - v13, + v12, v2 ], -v15 = { +v14 = { "kind": "ScalarField", "alias": null, "name": "number", "args": null, "storageKey": null }, -v16 = { +v15 = { "kind": "ScalarField", "alias": null, "name": "url", "args": null, "storageKey": null }, -v17 = { +v16 = { "kind": "InlineFragment", "type": "CrossReferencedEvent", "selections": [ @@ -621,7 +605,7 @@ v17 = { "args": null, "concreteType": null, "plural": false, - "selections": v14 + "selections": v13 }, { "kind": "LinkedField", @@ -659,9 +643,9 @@ v17 = { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v15, + v14, v9, - v16, + v15, { "kind": "ScalarField", "alias": "prState", @@ -675,9 +659,9 @@ v17 = { "kind": "InlineFragment", "type": "Issue", "selections": [ - v15, + v14, v9, - v16, + v15, { "kind": "ScalarField", "alias": "issueState", @@ -691,18 +675,18 @@ v17 = { } ] }, -v18 = { +v17 = { "kind": "ScalarField", "alias": null, "name": "oid", "args": null, "storageKey": null }, -v19 = [ - v18, +v18 = [ + v17, v2 ], -v20 = { +v19 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -710,22 +694,22 @@ v20 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v19 + "selections": v18 }, -v21 = { +v20 = { "kind": "ScalarField", "alias": null, "name": "createdAt", "args": null, "storageKey": null }, -v22 = [ +v21 = [ v4, - v13, + v12, v5, v2 ], -v23 = { +v22 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -733,9 +717,9 @@ v23 = { "args": null, "concreteType": null, "plural": false, - "selections": v22 + "selections": v21 }, -v24 = { +v23 = { "kind": "InlineFragment", "type": "IssueComment", "selections": [ @@ -747,13 +731,13 @@ v24 = { "args": null, "concreteType": null, "plural": false, - "selections": v22 + "selections": v21 }, v8, - v21 + v20 ] }, -v25 = { +v24 = { "kind": "LinkedField", "alias": null, "name": "user", @@ -766,7 +750,7 @@ v25 = { v2 ] }, -v26 = { +v25 = { "kind": "InlineFragment", "type": "Commit", "selections": [ @@ -780,8 +764,8 @@ v26 = { "plural": false, "selections": [ v3, - v25, - v13 + v24, + v12 ] }, { @@ -794,8 +778,8 @@ v26 = { "plural": false, "selections": [ v3, - v13, - v25 + v12, + v24 ] }, { @@ -805,7 +789,7 @@ v26 = { "args": null, "storageKey": null }, - v18, + v17, { "kind": "ScalarField", "alias": null, @@ -822,17 +806,17 @@ v26 = { } ] }, -v27 = { +v26 = { "kind": "ScalarField", "alias": null, "name": "state", "args": null, "storageKey": null }, -v28 = [ - v16 +v27 = [ + v15 ], -v29 = { +v28 = { "kind": "LinkedField", "alias": null, "name": "author", @@ -843,21 +827,21 @@ v29 = { "selections": [ v4, v5, - v13, + v12, v2, { "kind": "InlineFragment", "type": "Bot", - "selections": v28 + "selections": v27 }, { "kind": "InlineFragment", "type": "User", - "selections": v28 + "selections": v27 } ] }, -v30 = { +v29 = { "kind": "LinkedField", "alias": null, "name": "reactionGroups", @@ -898,7 +882,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishLookupByNumberContainer_repository\n id\n }\n}\n\nfragment issueishLookupByNumberContainer_repository on Repository {\n ...issueishPaneItemContainer_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishPaneItemContainer_issueish\n }\n ... on PullRequest {\n title\n number\n ...issueishPaneItemContainer_issueish\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishPaneItemContainer_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishPaneItemContainer_issueish on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_146t2V\n id\n }\n}\n\nfragment issueishDetailController_repository_146t2V on Repository {\n ...issueishPaneItemContainer_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishPaneItemContainer_issueish_1wZIw\n }\n ... on PullRequest {\n title\n number\n ...issueishPaneItemContainer_issueish_1wZIw\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishPaneItemContainer_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishPaneItemContainer_issueish_1wZIw on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue_1wZIw\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest_1wZIw\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue_1wZIw on Issue {\n url\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest_1wZIw on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -918,8 +902,15 @@ return { "selections": [ { "kind": "FragmentSpread", - "name": "issueishLookupByNumberContainer_repository", - "args": null + "name": "issueishDetailController_repository", + "args": [ + { + "kind": "Variable", + "name": "issueishNumber", + "variableName": "issueishNumber", + "type": null + } + ] } ] } @@ -971,11 +962,11 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": v10, + "args": null, "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v11, + v10, { "kind": "LinkedField", "alias": null, @@ -985,7 +976,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v12, + v11, { "kind": "LinkedField", "alias": null, @@ -997,12 +988,12 @@ return { "selections": [ v4, v2, - v17, + v16, { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v20, + v19, { "kind": "LinkedField", "alias": null, @@ -1046,11 +1037,11 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v14 + "selections": v13 }, - v20, + v19, v8, - v21, + v20, { "kind": "ScalarField", "alias": null, @@ -1077,7 +1068,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v23, + v22, { "kind": "LinkedField", "alias": null, @@ -1086,7 +1077,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v19 + "selections": v18 }, { "kind": "LinkedField", @@ -1096,17 +1087,17 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v19 + "selections": v18 }, - v21 + v20 ] }, { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v23, - v20, + v22, + v19, { "kind": "ScalarField", "alias": null, @@ -1114,11 +1105,11 @@ return { "args": null, "storageKey": null }, - v21 + v20 ] }, - v24, - v26 + v23, + v25 ] } ] @@ -1129,7 +1120,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v10, + "args": null, "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null @@ -1186,7 +1177,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v27, + v26, { "kind": "LinkedField", "alias": null, @@ -1197,7 +1188,7 @@ return { "plural": true, "selections": [ v2, - v27, + v26, { "kind": "ScalarField", "alias": null, @@ -1234,10 +1225,10 @@ return { } ] }, - v27, + v26, + v14, + v28, v15, - v29, - v16, { "kind": "ScalarField", "alias": null, @@ -1268,7 +1259,7 @@ return { v2 ] }, - v30 + v29 ] }, { @@ -1277,20 +1268,20 @@ return { "selections": [ v8, v9, - v27, + v26, + v14, + v28, v15, - v29, - v16, { "kind": "LinkedField", "alias": null, "name": "timeline", "storageKey": null, - "args": v10, + "args": null, "concreteType": "IssueTimelineConnection", "plural": false, "selections": [ - v11, + v10, { "kind": "LinkedField", "alias": null, @@ -1300,7 +1291,7 @@ return { "concreteType": "IssueTimelineItemEdge", "plural": true, "selections": [ - v12, + v11, { "kind": "LinkedField", "alias": null, @@ -1312,9 +1303,9 @@ return { "selections": [ v4, v2, - v17, - v24, - v26 + v16, + v23, + v25 ] } ] @@ -1325,12 +1316,12 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v10, + "args": null, "handle": "connection", "key": "IssueTimelineContainer_timeline", "filters": null }, - v30 + v29 ] } ] @@ -1342,5 +1333,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'a07360f886e4eb663defa81c3f6c8d65'; +(node/*: any*/).hash = 'd62715328b9954af775f83a45e8b6feb'; module.exports = node; diff --git a/lib/containers/__generated__/issueishPaneItemContainerRefetchQuery.graphql.js b/lib/containers/__generated__/issueishPaneItemContainerRefetchQuery.graphql.js index acdef7e89c..e42eca4f38 100644 --- a/lib/containers/__generated__/issueishPaneItemContainerRefetchQuery.graphql.js +++ b/lib/containers/__generated__/issueishPaneItemContainerRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 5c893f6b9fde1fa41058774e76c73dc3 + * @relayHash b45b269409a7865246e37c4dc1a47432 */ /* eslint-disable */ @@ -42,7 +42,7 @@ query issueishPaneItemContainerRefetchQuery( } issueish: node(id: $issueishId) { __typename - ...issueishPaneItemContainer_issueish + ...issueishPaneItemContainer_issueish_3D8CP9 id } } @@ -57,7 +57,7 @@ fragment issueishPaneItemContainer_repository on Repository { } } -fragment issueishPaneItemContainer_issueish on IssueOrPullRequest { +fragment issueishPaneItemContainer_issueish_3D8CP9 on IssueOrPullRequest { __typename ... on Node { id @@ -81,7 +81,7 @@ fragment issueishPaneItemContainer_issueish on IssueOrPullRequest { id } } - ...issueTimelineContainer_issue + ...issueTimelineContainer_issue_3D8CP9 } ... on PullRequest { ...prStatusesContainer_pullRequest @@ -103,7 +103,7 @@ fragment issueishPaneItemContainer_issueish on IssueOrPullRequest { id } } - ...prTimelineContainer_pullRequest + ...prTimelineContainer_pullRequest_3D8CP9 } ... on UniformResourceLocatable { url @@ -118,7 +118,7 @@ fragment issueishPaneItemContainer_issueish on IssueOrPullRequest { } } -fragment issueTimelineContainer_issue on Issue { +fragment issueTimelineContainer_issue_3D8CP9 on Issue { url timeline(first: $timelineCount, after: $timelineCursor) { pageInfo { @@ -163,7 +163,7 @@ fragment prStatusesContainer_pullRequest on PullRequest { } } -fragment prTimelineContainer_pullRequest on PullRequest { +fragment prTimelineContainer_pullRequest_3D8CP9 on PullRequest { url ...headRefForcePushedEventContainer_issueish timeline(first: $timelineCount, after: $timelineCursor) { @@ -840,7 +840,7 @@ return { "operationKind": "query", "name": "issueishPaneItemContainerRefetchQuery", "id": null, - "text": "query issueishPaneItemContainerRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishPaneItemContainer_repository\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishPaneItemContainer_issueish\n id\n }\n}\n\nfragment issueishPaneItemContainer_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishPaneItemContainer_issueish on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishPaneItemContainerRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishPaneItemContainer_repository\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishPaneItemContainer_issueish_3D8CP9\n id\n }\n}\n\nfragment issueishPaneItemContainer_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishPaneItemContainer_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -877,7 +877,20 @@ return { { "kind": "FragmentSpread", "name": "issueishPaneItemContainer_issueish", - "args": null + "args": [ + { + "kind": "Variable", + "name": "timelineCount", + "variableName": "timelineCount", + "type": null + }, + { + "kind": "Variable", + "name": "timelineCursor", + "variableName": "timelineCursor", + "type": null + } + ] } ] } @@ -1333,5 +1346,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '8765141f7ebed44770ebf7e6a76aea50'; +(node/*: any*/).hash = '51442b1c4d9a853580138f01efbc45fa'; module.exports = node; diff --git a/lib/containers/__generated__/issueishPaneItemContainer_issueish.graphql.js b/lib/containers/__generated__/issueishPaneItemContainer_issueish.graphql.js index 7837cc1748..4320f71a51 100644 --- a/lib/containers/__generated__/issueishPaneItemContainer_issueish.graphql.js +++ b/lib/containers/__generated__/issueishPaneItemContainer_issueish.graphql.js @@ -114,13 +114,40 @@ v6 = { "selections": v5 } ] -}; +}, +v7 = [ + { + "kind": "Variable", + "name": "timelineCount", + "variableName": "timelineCount", + "type": null + }, + { + "kind": "Variable", + "name": "timelineCursor", + "variableName": "timelineCursor", + "type": null + } +]; return { "kind": "Fragment", "name": "issueishPaneItemContainer_issueish", "type": "IssueOrPullRequest", "metadata": null, - "argumentDefinitions": [], + "argumentDefinitions": [ + { + "kind": "LocalArgument", + "name": "timelineCount", + "type": "Int", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "timelineCursor", + "type": "String", + "defaultValue": null + } + ], "selections": [ { "kind": "ScalarField", @@ -190,7 +217,7 @@ return { { "kind": "FragmentSpread", "name": "prTimelineContainer_pullRequest", - "args": null + "args": v7 } ] }, @@ -206,7 +233,7 @@ return { { "kind": "FragmentSpread", "name": "issueTimelineContainer_issue", - "args": null + "args": v7 } ] } @@ -214,5 +241,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'a4f903e357498f098d92c5fcca8a45cb'; +(node/*: any*/).hash = 'ddb3723645bb5fa5dbe55b81807a162f'; module.exports = node; diff --git a/lib/containers/__generated__/prTimelineContainerQuery.graphql.js b/lib/containers/__generated__/prTimelineContainerQuery.graphql.js index cf0ed01c29..2f1bd277f2 100644 --- a/lib/containers/__generated__/prTimelineContainerQuery.graphql.js +++ b/lib/containers/__generated__/prTimelineContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 29fcc87bf6e5821998433fa54078ce9c + * @relayHash a6c8a5736596f39e03e83fe3ad707fef */ /* eslint-disable */ @@ -25,8 +25,6 @@ export type prTimelineContainerQueryResponse = {| /* query prTimelineContainerQuery( - $timelineCount: Int! - $timelineCursor: String $url: URI! ) { resource(url: $url) { @@ -43,7 +41,7 @@ query prTimelineContainerQuery( fragment prTimelineContainer_pullRequest on PullRequest { url ...headRefForcePushedEventContainer_issueish - timeline(first: $timelineCount, after: $timelineCursor) { + timeline { pageInfo { endCursor hasNextPage @@ -445,7 +443,7 @@ return { "operationKind": "query", "name": "prTimelineContainerQuery", "id": null, - "text": "query prTimelineContainerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineContainer_pullRequest\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", + "text": "query prTimelineContainerQuery(\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineContainer_pullRequest\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -534,20 +532,7 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": [ - { - "kind": "Variable", - "name": "after", - "variableName": "timelineCursor", - "type": "String" - }, - { - "kind": "Variable", - "name": "first", - "variableName": "timelineCount", - "type": "Int" - } - ], + "args": null, "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ @@ -902,20 +887,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": [ - { - "kind": "Variable", - "name": "after", - "variableName": "timelineCursor", - "type": "String" - }, - { - "kind": "Variable", - "name": "first", - "variableName": "timelineCount", - "type": "Int" - } - ], + "args": null, "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null diff --git a/lib/containers/__generated__/prTimelineContainer_pullRequest.graphql.js b/lib/containers/__generated__/prTimelineContainer_pullRequest.graphql.js index eca2cf5309..2e0c84df1f 100644 --- a/lib/containers/__generated__/prTimelineContainer_pullRequest.graphql.js +++ b/lib/containers/__generated__/prTimelineContainer_pullRequest.graphql.js @@ -56,14 +56,16 @@ const node/*: ConcreteFragment*/ = { }, "argumentDefinitions": [ { - "kind": "RootArgument", + "kind": "LocalArgument", "name": "timelineCount", - "type": "Int" + "type": "Int", + "defaultValue": null }, { - "kind": "RootArgument", + "kind": "LocalArgument", "name": "timelineCursor", - "type": "String" + "type": "String", + "defaultValue": null } ], "selections": [ @@ -184,5 +186,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = '34655ef6a400d25e557bfc850f2d206e'; +(node/*: any*/).hash = 'ecf0555355586b59e8595a955dcaf5e4'; module.exports = node; diff --git a/lib/containers/issue-timeline-container.js b/lib/containers/issue-timeline-container.js index 7f90446d79..b5af6be22f 100644 --- a/lib/containers/issue-timeline-container.js +++ b/lib/containers/issue-timeline-container.js @@ -4,10 +4,14 @@ import IssueishTimelineView from '../views/issueish-timeline-view'; export default createPaginationContainer(IssueishTimelineView, { issue: graphql` - fragment issueTimelineContainer_issue on Issue { + fragment issueTimelineContainer_issue on Issue + @argumentDefinitions( + timelineCount: {type: "Int"}, + timelineCursor: {type: "String"} + ) { url timeline( - first: $timelineCount after: $timelineCursor + first: $timelineCount, after: $timelineCursor ) @connection(key: "IssueTimelineContainer_timeline") { pageInfo { endCursor hasNextPage } edges { @@ -41,10 +45,10 @@ export default createPaginationContainer(IssueishTimelineView, { }; }, query: graphql` - query issueTimelineContainerQuery($timelineCount: Int! $timelineCursor: String $url: URI!) { + query issueTimelineContainerQuery($timelineCount: Int!, $timelineCursor: String, $url: URI!) { resource(url: $url) { ... on Issue { - ...issueTimelineContainer_issue + ...issueTimelineContainer_issue @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) } } } diff --git a/lib/containers/__generated__/issueishLookupByNumberContainer_repository.graphql.js b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js similarity index 74% rename from lib/containers/__generated__/issueishLookupByNumberContainer_repository.graphql.js rename to lib/controllers/__generated__/issueishDetailController_repository.graphql.js index a7dc65302a..d826f4c26c 100644 --- a/lib/containers/__generated__/issueishLookupByNumberContainer_repository.graphql.js +++ b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js @@ -11,8 +11,8 @@ import type { ConcreteFragment } from 'relay-runtime'; type issueishPaneItemContainer_issueish$ref = any; type issueishPaneItemContainer_repository$ref = any; import type { FragmentReference } from "relay-runtime"; -declare export opaque type issueishLookupByNumberContainer_repository$ref: FragmentReference; -export type issueishLookupByNumberContainer_repository = {| +declare export opaque type issueishDetailController_repository$ref: FragmentReference; +export type issueishDetailController_repository = {| +name: string, +owner: {| +login: string @@ -28,7 +28,7 @@ export type issueishLookupByNumberContainer_repository = {| +__typename: "%other" |}), +$fragmentRefs: issueishPaneItemContainer_repository$ref, - +$refType: issueishLookupByNumberContainer_repository$ref, + +$refType: issueishDetailController_repository$ref, |}; */ @@ -52,19 +52,45 @@ var v0 = [ { "kind": "FragmentSpread", "name": "issueishPaneItemContainer_issueish", - "args": null + "args": [ + { + "kind": "Variable", + "name": "timelineCount", + "variableName": "timelineCount", + "type": null + }, + { + "kind": "Variable", + "name": "timelineCursor", + "variableName": "timelineCursor", + "type": null + } + ] } ]; return { "kind": "Fragment", - "name": "issueishLookupByNumberContainer_repository", + "name": "issueishDetailController_repository", "type": "Repository", "metadata": null, "argumentDefinitions": [ { - "kind": "RootArgument", + "kind": "LocalArgument", + "name": "timelineCount", + "type": "Int", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "timelineCursor", + "type": "String", + "defaultValue": null + }, + { + "kind": "LocalArgument", "name": "issueishNumber", - "type": "Int!" + "type": "Int!", + "defaultValue": null } ], "selections": [ @@ -137,5 +163,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'c71f81519589df9dbd61a32b1ce851ff'; +(node/*: any*/).hash = 'eaeab6bcc00588b29a2eaf7b6c107176'; module.exports = node; From 3bf31ea8219a16d0d14a09c37587b09bf8c19f6d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 12:54:26 -0400 Subject: [PATCH 0397/4847] Rename IssueishLookupByNumberContainer to IssueishDetailContainer --- lib/containers/issueish-detail-container.js | 6 +- .../issueish-lookup-by-number-container.js | 71 -------------- lib/controllers/issueish-detail-controller.js | 96 +++++++++++++++++++ .../issueish-detail-container.test.js | 4 +- 4 files changed, 101 insertions(+), 76 deletions(-) delete mode 100644 lib/containers/issueish-lookup-by-number-container.js create mode 100644 lib/controllers/issueish-detail-controller.js diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index c6f72d8cfb..2189fc3abb 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -10,7 +10,7 @@ import GithubLoginView from '../views/github-login-view'; import LoadingView from '../views/loading-view'; import QueryErrorView from '../views/query-error-view'; import ObserveModel from '../views/observe-model'; -import IssueishLookupByNumberContainer from '../containers/issueish-lookup-by-number-container'; +import IssueishDetailController from '../controllers/issueish-detail-controller'; import RelayEnvironment from '../views/relay-environment'; import {autobind} from '../helpers'; @@ -76,7 +76,7 @@ export default class IssueishDetailContainer extends React.Component { $timelineCursor: String ) { repository(owner: $repoOwner, name: $repoName) { - ...issueishLookupByNumberContainer_repository + ...issueishDetailController_repository @arguments(issueishNumber: $issueishNumber) } } `; @@ -117,7 +117,7 @@ export default class IssueishDetailContainer extends React.Component { } return ( - Issue/PR #{this.props.issueishNumber} not found
    ; // TODO: no PRs - } - return ( - - ); - } -} - -export default createFragmentContainer(IssueishLookupByNumber, { - repository: graphql` - fragment issueishLookupByNumberContainer_repository on Repository { - ...issueishPaneItemContainer_repository - name owner { login } - issueish:issueOrPullRequest(number: $issueishNumber) { - __typename - ... on Issue { - title number - ...issueishPaneItemContainer_issueish - } - ... on PullRequest { - title number - ...issueishPaneItemContainer_issueish - } - } - } - `, -}); diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js new file mode 100644 index 0000000000..a7c968e4ee --- /dev/null +++ b/lib/controllers/issueish-detail-controller.js @@ -0,0 +1,96 @@ +import React from 'react'; +import {graphql, createFragmentContainer} from 'react-relay'; +import PropTypes from 'prop-types'; + +import IssueishPaneItemContainer from '../containers/issueish-pane-item-container'; + +export class BareIssueishDetailController extends React.Component { + static propTypes = { + repository: PropTypes.shape({ + name: PropTypes.string.isRequired, + owner: PropTypes.shape({ + login: PropTypes.string.isRequired, + }).isRequired, + issueish: PropTypes.any, // FIXME from IssueishPaneItemContainer.propTypes + }), + issueishNumber: PropTypes.number.isRequired, + + onTitleChange: PropTypes.func.isRequired, + switchToIssueish: PropTypes.func.isRequired, + } + + componentDidMount() { + this.updateTitle(); + } + + componentDidUpdate() { + this.updateTitle(); + } + + updateTitle() { + const {repository} = this.props; + if (repository && repository.issueish) { + const issueish = repository.issueish; + + let title = issueish.__typename === 'Issue' ? 'Issue: ' : 'PR: '; + title += repository.owner.login; + title += '/'; + title += repository.owner.name; + title += '#'; + title += issueish.number; + title += ' — '; + title += issueish.title; + + this.props.onTitleChange(title); + } + } + + render() { + const {repository} = this.props; + if (!repository || !repository.issueish) { + return
    Issue/PR #{this.props.issueishNumber} not found
    ; // TODO: no PRs + } + + return ( + + ); + } +} + +export default createFragmentContainer(BareIssueishDetailController, { + repository: graphql` + fragment issueishDetailController_repository on Repository + @argumentDefinitions( + timelineCount: {type: "Int"}, + timelineCursor: {type: "String"}, + issueishNumber: {type: "Int!"} + ) { + ...issueishPaneItemContainer_repository + name + owner { + login + } + issueish: issueOrPullRequest(number: $issueishNumber) { + __typename + ... on Issue { + title number + ...issueishPaneItemContainer_issueish @arguments( + timelineCount: $timelineCount, + timelineCursor: $timelineCursor + ) + } + ... on PullRequest { + title number + ...issueishPaneItemContainer_issueish @arguments( + timelineCount: $timelineCount, + timelineCursor: $timelineCursor + ) + } + } + } + `, +}); diff --git a/test/containers/issueish-detail-container.test.js b/test/containers/issueish-detail-container.test.js index 7c55e95aa8..7a8d20ec16 100644 --- a/test/containers/issueish-detail-container.test.js +++ b/test/containers/issueish-detail-container.test.js @@ -110,9 +110,9 @@ describe('IssueishDetailContainer', function() { const wrapper = mount(buildApp()); resolve(); - await assert.async.isTrue(wrapper.update().find('IssueishLookupByNumber').exists()); + await assert.async.isTrue(wrapper.update().find('BareIssueishDetailController').exists()); - const controller = wrapper.find('IssueishLookupByNumber'); + const controller = wrapper.find('BareIssueishDetailController'); assert.isDefined(controller.prop('repository')); assert.strictEqual(controller.prop('issueishNumber'), 1); }); From 97c4feca90654d406806644decbb844943a8e634 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 14:25:17 -0400 Subject: [PATCH 0398/4847] Test the IssueishDetailController --- lib/controllers/issueish-detail-controller.js | 11 +-- .../issueish-detail-controller.test.js | 70 ++++++++++++++++ test/fixtures/props/issueish-pane-props.js | 81 +++++++++++++++++++ 3 files changed, 153 insertions(+), 9 deletions(-) create mode 100644 test/controllers/issueish-detail-controller.test.js diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index a7c968e4ee..edae627d5f 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -31,16 +31,9 @@ export class BareIssueishDetailController extends React.Component { const {repository} = this.props; if (repository && repository.issueish) { const issueish = repository.issueish; + const prefix = issueish.__typename === 'Issue' ? 'Issue:' : 'PR:'; - let title = issueish.__typename === 'Issue' ? 'Issue: ' : 'PR: '; - title += repository.owner.login; - title += '/'; - title += repository.owner.name; - title += '#'; - title += issueish.number; - title += ' — '; - title += issueish.title; - + const title = `${prefix} ${repository.owner.login}/${repository.name}#${issueish.number} — ${issueish.title}`; this.props.onTitleChange(title); } } diff --git a/test/controllers/issueish-detail-controller.test.js b/test/controllers/issueish-detail-controller.test.js new file mode 100644 index 0000000000..c12322c785 --- /dev/null +++ b/test/controllers/issueish-detail-controller.test.js @@ -0,0 +1,70 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BareIssueishDetailController} from '../../lib/controllers/issueish-detail-controller'; +import {issueishDetailControllerProps} from '../fixtures/props/issueish-pane-props'; + +describe('IssueishDetailController', function() { + function buildApp(opts, overrideProps = {}) { + return ; + } + + it('updates the pane title for a pull request on mount', function() { + const onTitleChange = sinon.stub(); + shallow(buildApp({ + repositoryName: 'reponame', + ownerLogin: 'ownername', + issueishNumber: 12, + issueishTitle: 'the title', + }, {onTitleChange})); + + assert.isTrue(onTitleChange.calledWith('PR: ownername/reponame#12 — the title')); + }); + + it('updates the pane title for an issue on mount', function() { + const onTitleChange = sinon.stub(); + shallow(buildApp({ + repositoryName: 'reponame', + ownerLogin: 'ownername', + issueishKind: 'Issue', + issueishNumber: 34, + issueishTitle: 'the title', + }, {onTitleChange})); + + assert.isTrue(onTitleChange.calledWith('Issue: ownername/reponame#34 — the title')); + }); + + it('updates the pane title on update', function() { + const onTitleChange = sinon.stub(); + const wrapper = shallow(buildApp({ + repositoryName: 'reponame', + ownerLogin: 'ownername', + issueishNumber: 12, + issueishTitle: 'the title', + }, {onTitleChange})); + assert.isTrue(onTitleChange.calledWith('PR: ownername/reponame#12 — the title')); + + wrapper.setProps(issueishDetailControllerProps({ + repositoryName: 'different', + ownerLogin: 'new', + issueishNumber: 34, + issueishTitle: 'the title', + }, {onTitleChange})); + + assert.isTrue(onTitleChange.calledWith('PR: new/different#34 — the title')); + }); + + it('leaves the title alone and renders a message if no repository was found', function() { + const onTitleChange = sinon.stub(); + const wrapper = shallow(buildApp({}, {onTitleChange, repository: null, issueishNumber: 123})); + assert.isFalse(onTitleChange.called); + assert.match(wrapper.find('div').text(), /#123 not found/); + }); + + it('leaves the title alone and renders a message if no issueish was found', function() { + const onTitleChange = sinon.stub(); + const wrapper = shallow(buildApp({omitIssueish: true}, {onTitleChange, issueishNumber: 123})); + assert.isFalse(onTitleChange.called); + assert.match(wrapper.find('div').text(), /#123 not found/); + }); +}); diff --git a/test/fixtures/props/issueish-pane-props.js b/test/fixtures/props/issueish-pane-props.js index 50cc72eb79..ec1aecec31 100644 --- a/test/fixtures/props/issueish-pane-props.js +++ b/test/fixtures/props/issueish-pane-props.js @@ -23,3 +23,84 @@ export function issueishDetailContainerProps(overrides = {}) { ...overrides, }; } + +export function issueishDetailControllerProps(opts, overrides = {}) { + const o = { + repositoryName: 'repository', + ownerLogin: 'owner', + + omitIssueish: false, + issueishNumber: 1, + issueishOverrides: {}, + + ...opts, + }; + + return { + repository: { + name: o.repositoryName, + owner: { + login: o.ownerLogin, + }, + issueish: o.omitIssueish ? null : issueishDetailViewProps(opts, o.issueishOverrides).issueish, + }, + issueishNumber: o.issueishNumber, + + onTitleChange: () => {}, + switchToIssueish: () => {}, + + ...overrides, + }; +} + +export function issueishDetailViewProps(opts, overrides = {}) { + const o = { + issueishKind: 'PullRequest', + + repositoryName: 'repository', + ownerLogin: 'owner', + + issueishTitle: 'title', + issueishBodyHTML: '

    body

    ', + issueishAuthorLogin: 'author', + issueishAuthorAvatarURL: 'https://avatars3.githubusercontent.com/u/000?v=4', + issueishNumber: 1, + issueishState: 'OPEN', + + relayRefetch: () => {}, + ...opts, + }; + + return { + relay: { + refetch: o.relayRefetch, + }, + + repository: { + id: 'repository0', + name: o.repositoryName, + owner: { + login: o.ownerLogin, + }, + }, + + issueish: { + id: 'pr0', + __typename: o.issueishKind, + title: o.issueishTitle, + bodyHTML: o.issueishBodyHTML, + number: o.issueishNumber, + state: o.issueishState, + author: { + login: o.issueishAuthorLogin, + avatarUrl: o.issueishAuthorAvatarURL, + url: `https://github.com/${o.issueishAuthorLogin}`, + }, + reactionGroups: [], + }, + + switchToIssueish: () => {}, + + ...overrides, + }; +} From 7797d9fd0b874951d3684df30dcee4843be9072f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 14:25:48 -0400 Subject: [PATCH 0399/4847] More fragment arguments --- lib/containers/issueish-pane-item-container.js | 18 +++++++++++++----- lib/containers/pr-timeline-container.js | 10 ++++++---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/containers/issueish-pane-item-container.js b/lib/containers/issueish-pane-item-container.js index 3165aafc90..374ff753a6 100644 --- a/lib/containers/issueish-pane-item-container.js +++ b/lib/containers/issueish-pane-item-container.js @@ -186,12 +186,20 @@ export class IssueishPaneItemView extends React.Component { export default createRefetchContainer(IssueishPaneItemView, { repository: graphql` fragment issueishPaneItemContainer_repository on Repository { - id name owner { login } + id + name + owner { + login + } } `, issueish: graphql` - fragment issueishPaneItemContainer_issueish on IssueOrPullRequest { + fragment issueishPaneItemContainer_issueish on IssueOrPullRequest + @argumentDefinitions( + timelineCount: {type: "Int"}, + timelineCursor: {type: "String"} + ) { __typename ... on Node { @@ -206,7 +214,7 @@ export default createRefetchContainer(IssueishPaneItemView, { ... on Bot { url } } - ...issueTimelineContainer_issue + ...issueTimelineContainer_issue @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) } ... on PullRequest { @@ -218,7 +226,7 @@ export default createRefetchContainer(IssueishPaneItemView, { ... on Bot { url } } - ...prTimelineContainer_pullRequest + ...prTimelineContainer_pullRequest @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) } ... on UniformResourceLocatable { url } @@ -240,7 +248,7 @@ export default createRefetchContainer(IssueishPaneItemView, { } issueish:node(id: $issueishId) { - ...issueishPaneItemContainer_issueish + ...issueishPaneItemContainer_issueish @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) } } `); diff --git a/lib/containers/pr-timeline-container.js b/lib/containers/pr-timeline-container.js index d2af2b2472..5451250d2d 100644 --- a/lib/containers/pr-timeline-container.js +++ b/lib/containers/pr-timeline-container.js @@ -4,12 +4,14 @@ import IssueishTimelineView from '../views/issueish-timeline-view'; export default createPaginationContainer(IssueishTimelineView, { pullRequest: graphql` - fragment prTimelineContainer_pullRequest on PullRequest { + fragment prTimelineContainer_pullRequest on PullRequest + @argumentDefinitions( + timelineCount: {type: "Int"}, + timelineCursor: {type: "String"} + ) { url ...headRefForcePushedEventContainer_issueish - timeline( - first: $timelineCount after: $timelineCursor - ) @connection(key: "prTimelineContainer_timeline") { + timeline(first: $timelineCount, after: $timelineCursor) @connection(key: "prTimelineContainer_timeline") { pageInfo { endCursor hasNextPage } edges { cursor From df5f34e7c8dd729a3d06d38606cb3c1194c15d9f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 14:38:52 -0400 Subject: [PATCH 0400/4847] Rename IssueishPaneItemContainer to IssueishDetailView --- lib/controllers/issueish-detail-controller.js | 10 ++++---- .../issueish-detail-view.js} | 23 ++++++++++--------- 2 files changed, 17 insertions(+), 16 deletions(-) rename lib/{containers/issueish-pane-item-container.js => views/issueish-detail-view.js} (90%) diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index edae627d5f..a393610b1c 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -2,7 +2,7 @@ import React from 'react'; import {graphql, createFragmentContainer} from 'react-relay'; import PropTypes from 'prop-types'; -import IssueishPaneItemContainer from '../containers/issueish-pane-item-container'; +import IssueishDetailView from '../views/issueish-detail-view'; export class BareIssueishDetailController extends React.Component { static propTypes = { @@ -45,7 +45,7 @@ export class BareIssueishDetailController extends React.Component { } return ( - 5 * 60 * 1000, getCurrentId: () => this.props.issueish.id, refresh: this.refresh, @@ -183,9 +184,9 @@ export class IssueishPaneItemView extends React.Component { } } -export default createRefetchContainer(IssueishPaneItemView, { +export default createRefetchContainer(BareIssueishDetailView, { repository: graphql` - fragment issueishPaneItemContainer_repository on Repository { + fragment issueishDetailView_repository on Repository { id name owner { @@ -195,7 +196,7 @@ export default createRefetchContainer(IssueishPaneItemView, { `, issueish: graphql` - fragment issueishPaneItemContainer_issueish on IssueOrPullRequest + fragment issueishDetailView_issueish on IssueOrPullRequest @argumentDefinitions( timelineCount: {type: "Int"}, timelineCursor: {type: "String"} @@ -239,16 +240,16 @@ export default createRefetchContainer(IssueishPaneItemView, { } `, }, graphql` - query issueishPaneItemContainerRefetchQuery + query issueishDetailViewRefetchQuery ( $repoId: ID!, $issueishId: ID!, $timelineCount: Int!, $timelineCursor: String ) { repository:node(id: $repoId) { - ...issueishPaneItemContainer_repository + ...issueishDetailView_repository } issueish:node(id: $issueishId) { - ...issueishPaneItemContainer_issueish @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) + ...issueishDetailView_issueish @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) } } `); From 149b1e482d5d632969213f40918084f915e94390 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 14:40:19 -0400 Subject: [PATCH 0401/4847] Rename CSS classes --- lib/views/issueish-detail-view.js | 32 +++++++++---------- ...em-view.less => issueish-detail-view.less} | 6 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) rename styles/{issueish-pane-item-view.less => issueish-detail-view.less} (90%) diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index 933fde8068..e04d3d5638 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -92,37 +92,37 @@ export class BareIssueishDetailView extends React.Component { pullRequest: issueish.__typename === 'PullRequest' ? issueish : null, }; return ( -
    -
    +
    +
    -
    -
    - + -
    +
    -
    - - + + -

    {issueish.title}

    +

    {issueish.title}

    @@ -131,10 +131,10 @@ export class BareIssueishDetailView extends React.Component { switchToIssueish={this.props.switchToIssueish} /> -
    +
    {issueish.reactionGroups.map(group => ( group.users.totalCount > 0 - ? {reactionTypeToEmoji[group.content]}   {group.users.totalCount} @@ -153,7 +153,7 @@ export class BareIssueishDetailView extends React.Component { /> } - {isPr &&
    + {isPr &&
    } diff --git a/styles/issueish-pane-item-view.less b/styles/issueish-detail-view.less similarity index 90% rename from styles/issueish-pane-item-view.less rename to styles/issueish-detail-view.less index d2188d4a66..a36451b2ab 100644 --- a/styles/issueish-pane-item-view.less +++ b/styles/issueish-detail-view.less @@ -1,6 +1,6 @@ @import 'variables'; -.github-IssueishPaneItemView { +.github-IssueishDetailView { padding: @component-padding * 3; overflow: auto; position: absolute; @@ -66,10 +66,10 @@ text-align: center; } &.refreshing::before { - @keyframes github-IssueishPaneItemView-headerRefreshButtonAnimation { + @keyframes github-IssueishDetailView-headerRefreshButtonAnimation { 100% { transform: rotate(360deg); } } - animation: github-IssueishPaneItemView-headerRefreshButtonAnimation 2s linear 30; // limit to 1min in case something gets stuck + animation: github-IssueishDetailView-headerRefreshButtonAnimation 2s linear 30; // limit to 1min in case something gets stuck } } From 33107baead67b03a8143319d57bf9da3c6006983 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 15:51:08 -0400 Subject: [PATCH 0402/4847] Test out the IssueishDetailView --- lib/views/issueish-detail-view.js | 3 +- test/fixtures/props/issueish-pane-props.js | 18 ++- test/views/issueish-detail-view.test.js | 158 +++++++++++++++++++++ 3 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 test/views/issueish-detail-view.test.js diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index e04d3d5638..36bfb39b50 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -38,6 +38,7 @@ export class BareIssueishDetailView extends React.Component { __typename: PropTypes.string.isRequired, id: PropTypes.string.isRequired, title: PropTypes.string, + url: PropTypes.string.isRequired, bodyHTML: PropTypes.string, number: PropTypes.number, state: PropTypes.oneOf([ @@ -154,7 +155,7 @@ export class BareIssueishDetailView extends React.Component { } {isPr &&
    - +
    }
    diff --git a/test/fixtures/props/issueish-pane-props.js b/test/fixtures/props/issueish-pane-props.js index ec1aecec31..e99817b731 100644 --- a/test/fixtures/props/issueish-pane-props.js +++ b/test/fixtures/props/issueish-pane-props.js @@ -55,22 +55,31 @@ export function issueishDetailControllerProps(opts, overrides = {}) { export function issueishDetailViewProps(opts, overrides = {}) { const o = { - issueishKind: 'PullRequest', - repositoryName: 'repository', ownerLogin: 'owner', + issueishKind: 'PullRequest', issueishTitle: 'title', issueishBodyHTML: '

    body

    ', issueishAuthorLogin: 'author', issueishAuthorAvatarURL: 'https://avatars3.githubusercontent.com/u/000?v=4', issueishNumber: 1, issueishState: 'OPEN', + issueishReactions: [], relayRefetch: () => {}, ...opts, }; + const buildReaction = reaction => { + return { + content: reaction.content, + users: { + totalCount: reaction.count, + }, + }; + }; + return { relay: { refetch: o.relayRefetch, @@ -88,6 +97,9 @@ export function issueishDetailViewProps(opts, overrides = {}) { id: 'pr0', __typename: o.issueishKind, title: o.issueishTitle, + url: o.issueishKind === 'PullRequest' + ? `https://github.com/${o.ownerLogin}/${o.repositoryName}/pull/${o.issueishNumber}` + : `https://github.com/${o.ownerLogin}/${o.repositoryName}/issues/${o.issueishNumber}`, bodyHTML: o.issueishBodyHTML, number: o.issueishNumber, state: o.issueishState, @@ -96,7 +108,7 @@ export function issueishDetailViewProps(opts, overrides = {}) { avatarUrl: o.issueishAuthorAvatarURL, url: `https://github.com/${o.issueishAuthorLogin}`, }, - reactionGroups: [], + reactionGroups: o.issueishReactions.map(buildReaction), }, switchToIssueish: () => {}, diff --git a/test/views/issueish-detail-view.test.js b/test/views/issueish-detail-view.test.js new file mode 100644 index 0000000000..7c0b3eff75 --- /dev/null +++ b/test/views/issueish-detail-view.test.js @@ -0,0 +1,158 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BareIssueishDetailView} from '../../lib/views/issueish-detail-view'; +import {issueishDetailViewProps} from '../fixtures/props/issueish-pane-props'; + +describe('IssueishDetailView', function() { + function buildApp(opts, overrideProps = {}) { + return ; + } + + it('renders pull request information', function() { + const wrapper = shallow(buildApp({ + repositoryName: 'repo', + ownerLogin: 'user0', + + issueishKind: 'PullRequest', + issueishTitle: 'PR title', + issueishBodyHTML: 'stuff', + issueishAuthorLogin: 'author0', + issueishAuthorAvatarURL: 'https://avatars3.githubusercontent.com/u/1', + issueishNumber: 100, + issueishState: 'MERGED', + issueishReactions: [{content: 'THUMBS_UP', count: 10}, {content: 'THUMBS_DOWN', count: 5}, {content: 'LAUGH', count: 0}], + })); + + const badge = wrapper.find('IssueishBadge'); + assert.strictEqual(badge.prop('type'), 'PullRequest'); + assert.strictEqual(badge.prop('state'), 'MERGED'); + + const link = wrapper.find('a.github-IssueishDetailView-headerLink'); + assert.strictEqual(link.text(), 'user0/repo#100'); + assert.strictEqual(link.prop('href'), 'https://github.com/user0/repo/pull/100'); + + assert.isDefined(wrapper.find('Relay(PrStatuses)[displayType="check"]').prop('pullRequest')); + + const avatarLink = wrapper.find('.github-IssueishDetailView-avatar'); + assert.strictEqual(avatarLink.prop('href'), 'https://github.com/author0'); + const avatar = avatarLink.find('img'); + assert.strictEqual(avatar.prop('src'), 'https://avatars3.githubusercontent.com/u/1'); + assert.strictEqual(avatar.prop('title'), 'author0'); + + assert.strictEqual(wrapper.find('.github-IssueishDetailView-title').text(), 'PR title'); + + assert.isTrue(wrapper.find('GithubDotcomMarkdown').someWhere(n => n.prop('html') === 'stuff')); + + const reactionGroups = wrapper.find('.github-IssueishDetailView-reactionsGroup'); + assert.lengthOf(reactionGroups.findWhere(n => /👍/u.test(n.text()) && /\b10\b/.test(n.text())), 1); + assert.lengthOf(reactionGroups.findWhere(n => /👎/u.test(n.text()) && /\b5\b/.test(n.text())), 1); + assert.isFalse(reactionGroups.someWhere(n => /😆/u.test(n.text()))); + + assert.isNull(wrapper.find('Relay(IssueishTimelineView)').prop('issue')); + assert.isNotNull(wrapper.find('Relay(IssueishTimelineView)').prop('pullRequest')); + assert.isNotNull(wrapper.find('Relay(PrStatuses)[displayType="full"]').prop('pullRequest')); + }); + + it('renders issue information', function() { + const wrapper = shallow(buildApp({ + repositoryName: 'repo', + ownerLogin: 'user1', + + issueishKind: 'Issue', + issueishTitle: 'Issue title', + issueishBodyHTML: 'nope', + issueishAuthorLogin: 'author1', + issueishAuthorAvatarURL: 'https://avatars3.githubusercontent.com/u/2', + issueishNumber: 200, + issueishState: 'CLOSED', + issueishReactions: [{content: 'THUMBS_UP', count: 6}, {content: 'THUMBS_DOWN', count: 0}, {content: 'LAUGH', count: 2}], + })); + + const badge = wrapper.find('IssueishBadge'); + assert.strictEqual(badge.prop('type'), 'Issue'); + assert.strictEqual(badge.prop('state'), 'CLOSED'); + + const link = wrapper.find('a.github-IssueishDetailView-headerLink'); + assert.strictEqual(link.text(), 'user1/repo#200'); + assert.strictEqual(link.prop('href'), 'https://github.com/user1/repo/issues/200'); + + assert.isFalse(wrapper.find('Relay(PrStatuses)').exists()); + + const avatarLink = wrapper.find('.github-IssueishDetailView-avatar'); + assert.strictEqual(avatarLink.prop('href'), 'https://github.com/author1'); + const avatar = avatarLink.find('img'); + assert.strictEqual(avatar.prop('src'), 'https://avatars3.githubusercontent.com/u/2'); + assert.strictEqual(avatar.prop('title'), 'author1'); + + assert.strictEqual(wrapper.find('.github-IssueishDetailView-title').text(), 'Issue title'); + + assert.isTrue(wrapper.find('GithubDotcomMarkdown').someWhere(n => n.prop('html') === 'nope')); + + const reactionGroups = wrapper.find('.github-IssueishDetailView-reactionsGroup'); + assert.lengthOf(reactionGroups.findWhere(n => /👍/u.test(n.text()) && /\b6\b/.test(n.text())), 1); + assert.isFalse(reactionGroups.someWhere(n => /👎/u.test(n.text()))); + assert.lengthOf(reactionGroups.findWhere(n => /😆/u.test(n.text()) && /\b2\b/.test(n.text())), 1); + + assert.isNotNull(wrapper.find('Relay(IssueishTimelineView)').prop('issue')); + assert.isNull(wrapper.find('Relay(IssueishTimelineView)').prop('pullRequest')); + }); + + it('renders a placeholder issueish body', function() { + const wrapper = shallow(buildApp({issueishBodyHTML: null})); + assert.isTrue(wrapper.find('GithubDotcomMarkdown').someWhere(n => /No description/.test(n.prop('html')))); + }); + + it('refreshes on click', function() { + let callback = null; + const relayRefetch = sinon.stub().callsFake((_0, _1, cb) => { + callback = cb; + }); + const wrapper = shallow(buildApp({relayRefetch}, {})); + + wrapper.find('Octicon[icon="repo-sync"]').simulate('click', {preventDefault: () => {}}); + assert.isTrue(wrapper.find('Octicon[icon="repo-sync"]').hasClass('refreshing')); + + callback(); + wrapper.update(); + + assert.isFalse(wrapper.find('Octicon[icon="repo-sync"]').hasClass('refreshing')); + }); + + it('disregardes a double refresh', function() { + let callback = null; + const relayRefetch = sinon.stub().callsFake((_0, _1, cb) => { + callback = cb; + }); + const wrapper = shallow(buildApp({relayRefetch}, {})); + + wrapper.find('Octicon[icon="repo-sync"]').simulate('click', {preventDefault: () => {}}); + assert.strictEqual(relayRefetch.callCount, 1); + + wrapper.find('Octicon[icon="repo-sync"]').simulate('click', {preventDefault: () => {}}); + assert.strictEqual(relayRefetch.callCount, 1); + + callback(); + wrapper.update(); + + wrapper.find('Octicon[icon="repo-sync"]').simulate('click', {preventDefault: () => {}}); + assert.strictEqual(relayRefetch.callCount, 2); + }); + + it('configures the refresher with a 5 minute polling interval', function() { + const wrapper = shallow(buildApp({})); + + assert.strictEqual(wrapper.instance().refresher.options.interval(), 5 * 60 * 1000); + }); + + it('destroys its refresher on unmount', function() { + const wrapper = shallow(buildApp({})); + + const refresher = wrapper.instance().refresher; + sinon.spy(refresher, 'destroy'); + + wrapper.unmount(); + + assert.isTrue(refresher.destroy.called); + }); +}); From 4b6f241ba16400fbc3a87aa5d85e3c8b41f17bc6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 16:12:53 -0400 Subject: [PATCH 0403/4847] Regenerate Relay queries --- .../issueishDetailContainerQuery.graphql.js | 14 +++---- ...eishDetailController_repository.graphql.js | 14 +++---- ...issueishDetailViewRefetchQuery.graphql.js} | 38 +++++++++---------- .../issueishDetailView_issueish.graphql.js} | 10 ++--- .../issueishDetailView_repository.graphql.js} | 10 ++--- .../issueish-detail-container.test.js | 2 +- 6 files changed, 44 insertions(+), 44 deletions(-) rename lib/{containers/__generated__/issueishPaneItemContainerRefetchQuery.graphql.js => views/__generated__/issueishDetailViewRefetchQuery.graphql.js} (81%) rename lib/{containers/__generated__/issueishPaneItemContainer_issueish.graphql.js => views/__generated__/issueishDetailView_issueish.graphql.js} (94%) rename lib/{containers/__generated__/issueishPaneItemContainer_repository.graphql.js => views/__generated__/issueishDetailView_repository.graphql.js} (77%) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 831b12007b..f85399804e 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash f746476b58e3b2c026b2609f9fd34880 + * @relayHash a9c4813acc6ce1b1808984294ef26262 */ /* eslint-disable */ @@ -38,7 +38,7 @@ query issueishDetailContainerQuery( } fragment issueishDetailController_repository_146t2V on Repository { - ...issueishPaneItemContainer_repository + ...issueishDetailView_repository name owner { __typename @@ -50,12 +50,12 @@ fragment issueishDetailController_repository_146t2V on Repository { ... on Issue { title number - ...issueishPaneItemContainer_issueish_1wZIw + ...issueishDetailView_issueish_1wZIw } ... on PullRequest { title number - ...issueishPaneItemContainer_issueish_1wZIw + ...issueishDetailView_issueish_1wZIw } ... on Node { id @@ -63,7 +63,7 @@ fragment issueishDetailController_repository_146t2V on Repository { } } -fragment issueishPaneItemContainer_repository on Repository { +fragment issueishDetailView_repository on Repository { id name owner { @@ -73,7 +73,7 @@ fragment issueishPaneItemContainer_repository on Repository { } } -fragment issueishPaneItemContainer_issueish_1wZIw on IssueOrPullRequest { +fragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest { __typename ... on Node { id @@ -882,7 +882,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_146t2V\n id\n }\n}\n\nfragment issueishDetailController_repository_146t2V on Repository {\n ...issueishPaneItemContainer_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishPaneItemContainer_issueish_1wZIw\n }\n ... on PullRequest {\n title\n number\n ...issueishPaneItemContainer_issueish_1wZIw\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishPaneItemContainer_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishPaneItemContainer_issueish_1wZIw on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue_1wZIw\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest_1wZIw\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue_1wZIw on Issue {\n url\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest_1wZIw on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_146t2V\n id\n }\n}\n\nfragment issueishDetailController_repository_146t2V on Repository {\n ...issueishDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishDetailView_issueish_1wZIw\n }\n ... on PullRequest {\n title\n number\n ...issueishDetailView_issueish_1wZIw\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue_1wZIw\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest_1wZIw\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue_1wZIw on Issue {\n url\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest_1wZIw on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", diff --git a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js index d826f4c26c..237c15b3f6 100644 --- a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js +++ b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js @@ -8,8 +8,8 @@ /*:: import type { ConcreteFragment } from 'relay-runtime'; -type issueishPaneItemContainer_issueish$ref = any; -type issueishPaneItemContainer_repository$ref = any; +type issueishDetailView_issueish$ref = any; +type issueishDetailView_repository$ref = any; import type { FragmentReference } from "relay-runtime"; declare export opaque type issueishDetailController_repository$ref: FragmentReference; export type issueishDetailController_repository = {| @@ -21,13 +21,13 @@ export type issueishDetailController_repository = {| +__typename: "Issue", +title: string, +number: number, - +$fragmentRefs: issueishPaneItemContainer_issueish$ref, + +$fragmentRefs: issueishDetailView_issueish$ref, |} | {| // This will never be '%other', but we need some // value in case none of the concrete values match. +__typename: "%other" |}), - +$fragmentRefs: issueishPaneItemContainer_repository$ref, + +$fragmentRefs: issueishDetailView_repository$ref, +$refType: issueishDetailController_repository$ref, |}; */ @@ -51,7 +51,7 @@ var v0 = [ }, { "kind": "FragmentSpread", - "name": "issueishPaneItemContainer_issueish", + "name": "issueishDetailView_issueish", "args": [ { "kind": "Variable", @@ -96,7 +96,7 @@ return { "selections": [ { "kind": "FragmentSpread", - "name": "issueishPaneItemContainer_repository", + "name": "issueishDetailView_repository", "args": null }, { @@ -163,5 +163,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'eaeab6bcc00588b29a2eaf7b6c107176'; +(node/*: any*/).hash = 'a4817f0fee232866758b7c80c77e71a9'; module.exports = node; diff --git a/lib/containers/__generated__/issueishPaneItemContainerRefetchQuery.graphql.js b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js similarity index 81% rename from lib/containers/__generated__/issueishPaneItemContainerRefetchQuery.graphql.js rename to lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js index e42eca4f38..efa007bf53 100644 --- a/lib/containers/__generated__/issueishPaneItemContainerRefetchQuery.graphql.js +++ b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash b45b269409a7865246e37c4dc1a47432 + * @relayHash 1fec69af8de0cc21e82edc72a3aa6f54 */ /* eslint-disable */ @@ -9,27 +9,27 @@ /*:: import type { ConcreteRequest } from 'relay-runtime'; -type issueishPaneItemContainer_issueish$ref = any; -type issueishPaneItemContainer_repository$ref = any; -export type issueishPaneItemContainerRefetchQueryVariables = {| +type issueishDetailView_issueish$ref = any; +type issueishDetailView_repository$ref = any; +export type issueishDetailViewRefetchQueryVariables = {| repoId: string, issueishId: string, timelineCount: number, timelineCursor?: ?string, |}; -export type issueishPaneItemContainerRefetchQueryResponse = {| +export type issueishDetailViewRefetchQueryResponse = {| +repository: ?{| - +$fragmentRefs: issueishPaneItemContainer_repository$ref + +$fragmentRefs: issueishDetailView_repository$ref |}, +issueish: ?{| - +$fragmentRefs: issueishPaneItemContainer_issueish$ref + +$fragmentRefs: issueishDetailView_issueish$ref |}, |}; */ /* -query issueishPaneItemContainerRefetchQuery( +query issueishDetailViewRefetchQuery( $repoId: ID! $issueishId: ID! $timelineCount: Int! @@ -37,17 +37,17 @@ query issueishPaneItemContainerRefetchQuery( ) { repository: node(id: $repoId) { __typename - ...issueishPaneItemContainer_repository + ...issueishDetailView_repository id } issueish: node(id: $issueishId) { __typename - ...issueishPaneItemContainer_issueish_3D8CP9 + ...issueishDetailView_issueish_3D8CP9 id } } -fragment issueishPaneItemContainer_repository on Repository { +fragment issueishDetailView_repository on Repository { id name owner { @@ -57,7 +57,7 @@ fragment issueishPaneItemContainer_repository on Repository { } } -fragment issueishPaneItemContainer_issueish_3D8CP9 on IssueOrPullRequest { +fragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest { __typename ... on Node { id @@ -838,13 +838,13 @@ v30 = { return { "kind": "Request", "operationKind": "query", - "name": "issueishPaneItemContainerRefetchQuery", + "name": "issueishDetailViewRefetchQuery", "id": null, - "text": "query issueishPaneItemContainerRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishPaneItemContainer_repository\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishPaneItemContainer_issueish_3D8CP9\n id\n }\n}\n\nfragment issueishPaneItemContainer_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishPaneItemContainer_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishDetailView_repository\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishDetailView_issueish_3D8CP9\n id\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", - "name": "issueishPaneItemContainerRefetchQuery", + "name": "issueishDetailViewRefetchQuery", "type": "Query", "metadata": null, "argumentDefinitions": v0, @@ -860,7 +860,7 @@ return { "selections": [ { "kind": "FragmentSpread", - "name": "issueishPaneItemContainer_repository", + "name": "issueishDetailView_repository", "args": null } ] @@ -876,7 +876,7 @@ return { "selections": [ { "kind": "FragmentSpread", - "name": "issueishPaneItemContainer_issueish", + "name": "issueishDetailView_issueish", "args": [ { "kind": "Variable", @@ -898,7 +898,7 @@ return { }, "operation": { "kind": "Operation", - "name": "issueishPaneItemContainerRefetchQuery", + "name": "issueishDetailViewRefetchQuery", "argumentDefinitions": v0, "selections": [ { @@ -1346,5 +1346,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '51442b1c4d9a853580138f01efbc45fa'; +(node/*: any*/).hash = '7607224ca8842b4949c0e98e1a37c3bf'; module.exports = node; diff --git a/lib/containers/__generated__/issueishPaneItemContainer_issueish.graphql.js b/lib/views/__generated__/issueishDetailView_issueish.graphql.js similarity index 94% rename from lib/containers/__generated__/issueishPaneItemContainer_issueish.graphql.js rename to lib/views/__generated__/issueishDetailView_issueish.graphql.js index 4320f71a51..2c88baf126 100644 --- a/lib/containers/__generated__/issueishPaneItemContainer_issueish.graphql.js +++ b/lib/views/__generated__/issueishDetailView_issueish.graphql.js @@ -15,8 +15,8 @@ export type IssueState = "CLOSED" | "OPEN" | "%future added value"; export type PullRequestState = "CLOSED" | "MERGED" | "OPEN" | "%future added value"; export type ReactionContent = "CONFUSED" | "HEART" | "HOORAY" | "LAUGH" | "THUMBS_DOWN" | "THUMBS_UP" | "%future added value"; import type { FragmentReference } from "relay-runtime"; -declare export opaque type issueishPaneItemContainer_issueish$ref: FragmentReference; -export type issueishPaneItemContainer_issueish = {| +declare export opaque type issueishDetailView_issueish$ref: FragmentReference; +export type issueishDetailView_issueish = {| +__typename: string, +id?: string, +url?: any, @@ -36,7 +36,7 @@ export type issueishPaneItemContainer_issueish = {| +url?: any, |}, +$fragmentRefs: issueTimelineContainer_issue$ref & prStatusesContainer_pullRequest$ref & prTimelineContainer_pullRequest$ref, - +$refType: issueishPaneItemContainer_issueish$ref, + +$refType: issueishDetailView_issueish$ref, |}; */ @@ -131,7 +131,7 @@ v7 = [ ]; return { "kind": "Fragment", - "name": "issueishPaneItemContainer_issueish", + "name": "issueishDetailView_issueish", "type": "IssueOrPullRequest", "metadata": null, "argumentDefinitions": [ @@ -241,5 +241,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'ddb3723645bb5fa5dbe55b81807a162f'; +(node/*: any*/).hash = '4030ff81df8e392b072a39440744e2bb'; module.exports = node; diff --git a/lib/containers/__generated__/issueishPaneItemContainer_repository.graphql.js b/lib/views/__generated__/issueishDetailView_repository.graphql.js similarity index 77% rename from lib/containers/__generated__/issueishPaneItemContainer_repository.graphql.js rename to lib/views/__generated__/issueishDetailView_repository.graphql.js index cbc0925496..7276c2e12e 100644 --- a/lib/containers/__generated__/issueishPaneItemContainer_repository.graphql.js +++ b/lib/views/__generated__/issueishDetailView_repository.graphql.js @@ -9,21 +9,21 @@ /*:: import type { ConcreteFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; -declare export opaque type issueishPaneItemContainer_repository$ref: FragmentReference; -export type issueishPaneItemContainer_repository = {| +declare export opaque type issueishDetailView_repository$ref: FragmentReference; +export type issueishDetailView_repository = {| +id: string, +name: string, +owner: {| +login: string |}, - +$refType: issueishPaneItemContainer_repository$ref, + +$refType: issueishDetailView_repository$ref, |}; */ const node/*: ConcreteFragment*/ = { "kind": "Fragment", - "name": "issueishPaneItemContainer_repository", + "name": "issueishDetailView_repository", "type": "Repository", "metadata": null, "argumentDefinitions": [], @@ -63,5 +63,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = 'e8a9f31307e91bb7637ca2303809e3e2'; +(node/*: any*/).hash = '816e09e12a5fbb89558b0ae0bfdc76af'; module.exports = node; diff --git a/test/containers/issueish-detail-container.test.js b/test/containers/issueish-detail-container.test.js index 7a8d20ec16..c2f9e37847 100644 --- a/test/containers/issueish-detail-container.test.js +++ b/test/containers/issueish-detail-container.test.js @@ -8,7 +8,7 @@ import GithubLoginModel from '../../lib/models/github-login-model'; import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; import IssueishDetailContainer from '../../lib/containers/issueish-detail-container'; -describe('IssueishDetailContainer', function() { +describe.only('IssueishDetailContainer', function() { let loginModel; beforeEach(function() { From dd8489132f0b8195d66e26918ecfc9a519830440 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Jun 2018 16:13:49 -0400 Subject: [PATCH 0404/4847] Oops --- test/containers/issueish-detail-container.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/containers/issueish-detail-container.test.js b/test/containers/issueish-detail-container.test.js index c2f9e37847..7a8d20ec16 100644 --- a/test/containers/issueish-detail-container.test.js +++ b/test/containers/issueish-detail-container.test.js @@ -8,7 +8,7 @@ import GithubLoginModel from '../../lib/models/github-login-model'; import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; import IssueishDetailContainer from '../../lib/containers/issueish-detail-container'; -describe.only('IssueishDetailContainer', function() { +describe('IssueishDetailContainer', function() { let loginModel; beforeEach(function() { From 9c588db39bf0dbd8e765694d4aca9dbb7d29967c Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 28 Jun 2018 12:23:37 +0900 Subject: [PATCH 0405/4847] Update screenshots Ref. https://github.com/atom/github/issues/1555 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 59fe4dfe21..1ca17da7da 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ The Atom GitHub package provides Git and GitHub integration for Atom. Check out [github.atom.io](https://github.atom.io) for more information. -git-integration +git-integration -github-integration +merge-conflicts -merge-conflicts +github-integration ## Installation From b7c9ced354a5bb7f75d002cf6a58ec51c0b0c138 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Jun 2018 10:44:18 -0400 Subject: [PATCH 0406/4847] Turn IssueTimeline and PrTimeline into Controllers --- .../issue-timeline-controller.js} | 0 .../pr-timeline-controller.js} | 0 lib/views/issueish-detail-view.js | 6 +++--- 3 files changed, 3 insertions(+), 3 deletions(-) rename lib/{containers/issue-timeline-container.js => controllers/issue-timeline-controller.js} (100%) rename lib/{containers/pr-timeline-container.js => controllers/pr-timeline-controller.js} (100%) diff --git a/lib/containers/issue-timeline-container.js b/lib/controllers/issue-timeline-controller.js similarity index 100% rename from lib/containers/issue-timeline-container.js rename to lib/controllers/issue-timeline-controller.js diff --git a/lib/containers/pr-timeline-container.js b/lib/controllers/pr-timeline-controller.js similarity index 100% rename from lib/containers/pr-timeline-container.js rename to lib/controllers/pr-timeline-controller.js diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index 36bfb39b50..5a2f2cb3aa 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -3,8 +3,8 @@ import {graphql, createRefetchContainer} from 'react-relay'; import PropTypes from 'prop-types'; import cx from 'classnames'; -import IssueTimelineContainer from '../containers/issue-timeline-container'; -import PrTimelineContainer from '../containers/pr-timeline-container'; +import IssueTimelineController from '../controllers/issue-timeline-controller'; +import PrTimelineContainer from '../controllers/pr-timeline-controller'; import PrStatusesContainer from '../containers/pr-statuses-container'; import Octicon from '../atom/octicon'; import IssueishBadge from '../views/issueish-badge'; @@ -148,7 +148,7 @@ export class BareIssueishDetailView extends React.Component { {...childProps} switchToIssueish={this.props.switchToIssueish} /> : - From 639b23cfc7a5da35347747f3983211fcc4ec5f3b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Jun 2018 13:44:40 -0400 Subject: [PATCH 0407/4847] Rename PrStatusesContainer to PrStatusesView and test it --- lib/containers/pr-status-context-container.js | 2 +- lib/models/issueish.js | 2 +- lib/views/issueish-detail-view.js | 6 +- .../pr-statuses-view.js} | 18 +-- .../fixtures/factories/pull-request-result.js | 14 +- test/views/pr-statuses-view.test.js | 147 ++++++++++++++++++ 6 files changed, 173 insertions(+), 16 deletions(-) rename lib/{containers/pr-statuses-container.js => views/pr-statuses-view.js} (90%) create mode 100644 test/views/pr-statuses-view.test.js diff --git a/lib/containers/pr-status-context-container.js b/lib/containers/pr-status-context-container.js index ec2d762ad7..bbebf100b8 100644 --- a/lib/containers/pr-status-context-container.js +++ b/lib/containers/pr-status-context-container.js @@ -3,7 +3,7 @@ import {createFragmentContainer, graphql} from 'react-relay'; import PropTypes from 'prop-types'; import Octicon from '../atom/octicon'; -import {stateToIconAndStyle} from './pr-statuses-container'; +import {stateToIconAndStyle} from '../views/pr-statuses-view'; export class PrStatusContext extends React.Component { static propTypes = { diff --git a/lib/models/issueish.js b/lib/models/issueish.js index 6acac64dc2..2ee646497d 100644 --- a/lib/models/issueish.js +++ b/lib/models/issueish.js @@ -1,7 +1,7 @@ import {URL} from 'url'; import moment from 'moment'; -import {category} from '../containers/pr-statuses-container'; +import {category} from '../views/pr-statuses-view'; export default class Issueish { constructor(data) { diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index 5a2f2cb3aa..0a92f73164 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -5,7 +5,7 @@ import cx from 'classnames'; import IssueTimelineController from '../controllers/issue-timeline-controller'; import PrTimelineContainer from '../controllers/pr-timeline-controller'; -import PrStatusesContainer from '../containers/pr-statuses-container'; +import PrStatusesView from '../views/pr-statuses-view'; import Octicon from '../atom/octicon'; import IssueishBadge from '../views/issueish-badge'; import GithubDotcomMarkdown from '../views/github-dotcom-markdown'; @@ -106,7 +106,7 @@ export class BareIssueishDetailView extends React.Component { href={issueish.url}>{repo.owner.login}/{repo.name}#{issueish.number} {isPr && - + }
    @@ -155,7 +155,7 @@ export class BareIssueishDetailView extends React.Component { } {isPr &&
    - +
    }
    diff --git a/lib/containers/pr-statuses-container.js b/lib/views/pr-statuses-view.js similarity index 90% rename from lib/containers/pr-statuses-container.js rename to lib/views/pr-statuses-view.js index e69fdaa357..b088514a8f 100644 --- a/lib/containers/pr-statuses-container.js +++ b/lib/views/pr-statuses-view.js @@ -3,9 +3,9 @@ import {createRefetchContainer, graphql} from 'react-relay'; import PropTypes from 'prop-types'; import {toSentence, autobind} from '../helpers'; -import PrStatusContextContainer from './pr-status-context-container'; +import PrStatusContextContainer from '../containers/pr-status-context-container'; import Octicon from '../atom/octicon'; -import StatusDonutChart from '../views/status-donut-chart'; +import StatusDonutChart from './status-donut-chart'; import PeriodicRefresher from '../periodic-refresher'; import {RelayConnectionPropType} from '../prop-types'; @@ -25,7 +25,7 @@ export function category(state) { return info.category; } -export class PrStatuses extends React.Component { +export class BarePrStatusesView extends React.Component { static propTypes = { relay: PropTypes.shape({ refetch: PropTypes.func.isRequired, @@ -67,17 +67,17 @@ export class PrStatuses extends React.Component { } componentDidMount() { - this.refresher = new PeriodicRefresher(PrStatuses, { + this.refresher = new PeriodicRefresher(this.constructor, { interval: () => { if (this.isPendingResults()) { - return PrStatuses.PENDING_REFRESH_TIMEOUT; + return this.constructor.PENDING_REFRESH_TIMEOUT; } else { - return PrStatuses.SUCCESS_REFRESH_TIMEOUT; + return this.constructor.SUCCESS_REFRESH_TIMEOUT; } }, getCurrentId: () => this.props.pullRequest.id, refresh: this.refresh, - minimumIntervalPerId: PrStatuses.MINIMUM_REFRESH_INTERVAL, + minimumIntervalPerId: this.constructor.MINIMUM_REFRESH_INTERVAL, }); this.refresher.start(); } @@ -117,7 +117,7 @@ export class PrStatuses extends React.Component {
    ); } else { - throw new Error('Invalid `displayType` prop value'); + throw new Error(`Invalid \`displayType\` prop value: ${this.props.displayType}`); } } @@ -177,7 +177,7 @@ export class PrStatuses extends React.Component { } } -export default createRefetchContainer(PrStatuses, { +export default createRefetchContainer(BarePrStatusesView, { pullRequest: graphql` fragment prStatusesContainer_pullRequest on PullRequest { id diff --git a/test/fixtures/factories/pull-request-result.js b/test/fixtures/factories/pull-request-result.js index d2c628ee31..c1a59a11bc 100644 --- a/test/fixtures/factories/pull-request-result.js +++ b/test/fixtures/factories/pull-request-result.js @@ -12,11 +12,17 @@ export function createPullRequestResult(attrs = {}) { const o = { number: 0, repositoryID: 'repository0', + summaryState: null, states: null, headRefName: 'master', + includeEdges: false, ...attrs, }; + if (o.summaryState && !o.states) { + o.states = [o.summaryState]; + } + const commit = { id: 'commit0', }; @@ -25,10 +31,15 @@ export function createPullRequestResult(attrs = {}) { commit.status = null; } else { commit.status = { + state: o.summaryState, contexts: o.states.map((state, id) => ({state, id: `state${id}`})), }; } + const commits = o.includeEdges + ? {edges: [{node: {id: 'node0', commit}}]} + : {nodes: [{commit, id: 'node0'}]}; + return { __typename: 'PullRequest', id: `pullrequest${o.number}`, @@ -48,8 +59,7 @@ export function createPullRequestResult(attrs = {}) { id: o.repositoryID, }, - commits: {nodes: [{commit, id: 'node0'}]}, - + commits, } } diff --git a/test/views/pr-statuses-view.test.js b/test/views/pr-statuses-view.test.js new file mode 100644 index 0000000000..f169dfea02 --- /dev/null +++ b/test/views/pr-statuses-view.test.js @@ -0,0 +1,147 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BarePrStatusesView} from '../../lib/views/pr-statuses-view'; +import {createPullRequestResult} from '../fixtures/factories/pull-request-result'; + +describe('PrStatusesView', function() { + function buildPullRequestResult(opts) { + return createPullRequestResult({includeEdges: true, ...opts}); + } + + function buildApp(opts, overrideProps = {}) { + const props = { + relay: { + refetch: () => {}, + }, + displayType: 'full', + pullRequest: buildPullRequestResult(opts), + ...overrideProps, + }; + + return ; + } + + it('renders nothing if the pull request has no status', function() { + const wrapper = shallow(buildApp({})); + assert.lengthOf(wrapper.children(), 0); + }); + + it('renders a styled octicon with displayType: check', function() { + const wrapper = shallow(buildApp({summaryState: 'EXPECTED'}, {displayType: 'check'})); + assert.isTrue(wrapper.find('Octicon[icon="primitive-dot"]').hasClass('github-PrStatuses--warning')); + + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'PENDING'}), + }); + assert.isTrue(wrapper.find('Octicon[icon="primitive-dot"]').hasClass('github-PrStatuses--warning')); + + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'SUCCESS'}), + }); + assert.isTrue(wrapper.find('Octicon[icon="check"]').hasClass('github-PrStatuses--success')); + + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'ERROR'}), + }); + assert.isTrue(wrapper.find('Octicon[icon="alert"]').hasClass('github-PrStatuses--error')); + + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'FAILURE'}), + }); + assert.isTrue(wrapper.find('Octicon[icon="x"]').hasClass('github-PrStatuses--error')); + }); + + it('renders a donut chart', function() { + const wrapper = shallow(buildApp({summaryState: 'FAILURE', states: ['SUCCESS', 'FAILURE', 'ERROR']})); + + const donutChart = wrapper.find('StatusDonutChart'); + assert.strictEqual(donutChart.prop('pending'), 0); + assert.strictEqual(donutChart.prop('failure'), 2); + assert.strictEqual(donutChart.prop('success'), 1); + }); + + it('renders a summary sentence', function() { + const wrapper = shallow(buildApp({summaryState: 'SUCCESS', states: ['SUCCESS', 'SUCCESS', 'SUCCESS']})); + assert.strictEqual(wrapper.find('.github-PrStatuses-summary').text(), 'All checks succeeded'); + + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'FAILURE', states: ['FAILURE', 'ERROR', 'FAILURE']}), + }); + assert.strictEqual(wrapper.find('.github-PrStatuses-summary').text(), 'All checks failed'); + + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'PENDING', states: ['PENDING', 'PENDING', 'PENDING']}), + }); + assert.strictEqual(wrapper.find('.github-PrStatuses-summary').text(), '3 pending checks'); + + // No pending checks + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'FAILURE', states: ['SUCCESS', 'SUCCESS', 'FAILURE']}), + }); + assert.strictEqual(wrapper.find('.github-PrStatuses-summary').text(), '1 failing and 2 successful checks'); + + // No failing checks + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'PENDING', states: ['SUCCESS', 'PENDING', 'PENDING']}), + }); + assert.strictEqual(wrapper.find('.github-PrStatuses-summary').text(), '2 pending and 1 successful checks'); + + // No succeeding checks + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'FAILURE', states: ['FAILURE', 'ERROR', 'PENDING']}), + }); + assert.strictEqual(wrapper.find('.github-PrStatuses-summary').text(), '1 pending and 2 failing checks'); + + // All three categories + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'FAILURE', states: ['PENDING', 'SUCCESS', 'SUCCESS', 'FAILURE', 'FAILURE', 'FAILURE']}), + }); + assert.strictEqual(wrapper.find('.github-PrStatuses-summary').text(), '1 pending, 3 failing, and 2 successful checks'); + + // Singular + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'PENDING', states: ['PENDING']}), + }); + assert.strictEqual(wrapper.find('.github-PrStatuses-summary').text(), '1 pending check'); + }); + + it('renders a context view for each status context', function() { + const wrapper = shallow(buildApp({summaryState: 'FAILURE', states: ['SUCCESS', 'FAILURE', 'ERROR']})); + + const contextViews = wrapper.find('Relay(PrStatusContext)'); + assert.deepEqual(contextViews.map(v => v.prop('context').state), ['SUCCESS', 'FAILURE', 'ERROR']); + }); + + it('constructs a PeriodicRefresher to update the status checks', function() { + const refetch = sinon.stub(); + const wrapper = shallow(buildApp({summaryState: 'PENDING', states: ['PENDING', 'PENDING']}, { + relay: { + refetch, + }, + })); + const refresher = wrapper.instance().refresher; + assert.strictEqual(refresher.options.interval(), BarePrStatusesView.PENDING_REFRESH_TIMEOUT); + + wrapper.setProps({ + pullRequest: buildPullRequestResult({summaryState: 'FAILURE', state: ['FAILURE', 'SUCCESS']}), + }); + assert.strictEqual(refresher.options.interval(), BarePrStatusesView.SUCCESS_REFRESH_TIMEOUT); + + assert.isFalse(refetch.called); + refresher.refreshNow(true); + assert.isTrue(refetch.calledWith({id: 'pullrequest0'})); + + sinon.spy(refresher, 'destroy'); + wrapper.unmount(); + assert.isTrue(refresher.destroy.called); + }); + + it('throws an error on an unknown state', function() { + assert.throws(() => shallow(buildApp({states: ['OHNO']})), /OHNO/); + }); + + it('throws an error on an unknown displayType', function() { + assert.throws(() => shallow(buildApp({states: ['SUCCESS']}, {displayType: 'crazypants'})), /crazypants/); + }); +}); From 41c5bdb765fe241112dc8fd168b7f1dd233eaaa0 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Jun 2018 14:16:40 -0400 Subject: [PATCH 0408/4847] Use an ID generator to ensure IDs are unique --- test/fixtures/factories/id-generator.js | 21 ++++++ .../fixtures/factories/pull-request-result.js | 73 +++++++++++++++---- test/fixtures/factories/repository-result.js | 6 +- test/views/pr-statuses-view.test.js | 2 +- 4 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 test/fixtures/factories/id-generator.js diff --git a/test/fixtures/factories/id-generator.js b/test/fixtures/factories/id-generator.js new file mode 100644 index 0000000000..afcf1aedae --- /dev/null +++ b/test/fixtures/factories/id-generator.js @@ -0,0 +1,21 @@ +const IDGEN = Symbol('id-generator'); + +export default class IDGenerator { + static fromOpts(opts = {}) { + return opts[IDGEN] || new this(); + } + + constructor() { + this.current = 0; + } + + generate(prefix = '') { + const id = this.current; + this.current++; + return `${prefix}${id}`; + } + + embed() { + return {[IDGEN]: this}; + } +} diff --git a/test/fixtures/factories/pull-request-result.js b/test/fixtures/factories/pull-request-result.js index c1a59a11bc..75e63e3043 100644 --- a/test/fixtures/factories/pull-request-result.js +++ b/test/fixtures/factories/pull-request-result.js @@ -1,3 +1,5 @@ +import IDGenerator from './id-generator'; + function createCommitResult(attrs = {}) { return { commit: { @@ -8,10 +10,44 @@ function createCommitResult(attrs = {}) { }; } +export function createStatusContextResult(attrs = {}) { + const idGen = IDGenerator.fromOpts(attrs); + + const o = { + id: idGen.generate('context'), + context: 'context', + description: 'description', + state: 'SUCCESS', + creatorLogin: 'me', + creatorAvatarUrl: 'https://avatars3.githubusercontent.com/u/000?v=1', + ...idGen.embed(), + ...attrs, + } + + if (!o.targetUrl) { + o.targetUrl = `https://ci.provider.com/builds/${o.id}` + } + + return { + id: o.id, + context: o.context, + description: o.description, + state: o.state, + targetUrl: o.targetUrl, + creator: { + avatarUrl: o.creatorAvatarUrl, + login: o.creatorLogin, + } + } +} + export function createPullRequestResult(attrs = {}) { + const idGen = IDGenerator.fromOpts(attrs); + const o = { + id: idGen.generate('pullrequest'), number: 0, - repositoryID: 'repository0', + repositoryID: idGen.generate('repository'), summaryState: null, states: null, headRefName: 'master', @@ -20,11 +56,19 @@ export function createPullRequestResult(attrs = {}) { }; if (o.summaryState && !o.states) { - o.states = [o.summaryState]; + o.states = [{state: o.summaryState, ...idGen.embed()}]; + } + + if (o.states) { + o.states = o.states.map(state => { + return typeof state === 'string' + ? {state: state, ...idGen.embed()} + : state + }); } const commit = { - id: 'commit0', + id: idGen.generate('commit'), }; if (o.states === null) { @@ -32,17 +76,17 @@ export function createPullRequestResult(attrs = {}) { } else { commit.status = { state: o.summaryState, - contexts: o.states.map((state, id) => ({state, id: `state${id}`})), + contexts: o.states.map(createStatusContextResult), }; } const commits = o.includeEdges - ? {edges: [{node: {id: 'node0', commit}}]} - : {nodes: [{commit, id: 'node0'}]}; + ? {edges: [{node: {id: idGen.generate('node'), commit}}]} + : {nodes: [{commit, id: idGen.generate('node')}]}; return { __typename: 'PullRequest', - id: `pullrequest${o.number}`, + id: o.id, number: o.number, title: `Pull Request ${o.number}`, url: `https://github.com/owner/repo/pulls/${o.number}`, @@ -64,7 +108,10 @@ export function createPullRequestResult(attrs = {}) { } export function createPullRequestDetailResult(attrs = {}) { + const idGen = IDGenerator.fromOpts(attrs); + const o = { + id: idGen.generate('pullrequest'), number: 0, title: 'title', state: 'OPEN', @@ -77,20 +124,20 @@ export function createPullRequestDetailResult(attrs = {}) { }; const commit = { - id: 'commit0', + id: idGen.generate('commit'), status: null, }; return { __typename: 'PullRequest', - id: `pullrequest${o.number}`, + id: o.id, title: o.title, number: o.number, state: o.state, bodyHTML: '

    body

    ', author: { __typename: 'User', - id: `user${o.authorLogin}`, + id: idGen('user'), login: o.authorLogin, avatarUrl: o.authorAvatarURL, url: `https://github.com/${o.authorLogin}`, @@ -112,16 +159,16 @@ export function createPullRequestDetailResult(attrs = {}) { headRefName: o.headRefName, headRepositoryOwner: { __typename: 'User', - id: `user${o.headRepositoryLogin}`, + id: idGen.generate('user'), login: o.headRepositoryLogin, }, repository: { owner: { __typename: 'User', - id: `user${o.baseRepositoryLogin}`, + id: idGen.generate('user'), login: o.baseRepositoryLogin, }, - id: 'baserepository', + id: idGen.generate('repository'), } }; } diff --git a/test/fixtures/factories/repository-result.js b/test/fixtures/factories/repository-result.js index bec284827d..61519d920c 100644 --- a/test/fixtures/factories/repository-result.js +++ b/test/fixtures/factories/repository-result.js @@ -1,6 +1,10 @@ +import IDGenerator from './id-generator'; + export function createRepositoryResult(attrs = {}) { + const idGen = IDGenerator.fromOpts(attrs); + const o = { - id: 'repository0', + id: idGen.generate('repository'), defaultRefPrefix: 'refs/heads/', defaultRefName: 'master', defaultRefID: 'ref0', diff --git a/test/views/pr-statuses-view.test.js b/test/views/pr-statuses-view.test.js index f169dfea02..dfd5ac33a2 100644 --- a/test/views/pr-statuses-view.test.js +++ b/test/views/pr-statuses-view.test.js @@ -115,7 +115,7 @@ describe('PrStatusesView', function() { it('constructs a PeriodicRefresher to update the status checks', function() { const refetch = sinon.stub(); - const wrapper = shallow(buildApp({summaryState: 'PENDING', states: ['PENDING', 'PENDING']}, { + const wrapper = shallow(buildApp({id: 'pullrequest0', summaryState: 'PENDING', states: ['PENDING', 'PENDING']}, { relay: { refetch, }, From b8a8a373cd4c430e762308ed398a5a043e11227c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Jun 2018 14:18:29 -0400 Subject: [PATCH 0409/4847] Move PrStatusContextContainer to PrStatusContextView and test it --- .../pr-status-context-view.js} | 6 ++-- lib/views/pr-statuses-view.js | 6 ++-- test/views/pr-status-context-view.test.js | 28 +++++++++++++++++++ 3 files changed, 34 insertions(+), 6 deletions(-) rename lib/{containers/pr-status-context-container.js => views/pr-status-context-view.js} (87%) create mode 100644 test/views/pr-status-context-view.test.js diff --git a/lib/containers/pr-status-context-container.js b/lib/views/pr-status-context-view.js similarity index 87% rename from lib/containers/pr-status-context-container.js rename to lib/views/pr-status-context-view.js index bbebf100b8..9198ddfd68 100644 --- a/lib/containers/pr-status-context-container.js +++ b/lib/views/pr-status-context-view.js @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; import Octicon from '../atom/octicon'; import {stateToIconAndStyle} from '../views/pr-statuses-view'; -export class PrStatusContext extends React.Component { +export class BarePrStatusContextView extends React.Component { static propTypes = { context: PropTypes.shape({ context: PropTypes.string.isRequired, @@ -38,9 +38,9 @@ export class PrStatusContext extends React.Component { } } -export default createFragmentContainer(PrStatusContext, { +export default createFragmentContainer(BarePrStatusContextView, { context: graphql` - fragment prStatusContextContainer_context on StatusContext { + fragment prStatusContextView_context on StatusContext { context description state targetUrl } `, diff --git a/lib/views/pr-statuses-view.js b/lib/views/pr-statuses-view.js index b088514a8f..62b4a15984 100644 --- a/lib/views/pr-statuses-view.js +++ b/lib/views/pr-statuses-view.js @@ -3,7 +3,7 @@ import {createRefetchContainer, graphql} from 'react-relay'; import PropTypes from 'prop-types'; import {toSentence, autobind} from '../helpers'; -import PrStatusContextContainer from '../containers/pr-status-context-container'; +import PrStatusContextView from './pr-status-context-view'; import Octicon from '../atom/octicon'; import StatusDonutChart from './status-donut-chart'; import PeriodicRefresher from '../periodic-refresher'; @@ -112,7 +112,7 @@ export class BarePrStatusesView extends React.Component {
      - {contexts.map(context => )} + {contexts.map(context => )}
    ); @@ -190,7 +190,7 @@ export default createRefetchContainer(BarePrStatusesView, { contexts { id state - ...prStatusContextContainer_context + ...prStatusContextView_context } } } diff --git a/test/views/pr-status-context-view.test.js b/test/views/pr-status-context-view.test.js new file mode 100644 index 0000000000..9204d6e8ea --- /dev/null +++ b/test/views/pr-status-context-view.test.js @@ -0,0 +1,28 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BarePrStatusContextView} from '../../lib/views/pr-status-context-view'; +import {createStatusContextResult} from '../fixtures/factories/pull-request-result'; + +describe('PrStatusContextView', function() { + function buildApp(opts = {}) { + return ; + } + + it('renders an octicon corresponding to the status context state', function() { + const wrapper = shallow(buildApp({state: 'ERROR'})); + assert.isTrue(wrapper.find('Octicon[icon="alert"]').hasClass('github-PrStatuses--error')); + }); + + it('renders the context name and description', function() { + const wrapper = shallow(buildApp({context: 'the context', description: 'the description'})); + assert.match(wrapper.find('.github-PrStatuses-list-item-context').text(), /the context/); + assert.match(wrapper.find('.github-PrStatuses-list-item-context').text(), /the description/); + }); + + it('renders a link to the details', function() { + const targetUrl = 'https://ci.provider.com/builds/123'; + const wrapper = shallow(buildApp({targetUrl})); + assert.strictEqual(wrapper.find('.github-PrStatuses-list-item-details-link a').prop('href'), targetUrl); + }); +}); From 040d8b92add003eba95e9b3473d0cca815bfb46b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Jun 2018 15:33:30 -0400 Subject: [PATCH 0410/4847] Test the IssueishTimelineView --- lib/views/issueish-timeline-view.js | 10 +- test/views/issueish-timeline-view.test.js | 186 ++++++++++++++++++++++ 2 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 test/views/issueish-timeline-view.test.js diff --git a/lib/views/issueish-timeline-view.js b/lib/views/issueish-timeline-view.js index 68794e0e24..a7e7d9d768 100644 --- a/lib/views/issueish-timeline-view.js +++ b/lib/views/issueish-timeline-view.js @@ -11,9 +11,9 @@ import HeadRefForcePushedEventContainer from './../containers/timeline-items/hea import CrossReferencedEventsContainer from './../containers/timeline-items/cross-referenced-events-container.js'; import CommitCommentThreadContainer from './../containers/timeline-items/commit-comment-thread-container'; -function collectionRenderer(Component, styleAsTimelineItem = true) { +export function collectionRenderer(Component, styleAsTimelineItem = true) { return class GroupedComponent extends React.Component { - static displayName = `Grouped(${Component.name})` + static displayName = `Grouped(${Component.displayName})` static propTypes = { nodes: PropTypes.array.isRequired, @@ -109,16 +109,16 @@ export default class IssueishTimelineView extends React.Component { ); } else { // eslint-disable-next-line no-console - console.warn(`unrecogized timeline event type: ${type}`); + console.warn(`unrecognized timeline event type: ${type}`); return null; } })} - {this.renderLoadMore(issueish)} + {this.renderLoadMore()}
    ); } - renderLoadMore(issueish) { + renderLoadMore() { if (!this.props.relay.hasMore()) { return null; } diff --git a/test/views/issueish-timeline-view.test.js b/test/views/issueish-timeline-view.test.js new file mode 100644 index 0000000000..d170e84173 --- /dev/null +++ b/test/views/issueish-timeline-view.test.js @@ -0,0 +1,186 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import IssueishTimelineView, {collectionRenderer} from '../../lib/views/issueish-timeline-view'; + +describe('IssueishTimelineView', function() { + function buildApp(opts, overloadProps = {}) { + const o = { + relayHasMore: () => false, + relayLoadMore: () => {}, + relayIsLoading: () => false, + useIssue: true, + timelineItemSpecs: [], + timelineStartCursor: 0, + ...opts, + }; + + if (o.timelineItemTotal === undefined) { + o.timelineItemTotal = o.timelineItemSpecs.length; + } + + const props = { + switchToIssueish: () => {}, + relay: { + hasMore: o.relayHasMore, + loadMore: o.relayLoadMore, + isLoading: o.relayIsLoading, + }, + ...overloadProps, + }; + + const timeline = { + edges: o.timelineItemSpecs.map((spec, i) => ({ + cursor: `result${i}`, + node: { + id: spec.id, + __typename: spec.kind, + }, + })), + pageInfo: { + startCursor: `result${o.timelineStartCursor}`, + endCursor: `result${o.timelineStartCursor + o.timelineItemSpecs.length}`, + hasNextPage: o.timelineStartCursor + o.timelineItemSpecs.length < o.timelineItemTotal, + hasPreviousPage: o.timelineStartCursor !== 0, + }, + totalCount: o.timelineItemTotal, + }; + + if (o.issueMode) { + props.issue = {timeline}; + } else { + props.pullRequest = {timeline}; + } + + return ; + } + + it('separates timeline issues by typename and renders a grouped child component for each', function() { + const wrapper = shallow(buildApp({ + timelineItemSpecs: [ + {kind: 'Commit', id: 0}, + {kind: 'Commit', id: 1}, + {kind: 'IssueComment', id: 2}, + {kind: 'MergedEvent', id: 3}, + {kind: 'Commit', id: 4}, + {kind: 'Commit', id: 5}, + {kind: 'Commit', id: 6}, + {kind: 'Commit', id: 7}, + {kind: 'IssueComment', id: 8}, + {kind: 'IssueComment', id: 9}, + ], + })); + + const commitGroup0 = wrapper.find('Relay(Commits)').filterWhere(c => c.prop('nodes').length === 2); + assert.deepEqual(commitGroup0.prop('nodes').map(n => n.id), [0, 1]); + + const commentGroup0 = wrapper.find('Grouped(Relay(IssueComment))').filterWhere(c => c.prop('nodes').length === 1); + assert.deepEqual(commentGroup0.prop('nodes').map(n => n.id), [2]); + + const mergedGroup = wrapper.find('Grouped(Relay(MergedEvent))').filterWhere(c => c.prop('nodes').length === 1); + assert.deepEqual(mergedGroup.prop('nodes').map(n => n.id), [3]); + + const commitGroup1 = wrapper.find('Relay(Commits)').filterWhere(c => c.prop('nodes').length === 4); + assert.deepEqual(commitGroup1.prop('nodes').map(n => n.id), [4, 5, 6, 7]); + + const commentGroup1 = wrapper.find('Grouped(Relay(IssueComment))').filterWhere(c => c.prop('nodes').length === 2); + assert.deepEqual(commentGroup1.prop('nodes').map(n => n.id), [8, 9]); + }); + + it('skips unrecognized timeline events', function() { + sinon.stub(console, 'warn'); + + const wrapper = shallow(buildApp({ + timelineItemSpecs: [ + {kind: 'Commit', id: 0}, + {kind: 'Commit', id: 1}, + {kind: 'FancyNewDotcomFeature', id: 2}, + {kind: 'IssueComment', id: 3}, + ], + })); + + assert.lengthOf(wrapper.find('.github-PrTimeline').children(), 2); + + // eslint-disable-next-line no-console + assert.isTrue(console.warn.calledWith('unrecognized timeline event type: FancyNewDotcomFeature')); + }); + + it('omits the load more link if there are no more events', function() { + const wrapper = shallow(buildApp({ + relayHasMore: () => false, + })); + assert.isFalse(wrapper.find('.github-PrTimeline-load-more-link').exists()); + }); + + it('renders a link to load more timeline events', function() { + const relayLoadMore = sinon.stub().callsArg(1); + const wrapper = shallow(buildApp({ + relayHasMore: () => true, + relayLoadMore, + relayIsLoading: () => false, + timelineItemSpecs: [ + {kind: 'Commit', id: 0}, + {kind: 'IssueComment', id: 1}, + ], + })); + + const link = wrapper.find('.github-PrTimeline-load-more-link'); + assert.strictEqual(link.text(), 'Load More'); + assert.isFalse(relayLoadMore.called); + link.simulate('click'); + assert.isTrue(relayLoadMore.called); + }); + + it('renders ellipses while loading', function() { + const wrapper = shallow(buildApp({ + relayHasMore: () => true, + relayIsLoading: () => true, + })); + + assert.isTrue(wrapper.find('Octicon[icon="ellipsis"]').exists()); + }); + + describe('collectionRenderer', function() { + class Item extends React.Component { + render() { + return {this.props.item}; + } + + static getFragment(fragName) { + return `item fragment for ${fragName}`; + } + } + + it('renders a child component for each node', function() { + const Component = collectionRenderer(Item, false); + const props = { + issueish: {}, + switchToIssueish: () => {}, + nodes: [1, 2, 3], + }; + const wrapper = shallow(); + + assert.isTrue(wrapper.find('Item').everyWhere(i => i.prop('issueish') === props.issueish)); + assert.isTrue(wrapper.find('Item').everyWhere(i => i.prop('switchToIssueish') === props.switchToIssueish)); + assert.deepEqual(wrapper.find('Item').map(i => i.prop('item')), [1, 2, 3]); + assert.isFalse(wrapper.find('.timeline-item').exists()); + }); + + it('optionally applies the timeline-item class', function() { + const Component = collectionRenderer(Item, true); + const props = { + issueish: {}, + switchToIssueish: () => {}, + nodes: [1, 2, 3], + }; + const wrapper = shallow(); + assert.isTrue(wrapper.find('.timeline-item').exists()); + }); + + it('translates the static getFragment call', function() { + const Component = collectionRenderer(Item); + assert.strictEqual(Component.getFragment('something'), 'item fragment for something'); + assert.strictEqual(Component.getFragment('nodes'), 'item fragment for item'); + }); + }); +}); From 7c73512b6639ff815539b592e66d1c3e4547f6ec Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Jun 2018 15:51:17 -0400 Subject: [PATCH 0411/4847] Convert IssueishBadge to a class component and test it --- lib/views/issueish-badge.js | 41 +++++++++++---------- test/views/issueish-badge.test.js | 60 +++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 test/views/issueish-badge.test.js diff --git a/lib/views/issueish-badge.js b/lib/views/issueish-badge.js index fe337b7988..610a202e15 100644 --- a/lib/views/issueish-badge.js +++ b/lib/views/issueish-badge.js @@ -16,24 +16,27 @@ const typeAndStateToIcon = { }, }; -export default function IssueishBadge({type, state, ...others}) { - const icons = typeAndStateToIcon[type] || {}; - const icon = icons[state] || ''; +export default class IssueishBadge extends React.Component { + static propTypes = { + type: PropTypes.oneOf([ + 'Issue', 'PullRequest', 'Unknown', + ]).isRequired, + state: PropTypes.oneOf([ + 'OPEN', 'CLOSED', 'MERGED', 'UNKNOWN', + ]).isRequired, + } - const {className, ...otherProps} = others; - return ( - - - {state.toLowerCase()} - - ); -} + render() { + const {type, state, ...others} = this.props; + const icons = typeAndStateToIcon[type] || {}; + const icon = icons[state] || 'question'; -IssueishBadge.propTypes = { - type: PropTypes.oneOf([ - 'Issue', 'PullRequest', - ]).isRequired, - state: PropTypes.oneOf([ - 'OPEN', 'CLOSED', 'MERGED', - ]).isRequired, -}; + const {className, ...otherProps} = others; + return ( + + + {state.toLowerCase()} + + ); + } +} diff --git a/test/views/issueish-badge.test.js b/test/views/issueish-badge.test.js new file mode 100644 index 0000000000..bdf9d358f3 --- /dev/null +++ b/test/views/issueish-badge.test.js @@ -0,0 +1,60 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import IssueishBadge from '../../lib/views/issueish-badge'; + +describe('IssueishBadge', function() { + function buildApp(overloadProps = {}) { + return ( + + ); + } + + it('applies a className and any other properties to the span', function() { + const extra = Symbol('extra'); + const wrapper = shallow(buildApp({ + className: 'added', + state: 'CLOSED', + extra, + })); + + const span = wrapper.find('span.github-IssueishBadge'); + assert.isTrue(span.hasClass('added')); + assert.isTrue(span.hasClass('closed')); + assert.strictEqual(span.prop('extra'), extra); + }); + + it('renders an appropriate icon', function() { + const wrapper = shallow(buildApp({type: 'Issue', state: 'OPEN'})); + assert.isTrue(wrapper.find('Octicon[icon="issue-opened"]').exists()); + assert.match(wrapper.text(), /open$/); + + wrapper.setProps({type: 'Issue', state: 'CLOSED'}); + assert.isTrue(wrapper.find('Octicon[icon="issue-closed"]').exists()); + assert.match(wrapper.text(), /closed$/); + + wrapper.setProps({type: 'PullRequest', state: 'OPEN'}); + assert.isTrue(wrapper.find('Octicon[icon="git-pull-request"]').exists()); + assert.match(wrapper.text(), /open$/); + + wrapper.setProps({type: 'PullRequest', state: 'CLOSED'}); + assert.isTrue(wrapper.find('Octicon[icon="git-pull-request"]').exists()); + assert.match(wrapper.text(), /closed$/); + + wrapper.setProps({type: 'PullRequest', state: 'MERGED'}); + assert.isTrue(wrapper.find('Octicon[icon="git-merge"]').exists()); + assert.match(wrapper.text(), /merged$/); + + wrapper.setProps({type: 'Unknown', state: 'OPEN'}); + assert.isTrue(wrapper.find('Octicon[icon="question"]').exists()); + assert.match(wrapper.text(), /open$/); + + wrapper.setProps({type: 'PullRequest', state: 'UNKNOWN'}); + assert.isTrue(wrapper.find('Octicon[icon="question"]').exists()); + assert.match(wrapper.text(), /unknown$/); + }); +}); From 337723a66a1d975f4702491060eb280119657314 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 28 Jun 2018 13:24:27 -0700 Subject: [PATCH 0412/4847] make `undoLastCommit` use `Author` type --- lib/controllers/git-tab-controller.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index 0d4344480a..ee2ebc0255 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -3,6 +3,7 @@ import path from 'path'; import React from 'react'; import PropTypes from 'prop-types'; +import Author from '../models/author'; import GitTabView from '../views/git-tab-view'; import UserStore from '../models/user-store'; import { @@ -268,7 +269,11 @@ export default class GitTabController extends React.Component { const lastCommit = await repo.getLastCommit(); if (lastCommit.isUnbornRef()) { return null; } repo.setCommitMessage(lastCommit.getFullMessage()); - this.updateSelectedCoAuthors(lastCommit.getCoAuthors()); + + const coAuthors = lastCommit.getCoAuthors().map(author => + new Author(author.name, author.email)); + + this.updateSelectedCoAuthors(coAuthors); return repo.undoLastCommit(); } From 815ac827097bb792074f46964c689ffe1f374880 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Jun 2018 16:27:33 -0400 Subject: [PATCH 0413/4847] Rename and test CommitCommentThreadView --- lib/views/issueish-timeline-view.js | 4 +- .../commit-comment-thread-view.js} | 8 +-- .../commit-comment-thread-results.js | 60 +++++++++++++++++++ .../commit-comment-thread-view.test.js | 35 +++++++++++ 4 files changed, 101 insertions(+), 6 deletions(-) rename lib/{containers/timeline-items/commit-comment-thread-container.js => views/timeline-items/commit-comment-thread-view.js} (79%) create mode 100644 test/fixtures/factories/commit-comment-thread-results.js create mode 100644 test/views/timeline-items/commit-comment-thread-view.test.js diff --git a/lib/views/issueish-timeline-view.js b/lib/views/issueish-timeline-view.js index a7e7d9d768..8ee8160cca 100644 --- a/lib/views/issueish-timeline-view.js +++ b/lib/views/issueish-timeline-view.js @@ -9,7 +9,7 @@ import IssueCommentContainer from './../containers/timeline-items/issue-comment- import MergedEventContainer from './../containers/timeline-items/merged-event-container.js'; import HeadRefForcePushedEventContainer from './../containers/timeline-items/head-ref-force-pushed-event-container.js'; import CrossReferencedEventsContainer from './../containers/timeline-items/cross-referenced-events-container.js'; -import CommitCommentThreadContainer from './../containers/timeline-items/commit-comment-thread-container'; +import CommitCommentThreadView from './../views/timeline-items/commit-comment-thread-view'; export function collectionRenderer(Component, styleAsTimelineItem = true) { return class GroupedComponent extends React.Component { @@ -50,7 +50,7 @@ export function collectionRenderer(Component, styleAsTimelineItem = true) { const timelineItems = { Commit: CommitsContainer, - CommitCommentThread: collectionRenderer(CommitCommentThreadContainer, false), + CommitCommentThread: collectionRenderer(CommitCommentThreadView, false), IssueComment: collectionRenderer(IssueCommentContainer, false), MergedEvent: collectionRenderer(MergedEventContainer), HeadRefForcePushedEvent: collectionRenderer(HeadRefForcePushedEventContainer), diff --git a/lib/containers/timeline-items/commit-comment-thread-container.js b/lib/views/timeline-items/commit-comment-thread-view.js similarity index 79% rename from lib/containers/timeline-items/commit-comment-thread-container.js rename to lib/views/timeline-items/commit-comment-thread-view.js index 935bf084b2..8d04be173f 100644 --- a/lib/containers/timeline-items/commit-comment-thread-container.js +++ b/lib/views/timeline-items/commit-comment-thread-view.js @@ -2,9 +2,9 @@ import React from 'react'; import {graphql, createFragmentContainer} from 'react-relay'; import PropTypes from 'prop-types'; -import CommitCommentContainer from './commit-comment-container'; +import CommitCommentContainer from '../../containers/timeline-items/commit-comment-container'; -export class CommitCommentThread extends React.Component { +export class BareCommitCommentThreadView extends React.Component { static propTypes = { item: PropTypes.shape({ commit: PropTypes.shape({ @@ -39,9 +39,9 @@ export class CommitCommentThread extends React.Component { } -export default createFragmentContainer(CommitCommentThread, { +export default createFragmentContainer(BareCommitCommentThreadView, { item: graphql` - fragment commitCommentThreadContainer_item on CommitCommentThread { + fragment commitCommentThreadView_item on CommitCommentThread { commit { oid } comments(first: 100) { edges { diff --git a/test/fixtures/factories/commit-comment-thread-results.js b/test/fixtures/factories/commit-comment-thread-results.js new file mode 100644 index 0000000000..24eb98c705 --- /dev/null +++ b/test/fixtures/factories/commit-comment-thread-results.js @@ -0,0 +1,60 @@ +import IDGenerator from './id-generator'; + +export function createCommitComment(opts = {}) { + const idGen = IDGenerator.fromOpts(opts); + + const o = { + id: idGen.generate('comment-comment'), + commitOid: '1234abcd', + authorLogin: 'author0', + authorAvatar: 'https://avatars2.githubusercontent.com/u/0?v=12', + bodyHTML: '

    body

    ', + createdAt: '2018-06-28T15:04:05Z', + commentPath: null, + ...opts, + }; + + return { + id: o.id, + author: { + __typename: 'User', + id: idGen.generate('user'), + login: o.authorLogin, + avatarUrl: o.authorAvatar, + }, + commit: { + oid: o.commitOid, + }, + bodyHtml: o.bodyHtml, + createdAt: o.createdAt, + path: o.commentPath, + }; +} + +export function createCommitCommentThread(opts = {}) { + const idGen = IDGenerator.fromOpts(opts); + + const o = { + id: idGen.generate('commit-comment-thread'), + commitOid: '1234abcd', + commitCommentOpts: [], + ...opts, + }; + + return { + id: o.id, + commit: { + oid: o.commitOid, + }, + comments: { + edges: o.commitCommentOpts.map(eachOpts => { + return { + node: createCommitComment({ + ...idGen.embed(), + ...eachOpts, + }), + } + }), + }, + }; +} diff --git a/test/views/timeline-items/commit-comment-thread-view.test.js b/test/views/timeline-items/commit-comment-thread-view.test.js new file mode 100644 index 0000000000..7e75e24ab9 --- /dev/null +++ b/test/views/timeline-items/commit-comment-thread-view.test.js @@ -0,0 +1,35 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BareCommitCommentThreadView} from '../../../lib/views/timeline-items/commit-comment-thread-view'; +import {createCommitCommentThread} from '../../fixtures/factories/commit-comment-thread-results'; + +describe('CommitCommentThreadView', function() { + function buildApp(opts, overloadProps = {}) { + const props = { + item: createCommitCommentThread(opts), + switchToIssueish: () => {}, + ...overloadProps, + }; + + return ; + } + + it('renders a CommitCommentView for each comment', function() { + const wrapper = shallow(buildApp({ + commitCommentOpts: [ + {authorLogin: 'user0'}, + {authorLogin: 'user1'}, + {authorLogin: 'user2'}, + ], + })); + + const commentViews = wrapper.find('Relay(CommitComment)'); + + assert.deepEqual(commentViews.map(c => c.prop('item').author.login), ['user0', 'user1', 'user2']); + + assert.isFalse(commentViews.at(0).prop('isReply')); + assert.isTrue(commentViews.at(1).prop('isReply')); + assert.isTrue(commentViews.at(2).prop('isReply')); + }); +}); From f68cf09cb6c700a76a06ad812210489140f82b2a Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 28 Jun 2018 13:36:52 -0700 Subject: [PATCH 0414/4847] fix unit test to check for author prop. --- package-lock.json | 3375 ++++++++++--------- test/controllers/git-tab-controller.test.js | 9 +- 2 files changed, 1693 insertions(+), 1691 deletions(-) diff --git a/package-lock.json b/package-lock.json index 43f90a9cb5..457e792282 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,10 +26,10 @@ "dev": true, "requires": { "@babel/types": "7.0.0-beta.44", - "jsesc": "^2.5.1", - "lodash": "^4.2.0", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "jsesc": "2.5.1", + "lodash": "4.17.5", + "source-map": "0.5.7", + "trim-right": "1.0.1" }, "dependencies": { "jsesc": { @@ -87,9 +87,9 @@ "integrity": "sha1-GMlM5UORaoBVPtzc9oGJCyAHR9U=", "dev": true, "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^3.0.0" + "chalk": "2.4.1", + "esutils": "2.0.2", + "js-tokens": "3.0.2" }, "dependencies": { "ansi-styles": { @@ -98,7 +98,7 @@ "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.1" } }, "chalk": { @@ -107,9 +107,9 @@ "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "escape-string-regexp": { @@ -130,7 +130,7 @@ "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -150,7 +150,7 @@ "@babel/code-frame": "7.0.0-beta.44", "@babel/types": "7.0.0-beta.44", "babylon": "7.0.0-beta.44", - "lodash": "^4.2.0" + "lodash": "4.17.5" }, "dependencies": { "babylon": { @@ -173,10 +173,10 @@ "@babel/helper-split-export-declaration": "7.0.0-beta.44", "@babel/types": "7.0.0-beta.44", "babylon": "7.0.0-beta.44", - "debug": "^3.1.0", - "globals": "^11.1.0", - "invariant": "^2.2.0", - "lodash": "^4.2.0" + "debug": "3.1.0", + "globals": "11.5.0", + "invariant": "2.2.4", + "lodash": "4.17.5" }, "dependencies": { "babylon": { @@ -206,7 +206,7 @@ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, "requires": { - "loose-envify": "^1.0.0" + "loose-envify": "1.3.1" } }, "loose-envify": { @@ -215,7 +215,7 @@ "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "dev": true, "requires": { - "js-tokens": "^3.0.0" + "js-tokens": "3.0.2" } } } @@ -226,9 +226,9 @@ "integrity": "sha1-axsWRZH3fewKA0KsqZXy0Eazp1c=", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.2.0", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "2.0.0" }, "dependencies": { "esutils": { @@ -248,17 +248,17 @@ "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "dev": true, "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" + "call-me-maybe": "1.0.1", + "glob-to-regexp": "0.3.0" } }, "@sinonjs/formatio": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", - "integrity": "sha1-hNt+nrVTHfGKjF4L+25EnlXmVLI=", + "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", "dev": true, "requires": { "samsam": "1.3.0" @@ -267,27 +267,27 @@ "@smashwilson/enzyme-adapter-react-16": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@smashwilson/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.2.tgz", - "integrity": "sha1-8NRWRn/qp5AwV8vF5PqsZKWoBsg=", + "integrity": "sha512-YGotyPAPOwi9vbRzvTutDgqYbBo5gX8mELNHPICcAXilV9XMa0yxqCQ6OY4ItIO5dPiRkc9RkjSYBr2M1fFOZw==", "dev": true, "requires": { - "@smashwilson/enzyme-adapter-utils": "^1.0.0", - "lodash": "^4.17.4", - "object.assign": "^4.1.0", - "object.values": "^1.0.4", - "prop-types": "^15.6.0", - "react-reconciler": "^0.7.0", - "react-test-renderer": "^16.0.0-0" + "@smashwilson/enzyme-adapter-utils": "1.0.0", + "lodash": "4.17.5", + "object.assign": "4.1.0", + "object.values": "1.0.4", + "prop-types": "15.6.2", + "react-reconciler": "0.7.0", + "react-test-renderer": "16.4.1" } }, "@smashwilson/enzyme-adapter-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@smashwilson/enzyme-adapter-utils/-/enzyme-adapter-utils-1.0.0.tgz", - "integrity": "sha1-H5zSVcvNm1Fd8WkCGgLbEMX8Ydc=", + "integrity": "sha512-/kQoTFU5bdbZbh6C9Ohxz1BgoHW+n2BX/kGUcS3DucGZfVNl4Em9lJqzd3aelyZSJz+cRX/FuE6ccnO6MnZc0Q==", "dev": true, "requires": { - "lodash": "^4.17.4", - "object.assign": "^4.1.0", - "prop-types": "^15.6.0" + "lodash": "4.17.5", + "object.assign": "4.1.0", + "prop-types": "15.6.2" } }, "@types/node": { @@ -308,7 +308,7 @@ "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "acorn": "^3.0.4" + "acorn": "3.3.0" }, "dependencies": { "acorn": { @@ -324,10 +324,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" } }, "ajv-keywords": { @@ -339,7 +339,7 @@ "ansi-escapes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha1-9zIHu4EgfXX9bIPxJa8m7qN4yjA=", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", "dev": true }, "ansi-regex": { @@ -364,17 +364,17 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "delegates": "1.0.0", + "readable-stream": "2.3.3" } }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "sprintf-js": "1.0.3" } }, "arr-diff": { @@ -401,7 +401,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "^1.0.1" + "array-uniq": "1.0.3" } }, "array-uniq": { @@ -422,8 +422,8 @@ "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" + "define-properties": "1.1.2", + "es-abstract": "1.11.0" } }, "arrify": { @@ -475,7 +475,7 @@ "resolved": "https://registry.npmjs.org/atom-babel6-transpiler/-/atom-babel6-transpiler-1.2.0.tgz", "integrity": "sha512-lZucrjVyRtPAPPJxvICCEBsAC1qn48wUHaIlieriWCXTXLqtLC2PvkQU7vNvU2w1eZ7tw9m0lojZ8PbpVyWTvg==", "requires": { - "babel-core": "6.x" + "babel-core": "6.26.3" } }, "atom-mocha-test-runner": { @@ -484,10 +484,10 @@ "integrity": "sha1-qPZQm40pqAn8tv9H8FiEthLNxqk=", "dev": true, "requires": { - "etch": "^0.8.0", - "grim": "^2.0.1", - "less": "^2.7.1", - "mocha": "^3.0.0", + "etch": "0.8.0", + "grim": "2.0.2", + "less": "2.7.3", + "mocha": "3.5.3", "tmp": "0.0.31" }, "dependencies": { @@ -503,7 +503,7 @@ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", "dev": true, "requires": { - "graceful-readlink": ">= 1.0.0" + "graceful-readlink": "1.0.1" } }, "debug": { @@ -527,7 +527,7 @@ "integrity": "sha1-VPYZV0NG+KPueXP1T7vQG1YnItY=", "dev": true, "requires": { - "virtual-dom": "^2.0.1" + "virtual-dom": "2.1.1" } }, "fs.realpath": { @@ -542,12 +542,12 @@ "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.2", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "grim": { @@ -556,7 +556,7 @@ "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==", "dev": true, "requires": { - "event-kit": "^2.0.0" + "event-kit": "2.5.0" } }, "growl": { @@ -577,8 +577,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -593,7 +593,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.8" } }, "mocha": { @@ -630,7 +630,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "path-is-absolute": { @@ -645,7 +645,7 @@ "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", "dev": true, "requires": { - "has-flag": "^1.0.0" + "has-flag": "1.0.0" } }, "wrappy": { @@ -671,9 +671,9 @@ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" }, "dependencies": { "ansi-regex": { @@ -691,11 +691,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "escape-string-regexp": { @@ -713,7 +713,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "strip-ansi": { @@ -721,7 +721,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "supports-color": { @@ -736,25 +736,25 @@ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", "integrity": "sha1-suLwnjQtDwyI4vAuBneUEl51wgc=", "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.1", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.5.1", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.5", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" }, "dependencies": { "babel-runtime": { @@ -762,8 +762,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-template": { @@ -771,11 +771,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.5" } }, "babel-traverse": { @@ -783,15 +783,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.5" } }, "babel-types": { @@ -799,10 +799,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "babylon": { @@ -832,8 +832,8 @@ "@babel/traverse": "7.0.0-beta.44", "@babel/types": "7.0.0-beta.44", "babylon": "7.0.0-beta.44", - "eslint-scope": "~3.7.1", - "eslint-visitor-keys": "^1.0.0" + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0" }, "dependencies": { "babylon": { @@ -849,14 +849,14 @@ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", "integrity": "sha1-GERAjTuPDTWkBOp6wYDwh6YBvZA=", "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.5", + "source-map": "0.5.7", + "trim-right": "1.0.1" }, "dependencies": { "babel-messages": { @@ -864,7 +864,7 @@ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.26.0" } }, "babel-runtime": { @@ -872,8 +872,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-types": { @@ -881,10 +881,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "esutils": { @@ -919,9 +919,9 @@ "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "esutils": "^2.0.2" + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "esutils": "2.0.2" }, "dependencies": { "babel-runtime": { @@ -929,8 +929,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-types": { @@ -938,10 +938,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "esutils": { @@ -967,10 +967,10 @@ "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", "dev": true, "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helper-define-map": { @@ -979,10 +979,10 @@ "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.5" }, "dependencies": { "babel-runtime": { @@ -991,8 +991,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-types": { @@ -1001,16 +1001,16 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true }, "to-fast-properties": { @@ -1027,11 +1027,11 @@ "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", "dev": true, "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helper-get-function-arity": { @@ -1040,8 +1040,8 @@ "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helper-hoist-variables": { @@ -1050,8 +1050,8 @@ "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helper-optimise-call-expression": { @@ -1060,8 +1060,8 @@ "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helper-replace-supers": { @@ -1070,12 +1070,12 @@ "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", "dev": true, "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helpers": { @@ -1083,8 +1083,8 @@ "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-template": "6.25.0" } }, "babel-messages": { @@ -1092,7 +1092,7 @@ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-chai-assert-async": { @@ -1106,7 +1106,7 @@ "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-istanbul": { @@ -1115,10 +1115,10 @@ "integrity": "sha1-NsWbIZLvzoHFs3gyG3QXWt0cmkU=", "dev": true, "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.13.0", - "find-up": "^2.1.0", - "istanbul-lib-instrument": "^1.10.1", - "test-exclude": "^4.2.1" + "babel-plugin-syntax-object-rest-spread": "6.13.0", + "find-up": "2.1.0", + "istanbul-lib-instrument": "1.10.1", + "test-exclude": "4.2.1" }, "dependencies": { "babylon": { @@ -1139,13 +1139,13 @@ "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", "dev": true, "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.0", - "semver": "^5.3.0" + "babel-generator": "6.26.1", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.18.0", + "istanbul-lib-coverage": "1.2.0", + "semver": "5.4.1" } } } @@ -1155,8 +1155,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-relay/-/babel-plugin-relay-1.6.0.tgz", "integrity": "sha1-oiTaUkNi1pA6UkIUobhAUw/fvSg=", "requires": { - "babel-runtime": "^6.23.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-plugin-syntax-class-properties": { @@ -1190,10 +1190,10 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-plugin-syntax-class-properties": "^6.8.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "babel-helper-function-name": "6.24.1", + "babel-plugin-syntax-class-properties": "6.13.0", + "babel-runtime": "6.25.0", + "babel-template": "6.25.0" }, "dependencies": { "babel-helper-function-name": { @@ -1201,11 +1201,11 @@ "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helper-get-function-arity": { @@ -1213,8 +1213,8 @@ "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } } } @@ -1225,7 +1225,7 @@ "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-block-scoped-functions": { @@ -1234,7 +1234,7 @@ "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-block-scoping": { @@ -1243,11 +1243,11 @@ "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.5" }, "dependencies": { "babel-runtime": { @@ -1256,8 +1256,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-template": { @@ -1266,11 +1266,11 @@ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.5" } }, "babel-traverse": { @@ -1279,15 +1279,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.5" } }, "babel-types": { @@ -1296,22 +1296,22 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "dev": true }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true }, "to-fast-properties": { @@ -1328,15 +1328,15 @@ "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", "dev": true, "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "babel-helper-define-map": "6.26.0", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" } }, "babel-plugin-transform-es2015-computed-properties": { @@ -1345,8 +1345,8 @@ "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-template": "6.25.0" } }, "babel-plugin-transform-es2015-destructuring": { @@ -1355,7 +1355,7 @@ "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-for-of": { @@ -1364,7 +1364,7 @@ "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-function-name": { @@ -1373,9 +1373,9 @@ "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-plugin-transform-es2015-literals": { @@ -1384,7 +1384,7 @@ "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-modules-commonjs": { @@ -1392,10 +1392,10 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", "integrity": "sha1-WKeThjqefKhwvcWogRF/+sJ9tvM=", "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" }, "dependencies": { "ansi-regex": { @@ -1413,9 +1413,9 @@ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" } }, "babel-messages": { @@ -1423,7 +1423,7 @@ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.26.0" } }, "babel-runtime": { @@ -1431,8 +1431,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-template": { @@ -1440,11 +1440,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.5" } }, "babel-traverse": { @@ -1452,15 +1452,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.5" } }, "babel-types": { @@ -1468,10 +1468,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "babylon": { @@ -1484,11 +1484,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "escape-string-regexp": { @@ -1506,7 +1506,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "regenerator-runtime": { @@ -1519,7 +1519,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "supports-color": { @@ -1540,8 +1540,8 @@ "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", "dev": true, "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-parameters": { @@ -1550,12 +1550,12 @@ "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", "dev": true, "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" } }, "babel-plugin-transform-es2015-shorthand-properties": { @@ -1564,8 +1564,8 @@ "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-plugin-transform-es2015-spread": { @@ -1574,7 +1574,7 @@ "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-template-literals": { @@ -1583,7 +1583,7 @@ "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es3-member-expression-literals": { @@ -1592,7 +1592,7 @@ "integrity": "sha1-cz00RPPsxBvvjtGmpOCWV7iWnrs=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es3-property-literals": { @@ -1601,7 +1601,7 @@ "integrity": "sha1-sgeNWELiKr9A9z6M3pzTcRq9V1g=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-flow-strip-types": { @@ -1609,8 +1609,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", "requires": { - "babel-plugin-syntax-flow": "^6.18.0", - "babel-runtime": "^6.22.0" + "babel-plugin-syntax-flow": "6.18.0", + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-object-rest-spread": { @@ -1618,8 +1618,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" + "babel-plugin-syntax-object-rest-spread": "6.13.0", + "babel-runtime": "6.26.0" }, "dependencies": { "babel-runtime": { @@ -1627,8 +1627,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "regenerator-runtime": { @@ -1643,7 +1643,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=", "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-react-jsx": { @@ -1651,9 +1651,9 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", "requires": { - "babel-helper-builder-react-jsx": "^6.24.1", - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" + "babel-helper-builder-react-jsx": "6.26.0", + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-react-jsx-self": { @@ -1661,8 +1661,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz", "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=", "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-react-jsx-source": { @@ -1670,8 +1670,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz", "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=", "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-strict-mode": { @@ -1679,8 +1679,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-polyfill": { @@ -1689,9 +1689,9 @@ "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "regenerator-runtime": "^0.10.5" + "babel-runtime": "6.26.0", + "core-js": "2.5.0", + "regenerator-runtime": "0.10.5" }, "dependencies": { "babel-runtime": { @@ -1700,14 +1700,14 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" }, "dependencies": { "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true } } @@ -1720,34 +1720,34 @@ "integrity": "sha1-IvNY5mVAc6z2HkegUqd317zPA68=", "dev": true, "requires": { - "babel-plugin-check-es2015-constants": "^6.8.0", - "babel-plugin-syntax-class-properties": "^6.8.0", - "babel-plugin-syntax-flow": "^6.8.0", - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-plugin-syntax-trailing-function-commas": "^6.8.0", - "babel-plugin-transform-class-properties": "^6.8.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.8.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.8.0", - "babel-plugin-transform-es2015-block-scoping": "^6.8.0", - "babel-plugin-transform-es2015-classes": "^6.8.0", - "babel-plugin-transform-es2015-computed-properties": "^6.8.0", - "babel-plugin-transform-es2015-destructuring": "^6.8.0", - "babel-plugin-transform-es2015-for-of": "^6.8.0", - "babel-plugin-transform-es2015-function-name": "^6.8.0", - "babel-plugin-transform-es2015-literals": "^6.8.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.8.0", - "babel-plugin-transform-es2015-object-super": "^6.8.0", - "babel-plugin-transform-es2015-parameters": "^6.8.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.8.0", - "babel-plugin-transform-es2015-spread": "^6.8.0", - "babel-plugin-transform-es2015-template-literals": "^6.8.0", - "babel-plugin-transform-es3-member-expression-literals": "^6.8.0", - "babel-plugin-transform-es3-property-literals": "^6.8.0", - "babel-plugin-transform-flow-strip-types": "^6.8.0", - "babel-plugin-transform-object-rest-spread": "^6.8.0", - "babel-plugin-transform-react-display-name": "^6.8.0", - "babel-plugin-transform-react-jsx": "^6.8.0" + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-syntax-class-properties": "6.13.0", + "babel-plugin-syntax-flow": "6.18.0", + "babel-plugin-syntax-jsx": "6.18.0", + "babel-plugin-syntax-object-rest-spread": "6.13.0", + "babel-plugin-syntax-trailing-function-commas": "6.22.0", + "babel-plugin-transform-class-properties": "6.24.1", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.26.0", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es3-member-expression-literals": "6.22.0", + "babel-plugin-transform-es3-property-literals": "6.22.0", + "babel-plugin-transform-flow-strip-types": "6.22.0", + "babel-plugin-transform-object-rest-spread": "6.26.0", + "babel-plugin-transform-react-display-name": "6.25.0", + "babel-plugin-transform-react-jsx": "6.24.1" } }, "babel-preset-flow": { @@ -1755,7 +1755,7 @@ "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=", "requires": { - "babel-plugin-transform-flow-strip-types": "^6.22.0" + "babel-plugin-transform-flow-strip-types": "6.22.0" } }, "babel-preset-react": { @@ -1763,12 +1763,12 @@ "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", "requires": { - "babel-plugin-syntax-jsx": "^6.3.13", - "babel-plugin-transform-react-display-name": "^6.23.0", - "babel-plugin-transform-react-jsx": "^6.24.1", - "babel-plugin-transform-react-jsx-self": "^6.22.0", - "babel-plugin-transform-react-jsx-source": "^6.22.0", - "babel-preset-flow": "^6.23.0" + "babel-plugin-syntax-jsx": "6.18.0", + "babel-plugin-transform-react-display-name": "6.25.0", + "babel-plugin-transform-react-jsx": "6.24.1", + "babel-plugin-transform-react-jsx-self": "6.22.0", + "babel-plugin-transform-react-jsx-source": "6.22.0", + "babel-preset-flow": "6.23.0" } }, "babel-register": { @@ -1776,13 +1776,13 @@ "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" + "babel-core": "6.26.3", + "babel-runtime": "6.26.0", + "core-js": "2.5.0", + "home-or-tmp": "2.0.0", + "lodash": "4.17.5", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" }, "dependencies": { "babel-runtime": { @@ -1790,8 +1790,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "regenerator-runtime": { @@ -1806,8 +1806,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.25.0.tgz", "integrity": "sha1-M7mOql1IK7AajRqmtDetKwGuxBw=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.10.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.10.5" } }, "babel-template": { @@ -1815,11 +1815,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.25.0", - "babel-types": "^6.25.0", - "babylon": "^6.17.2", - "lodash": "^4.2.0" + "babel-runtime": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "lodash": "4.17.5" } }, "babel-traverse": { @@ -1827,15 +1827,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", "requires": { - "babel-code-frame": "^6.22.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-types": "^6.25.0", - "babylon": "^6.17.2", - "debug": "^2.2.0", - "globals": "^9.0.0", - "invariant": "^2.2.0", - "lodash": "^4.2.0" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.5" }, "dependencies": { "babel-messages": { @@ -1843,7 +1843,7 @@ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } } } @@ -1853,10 +1853,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", "requires": { - "babel-runtime": "^6.22.0", - "esutils": "^2.0.2", - "lodash": "^4.2.0", - "to-fast-properties": "^1.0.1" + "babel-runtime": "6.25.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" }, "dependencies": { "esutils": { @@ -1887,13 +1887,13 @@ "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", "dev": true, "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" }, "dependencies": { "define-property": { @@ -1902,36 +1902,36 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -1942,7 +1942,7 @@ "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "optional": true, "requires": { - "tweetnacl": "^0.14.3" + "tweetnacl": "0.14.5" } }, "bl": { @@ -1950,8 +1950,8 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha1-oWCRFxcQPAdBDO9j71Gzl8Alr5w=", "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "readable-stream": "2.3.6", + "safe-buffer": "5.1.1" }, "dependencies": { "core-util-is": { @@ -1979,13 +1979,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -1993,7 +1993,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "util-deprecate": { @@ -2015,7 +2015,7 @@ "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", "dev": true, "requires": { - "hoek": "4.x.x" + "hoek": "4.2.1" } }, "brace-expansion": { @@ -2023,26 +2023,26 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.2", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -2051,7 +2051,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -2068,7 +2068,7 @@ "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", "dev": true, "requires": { - "node-int64": "^0.4.0" + "node-int64": "0.4.0" } }, "buffer-alloc": { @@ -2076,8 +2076,8 @@ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.1.0.tgz", "integrity": "sha1-BVFNM78WVtNUDGhPZbEgLpDsowM=", "requires": { - "buffer-alloc-unsafe": "^0.1.0", - "buffer-fill": "^0.1.0" + "buffer-alloc-unsafe": "0.1.1", + "buffer-fill": "0.1.1" } }, "buffer-alloc-unsafe": { @@ -2113,15 +2113,15 @@ "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", "dev": true, "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" } }, "call-me-maybe": { @@ -2136,7 +2136,7 @@ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "^0.2.0" + "callsites": "0.2.0" } }, "callsites": { @@ -2168,12 +2168,12 @@ "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", "dev": true, "requires": { - "assertion-error": "^1.0.1", - "check-error": "^1.0.1", - "deep-eql": "^3.0.0", - "get-func-name": "^2.0.0", - "pathval": "^1.0.0", - "type-detect": "^4.0.0" + "assertion-error": "1.1.0", + "check-error": "1.0.2", + "deep-eql": "3.0.1", + "get-func-name": "2.0.0", + "pathval": "1.1.0", + "type-detect": "4.0.8" } }, "chai-as-promised": { @@ -2182,7 +2182,7 @@ "integrity": "sha1-CGRdgl3rhpbuYXJdv1kMAS6wDKA=", "dev": true, "requires": { - "check-error": "^1.0.2" + "check-error": "1.0.2" } }, "chalk": { @@ -2191,11 +2191,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "chardet": { @@ -2215,7 +2215,7 @@ "resolved": "https://registry.npmjs.org/checksum/-/checksum-0.1.1.tgz", "integrity": "sha1-3GUn1MkL6FYNvR7Uzs8yl9Uo6ek=", "requires": { - "optimist": "~0.3.5" + "optimist": "0.3.7" } }, "cheerio": { @@ -2224,12 +2224,12 @@ "integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=", "dev": true, "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash": "^4.15.0", - "parse5": "^3.0.1" + "css-select": "1.2.0", + "dom-serializer": "0.1.0", + "entities": "1.1.1", + "htmlparser2": "3.9.2", + "lodash": "4.17.5", + "parse5": "3.0.3" } }, "chownr": { @@ -2249,10 +2249,10 @@ "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", "dev": true, "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" }, "dependencies": { "define-property": { @@ -2261,7 +2261,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -2269,7 +2269,7 @@ "classnames": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha1-Q5Nb/90pHzJtrQogUwmzjQD2UM4=" + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" }, "cli-cursor": { "version": "2.1.0", @@ -2277,7 +2277,7 @@ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "restore-cursor": "^2.0.0" + "restore-cursor": "2.0.0" } }, "cli-width": { @@ -2292,9 +2292,9 @@ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" }, "dependencies": { "string-width": { @@ -2303,9 +2303,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } } } @@ -2326,8 +2326,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "map-visit": "1.0.0", + "object-visit": "1.0.1" } }, "color-convert": { @@ -2336,7 +2336,7 @@ "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=", "dev": true, "requires": { - "color-name": "^1.1.1" + "color-name": "1.1.3" } }, "color-name": { @@ -2356,7 +2356,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } }, "compare-sets": { @@ -2381,10 +2381,10 @@ "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", "dev": true, "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "buffer-from": "1.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" }, "dependencies": { "inherits": { @@ -2422,11 +2422,11 @@ "integrity": "sha1-EuFZFOqikgTlaGml7Oe54UktKuI=", "dev": true, "requires": { - "js-yaml": "^3.6.1", - "lcov-parse": "^0.0.10", - "log-driver": "^1.2.5", - "minimist": "^1.2.0", - "request": "^2.79.0" + "js-yaml": "3.11.0", + "lcov-parse": "0.0.10", + "log-driver": "1.2.7", + "minimist": "1.2.0", + "request": "2.87.0" } }, "cross-spawn": { @@ -2435,9 +2435,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "lru-cache": "4.1.2", + "shebang-command": "1.2.0", + "which": "1.3.0" }, "dependencies": { "lru-cache": { @@ -2446,8 +2446,8 @@ "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", "dev": true, "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "pseudomap": "1.0.2", + "yallist": "2.1.2" } }, "yallist": { @@ -2470,7 +2470,7 @@ "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", "dev": true, "requires": { - "boom": "5.x.x" + "boom": "5.2.0" }, "dependencies": { "boom": { @@ -2479,7 +2479,7 @@ "integrity": "sha1-XdnabuOl8wIHdDYpDLcX0/SlTgI=", "dev": true, "requires": { - "hoek": "4.x.x" + "hoek": "4.2.1" } } } @@ -2490,10 +2490,10 @@ "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "dev": true, "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", + "boolbase": "1.0.0", + "css-what": "2.1.0", "domutils": "1.5.1", - "nth-check": "~1.0.1" + "nth-check": "1.0.1" } }, "css-what": { @@ -2507,7 +2507,7 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "debug": { @@ -2535,7 +2535,7 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "requires": { - "mimic-response": "^1.0.0" + "mimic-response": "1.0.0" } }, "dedent-js": { @@ -2550,7 +2550,7 @@ "integrity": "sha1-38lARACtHI/gI+faHfHBR8S0RN8=", "dev": true, "requires": { - "type-detect": "^4.0.0" + "type-detect": "4.0.8" } }, "deep-extend": { @@ -2570,8 +2570,8 @@ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", "dev": true, "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" + "foreach": "2.0.5", + "object-keys": "1.0.11" } }, "define-property": { @@ -2580,37 +2580,37 @@ "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "is-descriptor": "1.0.2", + "isobject": "3.0.1" }, "dependencies": { "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -2621,13 +2621,13 @@ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" }, "dependencies": { "object-assign": { @@ -2654,7 +2654,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "^2.0.0" + "pinkie": "2.0.4" } }, "rimraf": { @@ -2663,7 +2663,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "7.1.2" } } } @@ -2683,7 +2683,7 @@ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "requires": { - "repeating": "^2.0.0" + "repeating": "2.0.1" } }, "detect-libc": { @@ -2709,8 +2709,8 @@ "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "esutils": "2.0.2", + "isarray": "1.0.0" }, "dependencies": { "esutils": { @@ -2733,8 +2733,8 @@ "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "dev": true, "requires": { - "domelementtype": "~1.1.1", - "entities": "~1.1.1" + "domelementtype": "1.1.3", + "entities": "1.1.1" }, "dependencies": { "domelementtype": { @@ -2763,7 +2763,7 @@ "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", "dev": true, "requires": { - "domelementtype": "1" + "domelementtype": "1.3.0" } }, "domutils": { @@ -2772,8 +2772,8 @@ "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "dev": true, "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "dom-serializer": "0.1.0", + "domelementtype": "1.3.0" } }, "dugite": { @@ -2781,12 +2781,12 @@ "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.66.0.tgz", "integrity": "sha1-X9q2aDwLU4p5vb7Emenz0+pyEPk=", "requires": { - "checksum": "^0.1.1", - "mkdirp": "^0.5.1", - "progress": "^2.0.0", - "request": "^2.86.0", - "rimraf": "^2.5.4", - "tar": "^4.0.2" + "checksum": "0.1.1", + "mkdirp": "0.5.1", + "progress": "2.0.0", + "request": "2.87.0", + "rimraf": "2.6.2", + "tar": "4.4.4" } }, "ecc-jsbn": { @@ -2795,19 +2795,19 @@ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "optional": true, "requires": { - "jsbn": "~0.1.0" + "jsbn": "0.1.1" } }, "electron-devtools-installer": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-2.2.4.tgz", - "integrity": "sha1-JhpQM343Eh0zi5ZvB5IutJOah2M=", + "integrity": "sha512-b5kcM3hmUqn64+RUcHjjr8ZMpHS2WJ5YO0pnG9+P/RTdx46of/JrEjuciHWux6pE+On6ynWhHJF53j/EDJN0PA==", "dev": true, "requires": { "7zip": "0.0.6", "cross-unzip": "0.0.2", - "rimraf": "^2.5.2", - "semver": "^5.3.0" + "rimraf": "2.6.2", + "semver": "5.4.1" } }, "encoding": { @@ -2815,7 +2815,7 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "requires": { - "iconv-lite": "~0.4.13" + "iconv-lite": "0.4.18" } }, "end-of-stream": { @@ -2823,7 +2823,7 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", "requires": { - "once": "^1.4.0" + "once": "1.4.0" }, "dependencies": { "once": { @@ -2831,7 +2831,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "wrappy": { @@ -2853,22 +2853,22 @@ "integrity": "sha1-CXGr0Wfy1L8/W9UIIp4cS23FBHk=", "dev": true, "requires": { - "cheerio": "^1.0.0-rc.2", - "function.prototype.name": "^1.0.3", - "has": "^1.0.1", - "is-boolean-object": "^1.0.0", - "is-callable": "^1.1.3", - "is-number-object": "^1.0.3", - "is-string": "^1.0.4", - "is-subset": "^0.1.1", - "lodash": "^4.17.4", - "object-inspect": "^1.5.0", - "object-is": "^1.0.1", - "object.assign": "^4.1.0", - "object.entries": "^1.0.4", - "object.values": "^1.0.4", - "raf": "^3.4.0", - "rst-selector-parser": "^2.2.3" + "cheerio": "1.0.0-rc.2", + "function.prototype.name": "1.1.0", + "has": "1.0.1", + "is-boolean-object": "1.0.0", + "is-callable": "1.1.3", + "is-number-object": "1.0.3", + "is-string": "1.0.4", + "is-subset": "0.1.1", + "lodash": "4.17.5", + "object-inspect": "1.5.0", + "object-is": "1.0.1", + "object.assign": "4.1.0", + "object.entries": "1.0.4", + "object.values": "1.0.4", + "raf": "3.4.0", + "rst-selector-parser": "2.2.3" } }, "errno": { @@ -2878,7 +2878,7 @@ "dev": true, "optional": true, "requires": { - "prr": "~0.0.0" + "prr": "0.0.0" } }, "error": { @@ -2887,9 +2887,9 @@ "integrity": "sha1-v2n/JR+0onnBmtzNqmth6Q2b8So=", "dev": true, "requires": { - "camelize": "^1.0.0", - "string-template": "~0.2.0", - "xtend": "~4.0.0" + "camelize": "1.0.0", + "string-template": "0.2.1", + "xtend": "4.0.1" } }, "error-ex": { @@ -2898,7 +2898,7 @@ "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { - "is-arrayish": "^0.2.1" + "is-arrayish": "0.2.1" } }, "es-abstract": { @@ -2907,11 +2907,11 @@ "integrity": "sha1-zOh9UY8Elok7GjDNhGGDVTVIBoE=", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", - "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "es-to-primitive": "1.1.1", + "function-bind": "1.1.1", + "has": "1.0.1", + "is-callable": "1.1.3", + "is-regex": "1.0.4" }, "dependencies": { "function-bind": { @@ -2928,9 +2928,9 @@ "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", "dev": true, "requires": { - "is-callable": "^1.1.1", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.1" + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" } }, "escape-string-regexp": { @@ -2942,47 +2942,47 @@ "eslint": { "version": "4.19.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha1-MtHWU+HZBAiFS/spbwdux+GGowA=", - "dev": true, - "requires": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", - "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.4", - "esquery": "^1.0.0", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^1.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.3.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "dev": true, + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "concat-stream": "1.6.2", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.5.0", + "ignore": "3.3.8", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.11.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.5", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.4.1", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", "table": "4.0.2", - "text-table": "~0.2.0" + "text-table": "0.2.0" }, "dependencies": { "ansi-regex": { @@ -2994,10 +2994,10 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.1" } }, "babel-code-frame": { @@ -3006,9 +3006,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" }, "dependencies": { "ansi-regex": { @@ -3029,11 +3029,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "strip-ansi": { @@ -3042,7 +3042,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "supports-color": { @@ -3056,18 +3056,18 @@ "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -3076,10 +3076,10 @@ "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "esutils": "^2.0.2" + "esutils": "2.0.2" } }, "escape-string-regexp": { @@ -3097,7 +3097,7 @@ "globals": { "version": "11.5.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.5.0.tgz", - "integrity": "sha1-a8hA3mdxFzsZHxPTqclNRB7pJkI=", + "integrity": "sha512-hYyf+kI8dm3nORsiiXUQigOU62hDLfJ9G01uyGMxhc6BKsircrUhC4uJPQPUSuq2GrTmiiEt7ewxlMdBewfmKQ==", "dev": true }, "has-ansi": { @@ -3106,7 +3106,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" }, "dependencies": { "ansi-regex": { @@ -3123,7 +3123,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.8" } }, "strip-ansi": { @@ -3132,16 +3132,16 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } }, "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3152,13 +3152,13 @@ "integrity": "sha1-n2yIvtUXwGDuqcQ0BqBXMw2whJc=", "dev": true, "requires": { - "babel-eslint": "^7.1.1", - "eslint-plugin-babel": "^4.0.1", - "eslint-plugin-flowtype": "^2.30.0", - "eslint-plugin-jasmine": "^2.2.0", - "eslint-plugin-prefer-object-spread": "^1.1.0", - "eslint-plugin-react": "^6.9.0", - "fbjs-eslint-utils": "^1.0.0" + "babel-eslint": "7.2.3", + "eslint-plugin-babel": "4.1.2", + "eslint-plugin-flowtype": "2.46.3", + "eslint-plugin-jasmine": "2.9.3", + "eslint-plugin-prefer-object-spread": "1.2.1", + "eslint-plugin-react": "6.10.3", + "fbjs-eslint-utils": "1.0.0" }, "dependencies": { "ansi-regex": { @@ -3179,9 +3179,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" } }, "babel-eslint": { @@ -3190,10 +3190,10 @@ "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=", "dev": true, "requires": { - "babel-code-frame": "^6.22.0", - "babel-traverse": "^6.23.1", - "babel-types": "^6.23.0", - "babylon": "^6.17.0" + "babel-code-frame": "6.26.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4" } }, "chalk": { @@ -3202,11 +3202,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "escape-string-regexp": { @@ -3227,11 +3227,11 @@ "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", "dev": true, "requires": { - "array.prototype.find": "^2.0.1", - "doctrine": "^1.2.2", - "has": "^1.0.1", - "jsx-ast-utils": "^1.3.4", - "object.assign": "^4.0.4" + "array.prototype.find": "2.0.4", + "doctrine": "1.5.0", + "has": "1.0.1", + "jsx-ast-utils": "1.4.1", + "object.assign": "4.1.0" } }, "esutils": { @@ -3246,7 +3246,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "jsx-ast-utils": { @@ -3261,7 +3261,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "supports-color": { @@ -3278,7 +3278,7 @@ "integrity": "sha1-foQTHYfvGLSWsYEESFkzdIYLTo4=", "dev": true, "requires": { - "lodash": "^4.15.0" + "lodash": "4.17.5" } }, "eslint-plugin-jasmine": { @@ -3299,8 +3299,8 @@ "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", "dev": true, "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "esrecurse": "4.2.1", + "estraverse": "4.2.0" } }, "eslint-visitor-keys": { @@ -3312,11 +3312,11 @@ "espree": { "version": "3.5.4", "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha1-sPRHGHyKi+2US4FaZgvd9d610ac=", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", "dev": true, "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" + "acorn": "5.5.3", + "acorn-jsx": "3.0.1" } }, "esprima": { @@ -3328,10 +3328,10 @@ "esquery": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { - "estraverse": "^4.0.0" + "estraverse": "4.2.0" } }, "esrecurse": { @@ -3340,7 +3340,7 @@ "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", "dev": true, "requires": { - "estraverse": "^4.1.0" + "estraverse": "4.2.0" } }, "estraverse": { @@ -3360,13 +3360,13 @@ "integrity": "sha1-GrDH+CE2UF3XSzHRdwHLK+bSZVg=", "dev": true, "requires": { - "individual": "^3.0.0" + "individual": "3.0.0" } }, "event-kit": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.0.tgz", - "integrity": "sha1-L3KxHitfUzzByVA4cEBiSkoCX+g=" + "integrity": "sha512-tUDxeNC9JzN2Tw/f8mLtksY34v1hHmaR7lV7X4p04XSjaeUhFMfzjF6Nwov9e0EKGEx63BaKcgXKxjpQaPo0wg==" }, "execa": { "version": "0.7.0", @@ -3374,13 +3374,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" } }, "expand-brackets": { @@ -3389,13 +3389,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -3404,7 +3404,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -3413,7 +3413,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -3434,8 +3434,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -3444,7 +3444,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -3452,12 +3452,12 @@ "external-editor": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha1-BFURz9jRM/OEZnPRBHwVTiFK09U=", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" + "chardet": "0.4.2", + "iconv-lite": "0.4.18", + "tmp": "0.0.33" }, "dependencies": { "os-tmpdir": { @@ -3469,10 +3469,10 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "os-tmpdir": "~1.0.2" + "os-tmpdir": "1.0.2" } } } @@ -3483,14 +3483,14 @@ "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", "dev": true, "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -3499,7 +3499,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -3508,36 +3508,36 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -3569,7 +3569,7 @@ "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", "dev": true, "requires": { - "bser": "^2.0.0" + "bser": "2.0.0" } }, "fbjs": { @@ -3577,13 +3577,13 @@ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.9" + "core-js": "1.2.7", + "isomorphic-fetch": "2.2.1", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "promise": "7.3.1", + "setimmediate": "1.0.5", + "ua-parser-js": "0.7.14" }, "dependencies": { "core-js": { @@ -3601,8 +3601,8 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" + "node-fetch": "1.7.3", + "whatwg-fetch": "2.0.4" } }, "loose-envify": { @@ -3610,7 +3610,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "^3.0.0" + "js-tokens": "3.0.2" } }, "node-fetch": { @@ -3618,8 +3618,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" + "encoding": "0.1.12", + "is-stream": "1.1.0" } }, "object-assign": { @@ -3646,7 +3646,7 @@ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5" + "escape-string-regexp": "1.0.5" }, "dependencies": { "escape-string-regexp": { @@ -3663,8 +3663,8 @@ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "flat-cache": "1.3.0", + "object-assign": "4.1.1" }, "dependencies": { "object-assign": { @@ -3681,10 +3681,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -3693,7 +3693,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -3704,7 +3704,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "^2.0.0" + "locate-path": "2.0.0" } }, "flat-cache": { @@ -3713,10 +3713,10 @@ "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "dev": true, "requires": { - "circular-json": "^0.3.1", - "del": "^2.0.2", - "graceful-fs": "^4.1.2", - "write": "^0.2.1" + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" }, "dependencies": { "graceful-fs": { @@ -3749,9 +3749,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "^0.4.0", + "asynckit": "0.4.0", "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "mime-types": "2.1.16" } }, "fragment-cache": { @@ -3760,7 +3760,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "^0.2.2" + "map-cache": "0.2.2" } }, "fs-constants": { @@ -3771,11 +3771,11 @@ "fs-extra": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha1-DYUhIuW8W+tFP7Ao6cDJvzY0DJQ=", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" } }, "fs-minipass": { @@ -3783,7 +3783,7 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", "integrity": "sha1-BsJ3IYRU7CiN93raVKA7hwKqy50=", "requires": { - "minipass": "^2.2.1" + "minipass": "2.3.3" } }, "function.prototype.name": { @@ -3792,9 +3792,9 @@ "integrity": "sha1-i9djzAr4YKhZzF1JOE10uTLNIyc=", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "is-callable": "^1.1.3" + "define-properties": "1.1.2", + "function-bind": "1.1.1", + "is-callable": "1.1.3" }, "dependencies": { "function-bind": { @@ -3816,14 +3816,14 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" }, "dependencies": { "ansi-regex": { @@ -3841,9 +3841,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "strip-ansi": { @@ -3851,7 +3851,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } } } @@ -3885,7 +3885,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "github-from-package": { @@ -3898,12 +3898,12 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" }, "dependencies": { "fs.realpath": { @@ -3916,8 +3916,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -3930,7 +3930,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.8" } }, "once": { @@ -3938,7 +3938,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "path-is-absolute": { @@ -3959,8 +3959,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "3.1.0", + "path-dirname": "1.0.2" }, "dependencies": { "is-glob": { @@ -3969,7 +3969,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } } } @@ -3986,8 +3986,8 @@ "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", "dev": true, "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" + "min-document": "2.19.0", + "process": "0.5.2" } }, "globals": { @@ -4001,12 +4001,12 @@ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" }, "dependencies": { "object-assign": { @@ -4033,7 +4033,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "^2.0.0" + "pinkie": "2.0.4" } } } @@ -4054,18 +4054,18 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.13.2.tgz", "integrity": "sha1-THQK48Iigj5wBAlvgy57k7IQgnA=", "requires": { - "iterall": "^1.2.1" + "iterall": "1.2.2" } }, "graphql-compiler": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/graphql-compiler/-/graphql-compiler-1.6.0.tgz", - "integrity": "sha1-JPFGzfiLgOBFMipXKhpdhLnCqdU=", + "integrity": "sha512-9r6IHZYA9N+teTfiIC2X4WcHgRjzfSCtEI4Sxe80eMOckvWhT84d2rESQfMpJl+zelxyqFTs+HTHnApRRwy0/Q==", "dev": true, "requires": { - "chalk": "^1.1.1", - "fb-watchman": "^2.0.0", - "immutable": "~3.7.6" + "chalk": "1.1.3", + "fb-watchman": "2.0.0", + "immutable": "3.7.6" } }, "har-schema": { @@ -4078,8 +4078,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "requires": { - "ajv": "^5.1.0", - "har-schema": "^2.0.0" + "ajv": "5.5.2", + "har-schema": "2.0.0" } }, "has": { @@ -4088,7 +4088,7 @@ "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", "dev": true, "requires": { - "function-bind": "^1.0.2" + "function-bind": "1.1.1" }, "dependencies": { "function-bind": { @@ -4105,7 +4105,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "has-flag": { @@ -4131,9 +4131,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" } }, "has-values": { @@ -4142,8 +4142,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "is-number": "3.0.0", + "kind-of": "4.0.0" }, "dependencies": { "kind-of": { @@ -4152,7 +4152,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -4163,10 +4163,10 @@ "integrity": "sha1-r02RTrBl+bXOTZ0RwcshJu7MMDg=", "dev": true, "requires": { - "boom": "4.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x", - "sntp": "2.x.x" + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" } }, "he": { @@ -4203,14 +4203,14 @@ "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" } }, "hosted-git-info": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha1-IyNbKasjDFdqqw1PE/wEawsDgiI=", + "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", "dev": true }, "htmlparser2": { @@ -4219,12 +4219,12 @@ "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", "dev": true, "requires": { - "domelementtype": "^1.3.0", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^2.0.2" + "domelementtype": "1.3.0", + "domhandler": "2.4.1", + "domutils": "1.5.1", + "entities": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.3" }, "dependencies": { "inherits": { @@ -4240,20 +4240,20 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.1" } }, "iconv-lite": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha1-I9hlaxaq5nQqwpcy6o8DNqR4nPI=" + "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" }, "ignore": { "version": "3.3.8", "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.8.tgz", - "integrity": "sha1-P46cNdOHCKOn4Omrtsc+fudweys=", + "integrity": "sha512-pUh+xUQQhQzevjRHHFqqcTy0/dP/kS9I8HSrUydhihjuD09W6ldVWFtIrwhXdUJHis3i2rZNqEHpZH/cbinFbg==", "dev": true }, "image-size": { @@ -4289,23 +4289,23 @@ "inquirer": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha1-ndLyrXZdyrH/BEO0kUQqILoifck=", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.5", "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" }, "dependencies": { "ansi-regex": { @@ -4317,21 +4317,21 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.1" } }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "escape-string-regexp": { @@ -4346,16 +4346,16 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } }, "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } }, "through": { @@ -4371,7 +4371,7 @@ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", "requires": { - "loose-envify": "^1.0.0" + "loose-envify": "1.3.1" }, "dependencies": { "loose-envify": { @@ -4379,7 +4379,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "^3.0.0" + "js-tokens": "3.0.2" } } } @@ -4396,7 +4396,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -4405,7 +4405,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -4434,7 +4434,7 @@ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { - "builtin-modules": "^1.0.0" + "builtin-modules": "1.1.1" } }, "is-callable": { @@ -4449,7 +4449,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -4458,7 +4458,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -4472,18 +4472,18 @@ "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" }, "dependencies": { "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } @@ -4505,7 +4505,7 @@ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" }, "dependencies": { "number-is-nan": { @@ -4520,7 +4520,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" }, "dependencies": { "number-is-nan": { @@ -4536,7 +4536,7 @@ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { - "is-extglob": "^2.1.1" + "is-extglob": "2.1.1" } }, "is-number": { @@ -4545,7 +4545,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -4554,7 +4554,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -4577,7 +4577,7 @@ "integrity": "sha1-dkZiRnH9fqVYzNmieVGC8pWPGyQ=", "dev": true, "requires": { - "is-number": "^4.0.0" + "is-number": "4.0.0" }, "dependencies": { "is-number": { @@ -4597,10 +4597,10 @@ "is-path-in-cwd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha1-WsSLNF72dTOb1sekipEhELJBz1I=", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "requires": { - "is-path-inside": "^1.0.0" + "is-path-inside": "1.0.1" } }, "is-path-inside": { @@ -4609,7 +4609,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "^1.0.1" + "path-is-inside": "1.0.2" } }, "is-plain-object": { @@ -4618,7 +4618,7 @@ "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "is-promise": { @@ -4633,7 +4633,7 @@ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { - "has": "^1.0.1" + "has": "1.0.1" } }, "is-resolvable": { @@ -4723,8 +4723,8 @@ "@babel/template": "7.0.0-beta.49", "@babel/traverse": "7.0.0-beta.49", "@babel/types": "7.0.0-beta.49", - "istanbul-lib-coverage": "^2.0.0", - "semver": "^5.5.0" + "istanbul-lib-coverage": "2.0.0", + "semver": "5.5.0" }, "dependencies": { "@babel/code-frame": { @@ -4743,10 +4743,10 @@ "dev": true, "requires": { "@babel/types": "7.0.0-beta.49", - "jsesc": "^2.5.1", - "lodash": "^4.17.5", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "jsesc": "2.5.1", + "lodash": "4.17.5", + "source-map": "0.5.7", + "trim-right": "1.0.1" } }, "@babel/helper-function-name": { @@ -4784,9 +4784,9 @@ "integrity": "sha1-lr3GtD4TSCASumaRsQGEktOWIsw=", "dev": true, "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^3.0.0" + "chalk": "2.4.1", + "esutils": "2.0.2", + "js-tokens": "3.0.2" } }, "@babel/template": { @@ -4798,7 +4798,7 @@ "@babel/code-frame": "7.0.0-beta.49", "@babel/parser": "7.0.0-beta.49", "@babel/types": "7.0.0-beta.49", - "lodash": "^4.17.5" + "lodash": "4.17.5" } }, "@babel/traverse": { @@ -4813,10 +4813,10 @@ "@babel/helper-split-export-declaration": "7.0.0-beta.49", "@babel/parser": "7.0.0-beta.49", "@babel/types": "7.0.0-beta.49", - "debug": "^3.1.0", - "globals": "^11.1.0", - "invariant": "^2.2.0", - "lodash": "^4.17.5" + "debug": "3.1.0", + "globals": "11.7.0", + "invariant": "2.2.4", + "lodash": "4.17.5" } }, "@babel/types": { @@ -4825,9 +4825,9 @@ "integrity": "sha1-t+Oxw/TUz+Eb34yJ8e/V4WF7h6Y=", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.5", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "2.0.0" } }, "ansi-styles": { @@ -4836,7 +4836,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.1" } }, "chalk": { @@ -4845,9 +4845,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "debug": { @@ -4883,7 +4883,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -4928,8 +4928,8 @@ "integrity": "sha1-WXwai9VxUvJtYizkEXhRpR9euu8=", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "1.0.10", + "esprima": "4.0.0" } }, "jsbn": { @@ -4980,7 +4980,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "requires": { - "graceful-fs": "^4.1.6" + "graceful-fs": "4.1.11" } }, "jsprim": { @@ -5004,7 +5004,7 @@ "just-extend": { "version": "1.1.27", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha1-7G55QQ/5FORyZSq/oOYDwD1g6QU=", + "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", "dev": true }, "keytar": { @@ -5013,7 +5013,7 @@ "integrity": "sha1-igamV3/fY3PgqmsRInfmPex3/RI=", "requires": { "nan": "2.8.0", - "prebuild-install": "^2.4.1" + "prebuild-install": "2.5.3" } }, "kind-of": { @@ -5028,7 +5028,7 @@ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "invert-kv": "^1.0.0" + "invert-kv": "1.0.0" } }, "lcov-parse": { @@ -5043,14 +5043,14 @@ "integrity": "sha1-zBJg9RyQCp7A2R+2mYE54CUHtjs=", "dev": true, "requires": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "mime": "^1.2.11", - "mkdirp": "^0.5.0", - "promise": "^7.1.1", + "errno": "0.1.4", + "graceful-fs": "4.1.11", + "image-size": "0.5.5", + "mime": "1.4.1", + "mkdirp": "0.5.1", + "promise": "7.3.1", "request": "2.81.0", - "source-map": "^0.5.3" + "source-map": "0.5.7" }, "dependencies": { "ajv": { @@ -5060,8 +5060,8 @@ "dev": true, "optional": true, "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" + "co": "4.6.0", + "json-stable-stringify": "1.0.1" } }, "assert-plus": { @@ -5091,7 +5091,7 @@ "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, "requires": { - "hoek": "2.x.x" + "hoek": "2.16.3" } }, "combined-stream": { @@ -5108,7 +5108,7 @@ "dev": true, "optional": true, "requires": { - "boom": "2.x.x" + "boom": "2.10.1" } }, "extend": { @@ -5132,9 +5132,9 @@ "dev": true, "optional": true, "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.16" }, "dependencies": { "combined-stream": { @@ -5144,7 +5144,7 @@ "dev": true, "optional": true, "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } } } @@ -5170,8 +5170,8 @@ "dev": true, "optional": true, "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" + "ajv": "4.11.8", + "har-schema": "1.0.5" } }, "hawk": { @@ -5181,10 +5181,10 @@ "dev": true, "optional": true, "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" } }, "hoek": { @@ -5200,9 +5200,9 @@ "dev": true, "optional": true, "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.14.1" } }, "is-typedarray": { @@ -5226,7 +5226,7 @@ "dev": true, "optional": true, "requires": { - "jsonify": "~0.0.0" + "jsonify": "0.0.0" } }, "json-stringify-safe": { @@ -5278,28 +5278,28 @@ "dev": true, "optional": true, "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~4.2.1", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "performance-now": "^0.2.0", - "qs": "~6.4.0", - "safe-buffer": "^5.0.1", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.0.0" + "aws-sign2": "0.6.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.16", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.6", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" }, "dependencies": { "combined-stream": { @@ -5309,7 +5309,7 @@ "dev": true, "optional": true, "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } }, "tough-cookie": { @@ -5319,7 +5319,7 @@ "dev": true, "optional": true, "requires": { - "punycode": "^1.4.1" + "punycode": "1.4.1" } } } @@ -5331,7 +5331,7 @@ "dev": true, "optional": true, "requires": { - "hoek": "2.x.x" + "hoek": "2.16.3" } }, "source-map": { @@ -5356,8 +5356,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "1.1.2", + "type-check": "0.3.2" } }, "load-json-file": { @@ -5366,10 +5366,10 @@ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" } }, "locate-path": { @@ -5378,8 +5378,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "2.0.0", + "path-exists": "3.0.0" } }, "lodash": { @@ -5393,8 +5393,8 @@ "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", "dev": true, "requires": { - "lodash._basecopy": "^3.0.0", - "lodash.keys": "^3.0.0" + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" } }, "lodash._basecopy": { @@ -5427,9 +5427,9 @@ "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", "dev": true, "requires": { - "lodash._baseassign": "^3.0.0", - "lodash._basecreate": "^3.0.0", - "lodash._isiterateecall": "^3.0.0" + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" } }, "lodash.flattendeep": { @@ -5468,9 +5468,9 @@ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" } }, "lodash.memoize": { @@ -5492,7 +5492,7 @@ "lolex": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.0.tgz", - "integrity": "sha1-nAh6aexEDjnT95Z2fPGyzcQ9XqU=", + "integrity": "sha512-uJkH2e0BVfU5KOJUevbTOtpDduooSarH5PopO+LfM/vZf8Z9sJzODqKev804JYM2i++ktJfUmC1le4LwFQ1VMg==", "dev": true }, "loose-envify": { @@ -5500,7 +5500,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "^3.0.0" + "js-tokens": "3.0.2" } }, "lru-cache": { @@ -5521,7 +5521,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "^1.0.0" + "object-visit": "1.0.1" } }, "mem": { @@ -5530,7 +5530,7 @@ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "1.2.0" } }, "merge2": { @@ -5542,22 +5542,22 @@ "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.9", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "mime-db": { @@ -5570,7 +5570,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=", "requires": { - "mime-db": "~1.29.0" + "mime-db": "1.29.0" } }, "mimic-fn": { @@ -5590,7 +5590,7 @@ "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", "dev": true, "requires": { - "dom-walk": "^0.1.0" + "dom-walk": "0.1.1" } }, "minimatch": { @@ -5598,7 +5598,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.8" } }, "minimist": { @@ -5609,10 +5609,10 @@ "minipass": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz", - "integrity": "sha1-p9zIt7gz9dNodZzOVE3MtV9Q8jM=", + "integrity": "sha512-/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw==", "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" + "safe-buffer": "5.1.2", + "yallist": "3.0.2" }, "dependencies": { "safe-buffer": { @@ -5627,7 +5627,7 @@ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz", "integrity": "sha1-EeE2WM5GvDpwomeqxYNZ0eDCnOs=", "requires": { - "minipass": "^2.2.1" + "minipass": "2.3.3" } }, "mixin-deep": { @@ -5636,8 +5636,8 @@ "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", "dev": true, "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "for-in": "1.0.2", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -5646,7 +5646,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -5672,7 +5672,7 @@ "integrity": "sha1-gpOC/8Bla2Z+e+ZQoJSgba69Uk8=", "dev": true, "requires": { - "request-json": "^0.6.1" + "request-json": "0.6.3" }, "dependencies": { "depd": { @@ -5723,7 +5723,7 @@ "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "dev": true, "requires": { - "mime-db": "~1.33.0" + "mime-db": "1.33.0" } }, "oauth-sign": { @@ -5738,28 +5738,28 @@ "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", "dev": true, "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", - "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "hawk": "~6.0.2", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", - "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "stringstream": "~0.0.5", - "tough-cookie": "~2.3.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" } }, "request-json": { @@ -5774,7 +5774,8 @@ }, "stringstream": { "version": "0.0.5", - "resolved": "", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", "dev": true } } @@ -5785,10 +5786,10 @@ "integrity": "sha1-kBmEuev51g9xXvDo4EwG5KsSJFc=", "dev": true, "requires": { - "debug": "^2.2.0", - "mkdirp": "~0.5.1", - "mocha": "^2.2.5", - "xml": "^1.0.0" + "debug": "2.6.9", + "mkdirp": "0.5.1", + "mocha": "2.5.3", + "xml": "1.0.1" }, "dependencies": { "commander": { @@ -5824,8 +5825,8 @@ "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", "dev": true, "requires": { - "inherits": "2", - "minimatch": "0.3" + "inherits": "2.0.3", + "minimatch": "0.3.0" } }, "growl": { @@ -5846,8 +5847,8 @@ "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", "dev": true, "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "lru-cache": "2.7.3", + "sigmund": "1.0.1" } }, "mocha": { @@ -5926,18 +5927,18 @@ "integrity": "sha1-h59xUMstq3pHElkGbBBO7m4Pp8I=", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-odd": "2.0.0", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -5946,8 +5947,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" } }, "is-extendable": { @@ -5956,7 +5957,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -5973,10 +5974,10 @@ "integrity": "sha1-bnsPTmi/w+dMmervLto55RMUNDk=", "dev": true, "requires": { - "nomnom": "~1.6.2", - "railroad-diagrams": "^1.0.0", + "nomnom": "1.6.2", + "railroad-diagrams": "1.0.0", "randexp": "0.4.6", - "semver": "^5.4.1" + "semver": "5.4.1" } }, "next-tick": { @@ -5988,14 +5989,14 @@ "nise": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.1.tgz", - "integrity": "sha1-eLwrND1f8QMeqdG7LIepTCbbclA=", + "integrity": "sha512-9JX3YwoIt3kS237scmSSOpEv7vCukVzLfwK0I0XhocDSHUANid8ZHnLEULbbSkfeMn98B2y5kphIWzZUylESRQ==", "dev": true, "requires": { - "@sinonjs/formatio": "^2.0.0", - "just-extend": "^1.1.27", - "lolex": "^2.3.2", - "path-to-regexp": "^1.7.0", - "text-encoding": "^0.6.4" + "@sinonjs/formatio": "2.0.0", + "just-extend": "1.1.27", + "lolex": "2.7.0", + "path-to-regexp": "1.7.0", + "text-encoding": "0.6.4" } }, "node-abi": { @@ -6003,15 +6004,15 @@ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.0.tgz", "integrity": "sha1-PCdRXLhC9bvBMqMSVPnx4cVce4M=", "requires": { - "semver": "^5.4.1" + "semver": "5.4.1" } }, "node-emoji": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz", - "integrity": "sha1-buxr+wdCHiFIx1xrunJCH4UwqCY=", + "integrity": "sha512-+ktMAh1Jwas+TnGodfCfjUbJKoANqPaJFN0z0iqh41eqD8dvguNzcitVSBSVK1pidz0AqGbLKcoVuVLRVZ/aVg==", "requires": { - "lodash.toarray": "^4.4.0" + "lodash.toarray": "4.4.0" } }, "node-fetch": { @@ -6032,8 +6033,8 @@ "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", "dev": true, "requires": { - "colors": "0.5.x", - "underscore": "~1.4.4" + "colors": "0.5.1", + "underscore": "1.4.4" } }, "noop-logger": { @@ -6047,10 +6048,10 @@ "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "2.6.0", + "is-builtin-module": "1.0.0", + "semver": "5.4.1", + "validate-npm-package-license": "3.0.3" } }, "npm-run-path": { @@ -6059,7 +6060,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "^2.0.0" + "path-key": "2.0.1" } }, "npmlog": { @@ -6067,10 +6068,10 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" } }, "nth-check": { @@ -6079,7 +6080,7 @@ "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", "dev": true, "requires": { - "boolbase": "~1.0.0" + "boolbase": "1.0.0" } }, "nyc": { @@ -6088,31 +6089,31 @@ "integrity": "sha1-4Awm6b0zq16B7emSu+STCEhYmbY=", "dev": true, "requires": { - "archy": "^1.0.0", - "arrify": "^1.0.1", - "caching-transform": "^1.0.1", - "convert-source-map": "^1.5.1", - "debug-log": "^1.0.1", - "find-cache-dir": "^1.0.0", - "find-up": "^2.1.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.0", - "istanbul-lib-hook": "^2.0.0", - "istanbul-lib-instrument": "^2.2.0", - "istanbul-lib-report": "^2.0.0", - "istanbul-lib-source-maps": "^2.0.0", - "istanbul-reports": "^1.5.0", - "make-dir": "^1.3.0", - "md5-hex": "^2.0.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^4.2.2", + "archy": "1.0.0", + "arrify": "1.0.1", + "caching-transform": "1.0.1", + "convert-source-map": "1.5.1", + "debug-log": "1.0.1", + "find-cache-dir": "1.0.0", + "find-up": "2.1.0", + "foreground-child": "1.5.6", + "glob": "7.1.2", + "istanbul-lib-coverage": "2.0.0", + "istanbul-lib-hook": "2.0.0", + "istanbul-lib-instrument": "2.2.0", + "istanbul-lib-report": "2.0.0", + "istanbul-lib-source-maps": "2.0.0", + "istanbul-reports": "1.5.0", + "make-dir": "1.3.0", + "md5-hex": "2.0.0", + "merge-source-map": "1.1.0", + "resolve-from": "4.0.0", + "rimraf": "2.6.2", + "signal-exit": "3.0.2", + "spawn-wrap": "1.4.2", + "test-exclude": "4.2.2", "yargs": "11.1.0", - "yargs-parser": "^9.0.2" + "yargs-parser": "9.0.2" }, "dependencies": { "align-text": { @@ -6120,9 +6121,9 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" } }, "amdefine": { @@ -6140,7 +6141,7 @@ "bundled": true, "dev": true, "requires": { - "default-require-extensions": "^2.0.0" + "default-require-extensions": "2.0.0" } }, "archy": { @@ -6168,7 +6169,7 @@ "bundled": true, "dev": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -6182,9 +6183,9 @@ "bundled": true, "dev": true, "requires": { - "md5-hex": "^1.2.0", - "mkdirp": "^0.5.1", - "write-file-atomic": "^1.1.4" + "md5-hex": "1.3.0", + "mkdirp": "0.5.1", + "write-file-atomic": "1.3.4" }, "dependencies": { "md5-hex": { @@ -6192,7 +6193,7 @@ "bundled": true, "dev": true, "requires": { - "md5-o-matic": "^0.1.1" + "md5-o-matic": "0.1.1" } } } @@ -6209,8 +6210,8 @@ "dev": true, "optional": true, "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" + "align-text": "0.1.4", + "lazy-cache": "1.0.4" } }, "cliui": { @@ -6219,8 +6220,8 @@ "dev": true, "optional": true, "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", + "center-align": "0.1.3", + "right-align": "0.1.3", "wordwrap": "0.0.2" }, "dependencies": { @@ -6257,8 +6258,8 @@ "bundled": true, "dev": true, "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" + "lru-cache": "4.1.3", + "which": "1.3.1" } }, "debug": { @@ -6284,7 +6285,7 @@ "bundled": true, "dev": true, "requires": { - "strip-bom": "^3.0.0" + "strip-bom": "3.0.0" }, "dependencies": { "strip-bom": { @@ -6299,7 +6300,7 @@ "bundled": true, "dev": true, "requires": { - "is-arrayish": "^0.2.1" + "is-arrayish": "0.2.1" } }, "execa": { @@ -6307,13 +6308,13 @@ "bundled": true, "dev": true, "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" }, "dependencies": { "cross-spawn": { @@ -6321,9 +6322,9 @@ "bundled": true, "dev": true, "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" } } } @@ -6333,9 +6334,9 @@ "bundled": true, "dev": true, "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" + "commondir": "1.0.1", + "make-dir": "1.3.0", + "pkg-dir": "2.0.0" } }, "find-up": { @@ -6343,7 +6344,7 @@ "bundled": true, "dev": true, "requires": { - "locate-path": "^2.0.0" + "locate-path": "2.0.0" } }, "foreground-child": { @@ -6351,8 +6352,8 @@ "bundled": true, "dev": true, "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" + "cross-spawn": "4.0.2", + "signal-exit": "3.0.2" } }, "fs.realpath": { @@ -6375,12 +6376,12 @@ "bundled": true, "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "graceful-fs": { @@ -6393,10 +6394,10 @@ "bundled": true, "dev": true, "requires": { - "async": "^1.4.0", - "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" }, "dependencies": { "source-map": { @@ -6404,7 +6405,7 @@ "bundled": true, "dev": true, "requires": { - "amdefine": ">=0.0.4" + "amdefine": "1.0.1" } } } @@ -6429,8 +6430,8 @@ "bundled": true, "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -6458,7 +6459,7 @@ "bundled": true, "dev": true, "requires": { - "builtin-modules": "^1.0.0" + "builtin-modules": "1.1.1" } }, "is-fullwidth-code-point": { @@ -6486,7 +6487,7 @@ "bundled": true, "dev": true, "requires": { - "append-transform": "^1.0.0" + "append-transform": "1.0.0" } }, "istanbul-lib-report": { @@ -6494,9 +6495,9 @@ "bundled": true, "dev": true, "requires": { - "istanbul-lib-coverage": "^2.0.0", - "make-dir": "^1.3.0", - "supports-color": "^5.4.0" + "istanbul-lib-coverage": "2.0.0", + "make-dir": "1.3.0", + "supports-color": "5.4.0" } }, "istanbul-lib-source-maps": { @@ -6504,11 +6505,11 @@ "bundled": true, "dev": true, "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^2.0.0", - "make-dir": "^1.3.0", - "rimraf": "^2.6.2", - "source-map": "^0.6.1" + "debug": "3.1.0", + "istanbul-lib-coverage": "2.0.0", + "make-dir": "1.3.0", + "rimraf": "2.6.2", + "source-map": "0.6.1" }, "dependencies": { "source-map": { @@ -6523,7 +6524,7 @@ "bundled": true, "dev": true, "requires": { - "handlebars": "^4.0.11" + "handlebars": "4.0.11" } }, "json-parse-better-errors": { @@ -6536,7 +6537,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } }, "lazy-cache": { @@ -6550,7 +6551,7 @@ "bundled": true, "dev": true, "requires": { - "invert-kv": "^1.0.0" + "invert-kv": "1.0.0" } }, "locate-path": { @@ -6558,8 +6559,8 @@ "bundled": true, "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "2.0.0", + "path-exists": "3.0.0" }, "dependencies": { "path-exists": { @@ -6579,8 +6580,8 @@ "bundled": true, "dev": true, "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "pseudomap": "1.0.2", + "yallist": "2.1.2" } }, "make-dir": { @@ -6588,7 +6589,7 @@ "bundled": true, "dev": true, "requires": { - "pify": "^3.0.0" + "pify": "3.0.0" }, "dependencies": { "pify": { @@ -6603,7 +6604,7 @@ "bundled": true, "dev": true, "requires": { - "md5-o-matic": "^0.1.1" + "md5-o-matic": "0.1.1" } }, "md5-o-matic": { @@ -6616,7 +6617,7 @@ "bundled": true, "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "1.2.0" } }, "merge-source-map": { @@ -6624,7 +6625,7 @@ "bundled": true, "dev": true, "requires": { - "source-map": "^0.6.1" + "source-map": "0.6.1" }, "dependencies": { "source-map": { @@ -6644,7 +6645,7 @@ "bundled": true, "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -6670,10 +6671,10 @@ "bundled": true, "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "2.6.0", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" } }, "npm-run-path": { @@ -6681,7 +6682,7 @@ "bundled": true, "dev": true, "requires": { - "path-key": "^2.0.0" + "path-key": "2.0.1" } }, "number-is-nan": { @@ -6694,7 +6695,7 @@ "bundled": true, "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "optimist": { @@ -6702,8 +6703,8 @@ "bundled": true, "dev": true, "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" + "minimist": "0.0.8", + "wordwrap": "0.0.3" } }, "os-homedir": { @@ -6716,9 +6717,9 @@ "bundled": true, "dev": true, "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" } }, "p-finally": { @@ -6731,7 +6732,7 @@ "bundled": true, "dev": true, "requires": { - "p-try": "^1.0.0" + "p-try": "1.0.0" } }, "p-locate": { @@ -6739,7 +6740,7 @@ "bundled": true, "dev": true, "requires": { - "p-limit": "^1.1.0" + "p-limit": "1.2.0" } }, "p-try": { @@ -6762,7 +6763,7 @@ "bundled": true, "dev": true, "requires": { - "find-up": "^2.1.0" + "find-up": "2.1.0" } }, "pseudomap": { @@ -6796,7 +6797,7 @@ "dev": true, "optional": true, "requires": { - "align-text": "^0.1.1" + "align-text": "0.1.4" } }, "rimraf": { @@ -6804,7 +6805,7 @@ "bundled": true, "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "7.1.2" } }, "semver": { @@ -6822,7 +6823,7 @@ "bundled": true, "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "1.0.0" } }, "shebang-regex": { @@ -6851,12 +6852,12 @@ "bundled": true, "dev": true, "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" + "foreground-child": "1.5.6", + "mkdirp": "0.5.1", + "os-homedir": "1.0.2", + "rimraf": "2.6.2", + "signal-exit": "3.0.2", + "which": "1.3.1" } }, "spdx-correct": { @@ -6864,8 +6865,8 @@ "bundled": true, "dev": true, "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" } }, "spdx-exceptions": { @@ -6878,8 +6879,8 @@ "bundled": true, "dev": true, "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" } }, "spdx-license-ids": { @@ -6892,8 +6893,8 @@ "bundled": true, "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" } }, "strip-ansi": { @@ -6901,7 +6902,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } }, "strip-eof": { @@ -6914,7 +6915,7 @@ "bundled": true, "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } }, "test-exclude": { @@ -6922,10 +6923,10 @@ "bundled": true, "dev": true, "requires": { - "arrify": "^1.0.1", - "minimatch": "^3.0.4", - "read-pkg-up": "^3.0.0", - "require-main-filename": "^1.0.1" + "arrify": "1.0.1", + "minimatch": "3.0.4", + "read-pkg-up": "3.0.0", + "require-main-filename": "1.0.1" }, "dependencies": { "load-json-file": { @@ -6933,10 +6934,10 @@ "bundled": true, "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "graceful-fs": "4.1.11", + "parse-json": "4.0.0", + "pify": "3.0.0", + "strip-bom": "3.0.0" } }, "parse-json": { @@ -6944,8 +6945,8 @@ "bundled": true, "dev": true, "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "error-ex": "1.3.1", + "json-parse-better-errors": "1.0.2" } }, "path-type": { @@ -6953,7 +6954,7 @@ "bundled": true, "dev": true, "requires": { - "pify": "^3.0.0" + "pify": "3.0.0" } }, "pify": { @@ -6966,9 +6967,9 @@ "bundled": true, "dev": true, "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "load-json-file": "4.0.0", + "normalize-package-data": "2.4.0", + "path-type": "3.0.0" } }, "read-pkg-up": { @@ -6976,8 +6977,8 @@ "bundled": true, "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "find-up": "2.1.0", + "read-pkg": "3.0.0" } }, "strip-bom": { @@ -6993,9 +6994,9 @@ "dev": true, "optional": true, "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" }, "dependencies": { "yargs": { @@ -7004,9 +7005,9 @@ "dev": true, "optional": true, "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", "window-size": "0.1.0" } } @@ -7023,8 +7024,8 @@ "bundled": true, "dev": true, "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" } }, "which": { @@ -7032,7 +7033,7 @@ "bundled": true, "dev": true, "requires": { - "isexe": "^2.0.0" + "isexe": "2.0.0" } }, "which-module": { @@ -7056,8 +7057,8 @@ "bundled": true, "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "string-width": "1.0.2", + "strip-ansi": "3.0.1" }, "dependencies": { "ansi-regex": { @@ -7070,7 +7071,7 @@ "bundled": true, "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "string-width": { @@ -7078,9 +7079,9 @@ "bundled": true, "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "strip-ansi": { @@ -7088,7 +7089,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } } } @@ -7103,9 +7104,9 @@ "bundled": true, "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" } }, "y18n": { @@ -7123,18 +7124,18 @@ "bundled": true, "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" + "cliui": "4.1.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "9.0.2" }, "dependencies": { "camelcase": { @@ -7147,9 +7148,9 @@ "bundled": true, "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" } }, "yargs-parser": { @@ -7157,7 +7158,7 @@ "bundled": true, "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" } } } @@ -7167,7 +7168,7 @@ "bundled": true, "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" }, "dependencies": { "camelcase": { @@ -7195,9 +7196,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" }, "dependencies": { "define-property": { @@ -7206,7 +7207,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "kind-of": { @@ -7215,7 +7216,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -7244,7 +7245,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "^3.0.0" + "isobject": "3.0.1" } }, "object.assign": { @@ -7253,10 +7254,10 @@ "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "1.1.2", + "function-bind": "1.1.1", + "has-symbols": "1.0.0", + "object-keys": "1.0.11" }, "dependencies": { "function-bind": { @@ -7273,10 +7274,10 @@ "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" + "define-properties": "1.1.2", + "es-abstract": "1.11.0", + "function-bind": "1.1.1", + "has": "1.0.1" }, "dependencies": { "function-bind": { @@ -7293,7 +7294,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "object.values": { @@ -7302,10 +7303,10 @@ "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" + "define-properties": "1.1.2", + "es-abstract": "1.11.0", + "function-bind": "1.1.1", + "has": "1.0.1" }, "dependencies": { "function-bind": { @@ -7322,7 +7323,7 @@ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "1.2.0" } }, "optimist": { @@ -7330,7 +7331,7 @@ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", "requires": { - "wordwrap": "~0.0.2" + "wordwrap": "0.0.3" } }, "optionator": { @@ -7339,12 +7340,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" }, "dependencies": { "wordwrap": { @@ -7366,9 +7367,9 @@ "integrity": "sha1-QrwpAKa1uL0XN2yOiCtlr8zyS/I=", "dev": true, "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" } }, "os-tmpdir": { @@ -7388,7 +7389,7 @@ "integrity": "sha1-DpK2vty1nwIsE9DxlJ3ILRWQnxw=", "dev": true, "requires": { - "p-try": "^1.0.0" + "p-try": "1.0.0" } }, "p-locate": { @@ -7397,7 +7398,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "^1.1.0" + "p-limit": "1.2.0" } }, "p-try": { @@ -7412,7 +7413,7 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "^1.2.0" + "error-ex": "1.3.1" } }, "parse5": { @@ -7421,7 +7422,7 @@ "integrity": "sha1-BC95L/3TaFFVHPTp4Gazh0q0W1w=", "dev": true, "requires": { - "@types/node": "*" + "@types/node": "9.6.4" } }, "pascalcase": { @@ -7474,7 +7475,7 @@ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { - "pify": "^2.0.0" + "pify": "2.3.0" } }, "pathval": { @@ -7506,13 +7507,13 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "^2.0.0" + "pinkie": "2.0.4" } }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, "posix-character-classes": { @@ -7526,21 +7527,21 @@ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.5.3.tgz", "integrity": "sha1-n2XyQngtNwKWNTcQ6byENJDBn2k=", "requires": { - "detect-libc": "^1.0.3", - "expand-template": "^1.0.2", + "detect-libc": "1.0.3", + "expand-template": "1.1.0", "github-from-package": "0.0.0", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "node-abi": "^2.2.0", - "noop-logger": "^0.1.1", - "npmlog": "^4.0.1", - "os-homedir": "^1.0.1", - "pump": "^2.0.1", - "rc": "^1.1.6", - "simple-get": "^2.7.0", - "tar-fs": "^1.13.0", - "tunnel-agent": "^0.6.0", - "which-pm-runs": "^1.0.0" + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "node-abi": "2.4.0", + "noop-logger": "0.1.1", + "npmlog": "4.1.2", + "os-homedir": "1.0.2", + "pump": "2.0.1", + "rc": "1.2.7", + "simple-get": "2.8.1", + "tar-fs": "1.16.2", + "tunnel-agent": "0.6.0", + "which-pm-runs": "1.0.0" }, "dependencies": { "os-homedir": { @@ -7577,16 +7578,16 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", "requires": { - "asap": "~2.0.3" + "asap": "2.0.6" } }, "prop-types": { "version": "15.6.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", - "integrity": "sha1-BdXKd7RFPphdYPx/+MhZCUpJcQI=", + "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", "requires": { - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" + "loose-envify": "1.3.1", + "object-assign": "4.1.1" } }, "prr": { @@ -7607,8 +7608,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.1", + "once": "1.4.0" }, "dependencies": { "once": { @@ -7616,7 +7617,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "wrappy": { @@ -7642,7 +7643,7 @@ "integrity": "sha1-ooh2iBtLwsqRF9QTgWPduA94FXU=", "dev": true, "requires": { - "performance-now": "^2.1.0" + "performance-now": "2.1.0" } }, "railroad-diagrams": { @@ -7658,7 +7659,7 @@ "dev": true, "requires": { "discontinuous-range": "1.0.0", - "ret": "~0.1.10" + "ret": "0.1.15" } }, "rc": { @@ -7666,32 +7667,32 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz", "integrity": "sha1-ihDKMNWI0ARkNgNyuJDQbazQIpc=", "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "deep-extend": "0.5.1", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" } }, "react": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/react/-/react-16.4.1.tgz", - "integrity": "sha1-3lG6V2S1280fkHkDe4Yr0muC/jI=", + "integrity": "sha512-3GEs0giKp6E0Oh/Y9ZC60CmYgUPnp7voH9fbjWsvXtYFb4EWtgQub0ADSq0sJR0BbHc4FThLLtzlcFaFXIorwg==", "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "prop-types": "15.6.2" } }, "react-dom": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.1.tgz", - "integrity": "sha1-f4sCI7Ol++IFEWxW3rhd4yaF2tY=", + "integrity": "sha512-1Gin+wghF/7gl4Cqcvr1DxFX2Osz7ugxSwl6gBqCMpdrxHjIFUS7GYxrFftZ9Ln44FHw0JxCFD9YtZsrbR5/4A==", "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "prop-types": "15.6.2" } }, "react-input-autosize": { @@ -7699,7 +7700,7 @@ "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.1.tgz", "integrity": "sha1-7EKPoVsVkplPtfmqFbsetrr0IPg=", "requires": { - "prop-types": "^15.5.8" + "prop-types": "15.6.1" }, "dependencies": { "core-js": { @@ -7712,13 +7713,13 @@ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.9" + "core-js": "1.2.7", + "isomorphic-fetch": "2.2.1", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "promise": "7.3.1", + "setimmediate": "1.0.5", + "ua-parser-js": "0.7.14" } }, "is-stream": { @@ -7731,8 +7732,8 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" + "node-fetch": "1.7.3", + "whatwg-fetch": "2.0.4" } }, "loose-envify": { @@ -7740,7 +7741,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "^3.0.0" + "js-tokens": "3.0.2" } }, "node-fetch": { @@ -7748,8 +7749,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" + "encoding": "0.1.12", + "is-stream": "1.1.0" } }, "object-assign": { @@ -7762,9 +7763,9 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1" } }, "setimmediate": { @@ -7777,29 +7778,29 @@ "react-is": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.4.1.tgz", - "integrity": "sha1-1iTEZQ0sZdvVLHJiK784lDXZd24=", + "integrity": "sha512-xpb0PpALlFWNw/q13A+1aHeyJyLYCg0/cCHPUA43zYluZuIPHaHL3k8OBsTgQtxqW0FhyDEMvi8fZ/+7+r4OSQ==", "dev": true }, "react-reconciler": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.7.0.tgz", - "integrity": "sha1-lhSJQQPl8Tje7rXquvPugOsdAm0=", + "integrity": "sha512-50JwZ3yNyMS8fchN+jjWEJOH3Oze7UmhxeoJLn2j6f3NjpfCRbcmih83XTWmzqtar/ivd5f7tvQhvvhism2fgg==", "dev": true, "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "prop-types": "15.6.2" } }, "react-relay": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/react-relay/-/react-relay-1.6.0.tgz", - "integrity": "sha1-eg7KQ1yBubAdiRfUvKZQfu+83+Q=", + "integrity": "sha512-8clmRHXNo96pcdkA8ZeiqF7xGjE+mjSbdX/INj5upRm2M8AprSrFk2Oz5nH084O+0hvXQhZtFyraXJWQO9ld3A==", "requires": { - "babel-runtime": "^6.23.0", - "fbjs": "^0.8.14", - "prop-types": "^15.5.8", + "babel-runtime": "6.25.0", + "fbjs": "0.8.16", + "prop-types": "15.6.2", "relay-runtime": "1.6.0" } }, @@ -7808,9 +7809,9 @@ "resolved": "https://registry.npmjs.org/react-select/-/react-select-1.2.1.tgz", "integrity": "sha1-ov5YpWnrFNyqZUOBYmC5flOBINE=", "requires": { - "classnames": "^2.2.4", - "prop-types": "^15.5.8", - "react-input-autosize": "^2.1.2" + "classnames": "2.2.6", + "prop-types": "15.6.1", + "react-input-autosize": "2.2.1" }, "dependencies": { "core-js": { @@ -7823,13 +7824,13 @@ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.9" + "core-js": "1.2.7", + "isomorphic-fetch": "2.2.1", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "promise": "7.3.1", + "setimmediate": "1.0.5", + "ua-parser-js": "0.7.14" } }, "is-stream": { @@ -7842,8 +7843,8 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" + "node-fetch": "1.7.3", + "whatwg-fetch": "2.0.4" } }, "loose-envify": { @@ -7851,7 +7852,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "^3.0.0" + "js-tokens": "3.0.2" } }, "node-fetch": { @@ -7859,8 +7860,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" + "encoding": "0.1.12", + "is-stream": "1.1.0" } }, "object-assign": { @@ -7873,9 +7874,9 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1" } }, "setimmediate": { @@ -7888,13 +7889,13 @@ "react-test-renderer": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.4.1.tgz", - "integrity": "sha1-8vswwse1F9tuWxDtILtrCnzNjXA=", + "integrity": "sha512-wyyiPxRZOTpKnNIgUBOB6xPLTpIzwcQMIURhZvzUqZzezvHjaGNsDPBhMac5fIY3Jf5NuKxoGvV64zDSOECPPQ==", "dev": true, "requires": { - "fbjs": "^0.8.16", - "object-assign": "^4.1.1", - "prop-types": "^15.6.0", - "react-is": "^16.4.1" + "fbjs": "0.8.16", + "object-assign": "4.1.1", + "prop-types": "15.6.1", + "react-is": "16.4.1" }, "dependencies": { "prop-types": { @@ -7903,9 +7904,9 @@ "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", "dev": true, "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1" } } } @@ -7916,9 +7917,9 @@ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" } }, "read-pkg-up": { @@ -7927,22 +7928,22 @@ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "find-up": "2.1.0", + "read-pkg": "2.0.0" } }, "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" }, "dependencies": { "core-util-is": { @@ -7975,7 +7976,7 @@ "regenerator-runtime": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + "integrity": "sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w==" }, "regex-not": { "version": "1.0.2", @@ -7983,8 +7984,8 @@ "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" }, "dependencies": { "extend-shallow": { @@ -7993,8 +7994,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" } }, "is-extendable": { @@ -8003,7 +8004,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -8011,55 +8012,55 @@ "regexpp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha1-DjUW3Qt5BPQT0tQZPc5GGMOmias=", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", "dev": true }, "relay-compiler": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/relay-compiler/-/relay-compiler-1.6.0.tgz", - "integrity": "sha1-ChvI0owc8x2JhRCKdhumwNtI1KE=", + "integrity": "sha512-qm9Xp/5tcpMli0z4WFYeb4E16ynxTKtmaAPT077vDpAzalBB2f71JEkQJUdrvVzcdr5m53LuXhXBODkUNkLQkg==", "dev": true, "requires": { "@babel/generator": "7.0.0-beta.40", "@babel/types": "7.0.0-beta.40", - "babel-polyfill": "^6.20.0", - "babel-preset-fbjs": "^2.1.4", - "babel-runtime": "^6.23.0", - "babel-traverse": "^6.26.0", + "babel-polyfill": "6.26.0", + "babel-preset-fbjs": "2.1.4", + "babel-runtime": "6.25.0", + "babel-traverse": "6.26.0", "babylon": "7.0.0-beta.40", - "chalk": "^1.1.1", - "fast-glob": "^2.0.0", - "fb-watchman": "^2.0.0", - "fbjs": "^0.8.14", + "chalk": "1.1.3", + "fast-glob": "2.2.1", + "fb-watchman": "2.0.0", + "fbjs": "0.8.16", "graphql-compiler": "1.6.0", - "immutable": "~3.7.6", + "immutable": "3.7.6", "relay-runtime": "1.6.0", - "signedsource": "^1.0.0", - "yargs": "^9.0.0" + "signedsource": "1.0.0", + "yargs": "9.0.1" }, "dependencies": { "@babel/generator": { "version": "7.0.0-beta.40", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.40.tgz", - "integrity": "sha1-q2H5VW9PcdvRE4lJx5W7miHjAuo=", + "integrity": "sha512-c91BQcXyTq/5aFV4afgOionxZS1dxWt8OghEx5Q52SKssdGRFSiMKnk9tGkev1pYULPJBqjSDZU2Pcuc58ffZw==", "dev": true, "requires": { "@babel/types": "7.0.0-beta.40", - "jsesc": "^2.5.1", - "lodash": "^4.2.0", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "jsesc": "2.5.1", + "lodash": "4.17.5", + "source-map": "0.5.7", + "trim-right": "1.0.1" } }, "@babel/types": { "version": "7.0.0-beta.40", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.40.tgz", - "integrity": "sha1-JcPXquFBJqvgX8sJjGWma21rjBQ=", + "integrity": "sha512-uXCGCzTgMZxcSUzutCPtZmXbVC+cvENgS2e0tRuhn+Y1hZnMb8IHP0Trq7Q2MB/eFmG5pKrAeTIUfQIe5kA4Tg==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.2.0", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "2.0.0" } }, "babel-traverse": { @@ -8068,15 +8069,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.5" }, "dependencies": { "babel-runtime": { @@ -8085,14 +8086,14 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "dev": true } } @@ -8103,10 +8104,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" }, "dependencies": { "babel-runtime": { @@ -8115,8 +8116,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "to-fast-properties": { @@ -8130,7 +8131,7 @@ "babylon": { "version": "7.0.0-beta.40", "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.40.tgz", - "integrity": "sha1-kfyM1W1euYso5v3kEEXylXd5lAo=", + "integrity": "sha512-AVxF2EcxvGD5hhOuLTOLAXBb0VhwWpEX0HyHdAI2zU+AAP4qEwtQj8voz1JR3uclGai0rfcE+dCTHnNMOnimFg==", "dev": true }, "fast-glob": { @@ -8139,11 +8140,11 @@ "integrity": "sha512-wSyW1TBK3ia5V+te0rGPXudeMHoUQW6O5Y9oATiaGhpENmEifPDlOdhpsnlj5HoG6ttIvGiY1DdCmI9X2xGMhg==", "dev": true, "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.1", - "micromatch": "^3.1.10" + "@mrmlnc/readdir-enhanced": "2.2.1", + "glob-parent": "3.1.0", + "is-glob": "4.0.0", + "merge2": "1.2.1", + "micromatch": "3.1.10" } }, "jsesc": { @@ -8155,7 +8156,7 @@ "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true } } @@ -8163,10 +8164,10 @@ "relay-runtime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/relay-runtime/-/relay-runtime-1.6.0.tgz", - "integrity": "sha1-K3AFj7d6TJOhcXUs4Uf47o2KiLk=", + "integrity": "sha512-UJiEHp8CX2uFxXdM0nVLTCQ6yAT0GLmyMceXLISuW/l2a9jrS9a4MdZgdr/9UkkYno7Sj1hU/EUIQ0GaVkou8g==", "requires": { - "babel-runtime": "^6.23.0", - "fbjs": "^0.8.14" + "babel-runtime": "6.25.0", + "fbjs": "0.8.16" } }, "repeat-element": { @@ -8186,47 +8187,47 @@ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "requires": { - "is-finite": "^1.0.0" + "is-finite": "1.0.2" } }, "request": { "version": "2.87.0", "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", - "integrity": "sha1-MvACNc0I1IK00NaNuTqCnA7VdW4=", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", - "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", - "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "tough-cookie": "~2.3.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" }, "dependencies": { "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + "integrity": "sha1-o0kgUKXLm2NFBUHjnZeI0icng9s=" }, "mime-types": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "integrity": "sha1-bzI/YKg9ERRvgx/xH9ZuL+VQO7g=", "requires": { - "mime-db": "~1.33.0" + "mime-db": "1.33.0" } } } @@ -8249,8 +8250,8 @@ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" + "caller-path": "0.1.0", + "resolve-from": "1.0.1" } }, "resolve-from": { @@ -8271,8 +8272,8 @@ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" + "onetime": "2.0.1", + "signal-exit": "3.0.2" } }, "ret": { @@ -8284,9 +8285,9 @@ "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "requires": { - "glob": "^7.0.5" + "glob": "7.1.2" } }, "rst-selector-parser": { @@ -8295,8 +8296,8 @@ "integrity": "sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=", "dev": true, "requires": { - "lodash.flattendeep": "^4.4.0", - "nearley": "^2.7.10" + "lodash.flattendeep": "4.4.0", + "nearley": "2.13.0" } }, "run-async": { @@ -8305,7 +8306,7 @@ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true, "requires": { - "is-promise": "^2.1.0" + "is-promise": "2.1.0" } }, "rx-lite": { @@ -8320,7 +8321,7 @@ "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", "dev": true, "requires": { - "rx-lite": "*" + "rx-lite": "4.0.8" } }, "safe-buffer": { @@ -8334,19 +8335,19 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "~0.1.10" + "ret": "0.1.15" } }, "samsam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha1-jR2TUOJWItow3j5EumkrUiGrfFA=", + "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", "dev": true }, "semver": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha1-4FnAnYVx8FQII3M0M1BdOi8AsY4=" + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" }, "set-blocking": { "version": "2.0.0", @@ -8359,10 +8360,10 @@ "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" }, "dependencies": { "extend-shallow": { @@ -8371,7 +8372,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -8382,7 +8383,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "1.0.0" } }, "shebang-regex": { @@ -8418,9 +8419,9 @@ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", "integrity": "sha1-DiLpHUV12HYgYgvJEwjVenf0S10=", "requires": { - "decompress-response": "^3.3.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" + "decompress-response": "3.3.0", + "once": "1.4.0", + "simple-concat": "1.0.0" }, "dependencies": { "once": { @@ -8428,7 +8429,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "wrappy": { @@ -8441,25 +8442,25 @@ "sinon": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.0.0.tgz", - "integrity": "sha1-8mYn5IMNw0J5ZhR02iyeeE8WYhU=", + "integrity": "sha512-MatciKXyM5pXMSoqd593MqTsItJNCkSSl53HJYeKR5wfsDdp2yljjUQJLfVwAWLoBNfx1HThteqygGQ0ZEpXpQ==", "dev": true, "requires": { - "@sinonjs/formatio": "^2.0.0", - "diff": "^3.5.0", - "lodash.get": "^4.4.2", - "lolex": "^2.4.2", - "nise": "^1.3.3", - "supports-color": "^5.4.0", - "type-detect": "^4.0.8" + "@sinonjs/formatio": "2.0.0", + "diff": "3.5.0", + "lodash.get": "4.4.2", + "lolex": "2.7.0", + "nise": "1.4.1", + "supports-color": "5.4.0", + "type-detect": "4.0.8" }, "dependencies": { "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -8472,10 +8473,10 @@ "slice-ansi": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha1-BE8aSdiEL/MHqta1Be0Xi9lQE00=", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0" + "is-fullwidth-code-point": "2.0.0" }, "dependencies": { "is-fullwidth-code-point": { @@ -8489,17 +8490,17 @@ "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.1", + "use": "3.1.0" }, "dependencies": { "define-property": { @@ -8508,7 +8509,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -8517,7 +8518,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -8528,9 +8529,9 @@ "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", "dev": true, "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" }, "dependencies": { "define-property": { @@ -8539,36 +8540,36 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -8579,7 +8580,7 @@ "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", "dev": true, "requires": { - "kind-of": "^3.2.0" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -8588,7 +8589,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -8599,7 +8600,7 @@ "integrity": "sha1-LGzsFP7cIiJznK+bXD2F0cxaLMg=", "dev": true, "requires": { - "hoek": "4.x.x" + "hoek": "4.2.1" } }, "source-map": { @@ -8613,11 +8614,11 @@ "integrity": "sha1-etD1k/IoFZjoVN+A8ZquS5LXoRo=", "dev": true, "requires": { - "atob": "^2.0.0", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "atob": "2.1.1", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" } }, "source-map-support": { @@ -8625,7 +8626,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", "integrity": "sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8=", "requires": { - "source-map": "^0.5.6" + "source-map": "0.5.7" } }, "source-map-url": { @@ -8637,33 +8638,33 @@ "spdx-correct": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha1-BaW01xU6GVvJLDxCW2nzsqlSTII=", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" } }, "spdx-exceptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha1-LHrmEFbHFKW5ubKyr30xHvXHj+k=", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" } }, "spdx-license-ids": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=", + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", "dev": true }, "split": { @@ -8671,7 +8672,7 @@ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", "integrity": "sha1-YFvZvjA6pZ+zX5Ip++oN3snqB9k=", "requires": { - "through": "2" + "through": "2.3.8" }, "dependencies": { "through": { @@ -8687,7 +8688,7 @@ "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "extend-shallow": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -8696,8 +8697,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" } }, "is-extendable": { @@ -8706,7 +8707,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -8722,14 +8723,14 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" } }, "static-extend": { @@ -8738,8 +8739,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "define-property": "0.2.5", + "object-copy": "0.1.0" }, "dependencies": { "define-property": { @@ -8748,7 +8749,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -8762,11 +8763,11 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" }, "dependencies": { "ansi-regex": { @@ -8777,15 +8778,15 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" } }, "strip-ansi": { @@ -8793,7 +8794,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } } } @@ -8803,7 +8804,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "stringstream": { @@ -8819,7 +8820,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "strip-bom": { @@ -8848,35 +8849,35 @@ "table": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha1-ozRHN1OR52atNNNIbm4q7chNLjY=", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", "dev": true, "requires": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.4.1", + "lodash": "4.17.5", "slice-ansi": "1.0.0", - "string-width": "^2.1.1" + "string-width": "2.1.1" }, "dependencies": { "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.1" } }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "escape-string-regexp": { @@ -8888,10 +8889,10 @@ "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -8901,19 +8902,19 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.4.tgz", "integrity": "sha1-7IQJ+un2ZaQ1XMO0CH0IICMruM0=", "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.3", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" + "chownr": "1.0.1", + "fs-minipass": "1.2.5", + "minipass": "2.3.3", + "minizlib": "1.1.0", + "mkdirp": "0.5.1", + "safe-buffer": "5.1.2", + "yallist": "3.0.2" }, "dependencies": { "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" } } }, @@ -8922,10 +8923,10 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.2.tgz", "integrity": "sha1-F+Ujl0fjmffnc0T19TNl8Er1NXc=", "requires": { - "chownr": "^1.0.1", - "mkdirp": "^0.5.1", - "pump": "^1.0.0", - "tar-stream": "^1.1.2" + "chownr": "1.0.1", + "mkdirp": "0.5.1", + "pump": "1.0.3", + "tar-stream": "1.6.0" }, "dependencies": { "once": { @@ -8933,7 +8934,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "pump": { @@ -8941,8 +8942,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", "integrity": "sha1-Xf6DEcM7v2/BgmH580cCxHwIqVQ=", "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.1", + "once": "1.4.0" } }, "wrappy": { @@ -8957,13 +8958,13 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.0.tgz", "integrity": "sha1-pQ76p7F3YLgsJ7PK5KMBqCVKVxU=", "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.1.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.0.0", - "to-buffer": "^1.1.0", - "xtend": "^4.0.0" + "bl": "1.2.2", + "buffer-alloc": "1.1.0", + "end-of-stream": "1.4.1", + "fs-constants": "1.0.0", + "readable-stream": "2.3.3", + "to-buffer": "1.1.1", + "xtend": "4.0.1" } }, "temp": { @@ -8971,8 +8972,8 @@ "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", "requires": { - "os-tmpdir": "^1.0.0", - "rimraf": "~2.2.6" + "os-tmpdir": "1.0.2", + "rimraf": "2.2.8" }, "dependencies": { "os-tmpdir": { @@ -8993,11 +8994,11 @@ "integrity": "sha1-36Ii8DSAvKaSB8pyizfXS0X3JPo=", "dev": true, "requires": { - "arrify": "^1.0.1", - "micromatch": "^3.1.8", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", - "require-main-filename": "^1.0.1" + "arrify": "1.0.1", + "micromatch": "3.1.10", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "require-main-filename": "1.0.1" }, "dependencies": { "find-up": { @@ -9006,8 +9007,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" } }, "load-json-file": { @@ -9016,11 +9017,11 @@ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" } }, "path-exists": { @@ -9029,7 +9030,7 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "^2.0.0" + "pinkie-promise": "2.0.1" } }, "path-type": { @@ -9038,9 +9039,9 @@ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, "read-pkg": { @@ -9049,9 +9050,9 @@ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" } }, "read-pkg-up": { @@ -9060,8 +9061,8 @@ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "find-up": "1.1.2", + "read-pkg": "1.1.0" } }, "strip-bom": { @@ -9070,7 +9071,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "^0.2.0" + "is-utf8": "0.2.1" } } } @@ -9104,7 +9105,7 @@ "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", "dev": true, "requires": { - "os-tmpdir": "~1.0.1" + "os-tmpdir": "1.0.2" }, "dependencies": { "os-tmpdir": { @@ -9138,7 +9139,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -9147,7 +9148,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -9158,10 +9159,10 @@ "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", "dev": true, "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" }, "dependencies": { "extend-shallow": { @@ -9170,8 +9171,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" } }, "is-extendable": { @@ -9180,7 +9181,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -9191,8 +9192,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "3.0.0", + "repeat-string": "1.6.1" } }, "tough-cookie": { @@ -9200,7 +9201,7 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha1-7GDO44rGdQY//JelwYlwV47oNlU=", "requires": { - "punycode": "^1.4.1" + "punycode": "1.4.1" } }, "tree-kill": { @@ -9219,7 +9220,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "^5.0.1" + "safe-buffer": "5.1.1" } }, "tweetnacl": { @@ -9234,7 +9235,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "prelude-ls": "1.1.2" } }, "type-detect": { @@ -9266,10 +9267,10 @@ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" }, "dependencies": { "extend-shallow": { @@ -9278,7 +9279,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "set-value": { @@ -9287,10 +9288,10 @@ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" } } } @@ -9306,8 +9307,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "has-value": "0.3.1", + "isobject": "3.0.1" }, "dependencies": { "has-value": { @@ -9316,9 +9317,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" }, "dependencies": { "isobject": { @@ -9355,25 +9356,25 @@ "use": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha1-FHFr8D/f79AwQK71jYtLhfOnxUQ=", + "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", "dev": true, "requires": { - "kind-of": "^6.0.2" + "kind-of": "6.0.2" } }, "uuid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=" + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" }, "validate-npm-package-license": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha1-gWQ7y+8b3+zUYjeT3EZIlIupgzg=", + "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", "dev": true, "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" } }, "verror": { @@ -9381,9 +9382,9 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "^1.0.0", + "assert-plus": "1.0.0", "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "extsprintf": "1.3.0" }, "dependencies": { "assert-plus": { @@ -9405,11 +9406,11 @@ "dev": true, "requires": { "browser-split": "0.0.1", - "error": "^4.3.0", - "ev-store": "^7.0.0", - "global": "^4.3.0", - "is-object": "^1.0.1", - "next-tick": "^0.2.2", + "error": "4.4.0", + "ev-store": "7.0.0", + "global": "4.3.2", + "is-object": "1.0.1", + "next-tick": "0.2.2", "x-is-array": "0.1.0", "x-is-string": "0.1.0" } @@ -9424,7 +9425,7 @@ "resolved": "https://registry.npmjs.org/what-the-status/-/what-the-status-1.0.3.tgz", "integrity": "sha1-lP3NAR/7U6Ijnnb6+NrL78mHdRA=", "requires": { - "split": "^1.0.0" + "split": "1.0.1" } }, "whatwg-fetch": { @@ -9438,7 +9439,7 @@ "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", "dev": true, "requires": { - "isexe": "^2.0.0" + "isexe": "2.0.0" } }, "which-module": { @@ -9457,7 +9458,7 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", "integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=", "requires": { - "string-width": "^1.0.2" + "string-width": "1.0.2" }, "dependencies": { "ansi-regex": { @@ -9470,9 +9471,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "strip-ansi": { @@ -9480,7 +9481,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } } } @@ -9496,8 +9497,8 @@ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "string-width": "1.0.2", + "strip-ansi": "3.0.1" }, "dependencies": { "string-width": { @@ -9506,9 +9507,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } } } @@ -9519,7 +9520,7 @@ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "^0.5.1" + "mkdirp": "0.5.1" } }, "x-is-array": { @@ -9562,19 +9563,19 @@ "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", "dev": true, "requires": { - "camelcase": "^4.1.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "read-pkg-up": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^7.0.0" + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" } }, "yargs-parser": { @@ -9583,7 +9584,7 @@ "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" } }, "yubikiri": { diff --git a/test/controllers/git-tab-controller.test.js b/test/controllers/git-tab-controller.test.js index 9c6dfbd12b..63c3b05c37 100644 --- a/test/controllers/git-tab-controller.test.js +++ b/test/controllers/git-tab-controller.test.js @@ -713,13 +713,15 @@ describe('GitTabController', function() { const repository = await buildRepository(workdirPath); sinon.spy(repository, 'undoLastCommit'); fs.writeFileSync(path.join(workdirPath, 'new-file.txt'), 'foo\nbar\nbaz\n'); + const coAuthorName = 'Janelle Monae'; + const coAuthorEmail = 'janellemonae@github.com'; await repository.stageFiles(['new-file.txt']); const commitSubject = 'Commit some stuff'; const commitMessage = dedent` ${commitSubject} - Co-authored-by: Foo Bar + Co-authored-by: ${coAuthorName} <${coAuthorEmail}> `; await repository.commit(commitMessage); @@ -745,10 +747,9 @@ describe('GitTabController', function() { commitMessages = wrapper.find('.github-RecentCommit-message').map(node => node.text()); assert.deepEqual(commitMessages, ['Initial commit']); + const expectedCoAuthor = new Author(coAuthorName, coAuthorEmail); assert.strictEqual(wrapper.find('CommitView').prop('message'), commitSubject); - assert.deepEqual(wrapper.find('CommitView').prop('selectedCoAuthors'), [ - {name: 'Foo Bar', email: 'foo@bar.com'}, - ]); + assert.deepEqual(wrapper.find('CommitView').prop('selectedCoAuthors'), [expectedCoAuthor]); }); }); }); From 825778ec3c347fd548242e546fa2a31b2fd4483f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Jun 2018 21:12:21 -0400 Subject: [PATCH 0415/4847] Yadda yadda CommitCommentContainer to CommitCommentView --- .../commit-comment-thread-view.js | 4 +- .../timeline-items/commit-comment-view.js} | 10 +-- .../commit-comment-thread-results.js | 6 +- .../commit-comment-view.test.js | 61 +++++++++++++++++++ 4 files changed, 71 insertions(+), 10 deletions(-) rename lib/{containers/timeline-items/commit-comment-container.js => views/timeline-items/commit-comment-view.js} (85%) create mode 100644 test/views/timeline-items/commit-comment-view.test.js diff --git a/lib/views/timeline-items/commit-comment-thread-view.js b/lib/views/timeline-items/commit-comment-thread-view.js index 8d04be173f..d731ffe07a 100644 --- a/lib/views/timeline-items/commit-comment-thread-view.js +++ b/lib/views/timeline-items/commit-comment-thread-view.js @@ -2,7 +2,7 @@ import React from 'react'; import {graphql, createFragmentContainer} from 'react-relay'; import PropTypes from 'prop-types'; -import CommitCommentContainer from '../../containers/timeline-items/commit-comment-container'; +import CommitCommentContainer from '../../views/timeline-items/commit-comment-view'; export class BareCommitCommentThreadView extends React.Component { static propTypes = { @@ -47,7 +47,7 @@ export default createFragmentContainer(BareCommitCommentThreadView, { edges { node { id - ...commitCommentContainer_item + ...commitCommentView_item } } } diff --git a/lib/containers/timeline-items/commit-comment-container.js b/lib/views/timeline-items/commit-comment-view.js similarity index 85% rename from lib/containers/timeline-items/commit-comment-container.js rename to lib/views/timeline-items/commit-comment-view.js index 04a29668e6..e1fde61f76 100644 --- a/lib/containers/timeline-items/commit-comment-container.js +++ b/lib/views/timeline-items/commit-comment-view.js @@ -3,10 +3,10 @@ import {graphql, createFragmentContainer} from 'react-relay'; import PropTypes from 'prop-types'; import Octicon from '../../atom/octicon'; -import Timeago from '../../views/timeago'; -import GithubDotcomMarkdown from '../../views/github-dotcom-markdown'; +import Timeago from '../timeago'; +import GithubDotcomMarkdown from '../github-dotcom-markdown'; -export class CommitComment extends React.Component { +export class BareCommitCommentView extends React.Component { static propTypes = { item: PropTypes.object.isRequired, isReply: PropTypes.bool.isRequired, @@ -53,9 +53,9 @@ export class CommitComment extends React.Component { } } -export default createFragmentContainer(CommitComment, { +export default createFragmentContainer(BareCommitCommentView, { item: graphql` - fragment commitCommentContainer_item on CommitComment { + fragment commitCommentView_item on CommitComment { author { login avatarUrl } diff --git a/test/fixtures/factories/commit-comment-thread-results.js b/test/fixtures/factories/commit-comment-thread-results.js index 24eb98c705..bcbb2e7e18 100644 --- a/test/fixtures/factories/commit-comment-thread-results.js +++ b/test/fixtures/factories/commit-comment-thread-results.js @@ -7,7 +7,7 @@ export function createCommitComment(opts = {}) { id: idGen.generate('comment-comment'), commitOid: '1234abcd', authorLogin: 'author0', - authorAvatar: 'https://avatars2.githubusercontent.com/u/0?v=12', + authorAvatarUrl: 'https://avatars2.githubusercontent.com/u/0?v=12', bodyHTML: '

    body

    ', createdAt: '2018-06-28T15:04:05Z', commentPath: null, @@ -20,12 +20,12 @@ export function createCommitComment(opts = {}) { __typename: 'User', id: idGen.generate('user'), login: o.authorLogin, - avatarUrl: o.authorAvatar, + avatarUrl: o.authorAvatarUrl, }, commit: { oid: o.commitOid, }, - bodyHtml: o.bodyHtml, + bodyHTML: o.bodyHTML, createdAt: o.createdAt, path: o.commentPath, }; diff --git a/test/views/timeline-items/commit-comment-view.test.js b/test/views/timeline-items/commit-comment-view.test.js new file mode 100644 index 0000000000..72860039bb --- /dev/null +++ b/test/views/timeline-items/commit-comment-view.test.js @@ -0,0 +1,61 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BareCommitCommentView} from '../../../lib/views/timeline-items/commit-comment-view'; +import {createCommitComment} from '../../fixtures/factories/commit-comment-thread-results'; + +describe('CommitCommentView', function() { + function buildApp(opts, overloadProps = {}) { + const props = { + item: createCommitComment(opts), + isReply: false, + switchToIssueish: () => {}, + ...overloadProps, + }; + + return ; + } + + it('renders comment data', function() { + const wrapper = shallow(buildApp({ + commitOid: '0000ffff0000ffff', + authorLogin: 'me', + authorAvatarUrl: 'https://avatars2.githubusercontent.com/u/1?v=2', + bodyHTML: '

    text here

    ', + createdAt: '2018-06-28T15:04:05Z', + })); + + assert.isTrue(wrapper.find('Octicon[icon="comment"]').hasClass('pre-timeline-item-icon')); + + const avatarImg = wrapper.find('img.author-avatar'); + assert.strictEqual(avatarImg.prop('src'), 'https://avatars2.githubusercontent.com/u/1?v=2'); + assert.strictEqual(avatarImg.prop('title'), 'me'); + + const headerText = wrapper.find('.comment-message-header').text(); + assert.match(headerText, /^me commented/); + assert.match(headerText, /in 0000fff/); + assert.strictEqual(wrapper.find('Timeago').prop('time'), '2018-06-28T15:04:05Z'); + + assert.strictEqual(wrapper.find('GithubDotcomMarkdown').prop('html'), '

    text here

    '); + }); + + it('renders a reply comment', function() { + const wrapper = shallow(buildApp({ + authorLogin: 'me', + createdAt: '2018-06-29T15:04:05Z', + }, {isReply: true})); + + assert.isFalse(wrapper.find('.pre-timeline-item-icon').exists()); + + assert.match(wrapper.find('.comment-message-header').text(), /^me replied/); + assert.strictEqual(wrapper.find('Timeago').prop('time'), '2018-06-29T15:04:05Z'); + }); + + it('renders a path when available', function() { + const wrapper = shallow(buildApp({ + commentPath: 'aaa/bbb/ccc.txt', + })); + + assert.match(wrapper.find('.comment-message-header').text(), /on aaa\/bbb\/ccc.txt/); + }); +}); From f37e4d1da3e999e5ccc79941e880dc13650b4196 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Jun 2018 21:20:35 -0400 Subject: [PATCH 0416/4847] CommitsView --- lib/controllers/issue-timeline-controller.js | 2 +- lib/controllers/pr-timeline-controller.js | 2 +- lib/views/issueish-timeline-view.js | 4 ++-- .../timeline-items/commits-view.js} | 8 +++----- .../timeline-items/commits-view.test.js} | 16 ++++++++-------- 5 files changed, 15 insertions(+), 17 deletions(-) rename lib/{containers/timeline-items/commits-container.js => views/timeline-items/commits-view.js} (91%) rename test/{containers/commits-container.test.js => views/timeline-items/commits-view.test.js} (82%) diff --git a/lib/controllers/issue-timeline-controller.js b/lib/controllers/issue-timeline-controller.js index b5af6be22f..5a84346722 100644 --- a/lib/controllers/issue-timeline-controller.js +++ b/lib/controllers/issue-timeline-controller.js @@ -18,7 +18,7 @@ export default createPaginationContainer(IssueishTimelineView, { cursor node { __typename - ...commitsContainer_nodes + ...commitsView_nodes ...issueCommentContainer_item ...crossReferencedEventsContainer_nodes } diff --git a/lib/controllers/pr-timeline-controller.js b/lib/controllers/pr-timeline-controller.js index 5451250d2d..b613221de4 100644 --- a/lib/controllers/pr-timeline-controller.js +++ b/lib/controllers/pr-timeline-controller.js @@ -17,7 +17,7 @@ export default createPaginationContainer(IssueishTimelineView, { cursor node { __typename - ...commitsContainer_nodes + ...commitsView_nodes ...issueCommentContainer_item ...mergedEventContainer_item ...headRefForcePushedEventContainer_item diff --git a/lib/views/issueish-timeline-view.js b/lib/views/issueish-timeline-view.js index 8ee8160cca..a2985b2d72 100644 --- a/lib/views/issueish-timeline-view.js +++ b/lib/views/issueish-timeline-view.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import {RelayConnectionPropType} from '../prop-types'; import {autobind} from '../helpers'; import Octicon from '../atom/octicon'; -import CommitsContainer from './../containers/timeline-items/commits-container.js'; +import CommitsView from './../views/timeline-items/commits-view.js'; import IssueCommentContainer from './../containers/timeline-items/issue-comment-container.js'; import MergedEventContainer from './../containers/timeline-items/merged-event-container.js'; import HeadRefForcePushedEventContainer from './../containers/timeline-items/head-ref-force-pushed-event-container.js'; @@ -49,7 +49,7 @@ export function collectionRenderer(Component, styleAsTimelineItem = true) { } const timelineItems = { - Commit: CommitsContainer, + Commit: CommitsView, CommitCommentThread: collectionRenderer(CommitCommentThreadView, false), IssueComment: collectionRenderer(IssueCommentContainer, false), MergedEvent: collectionRenderer(MergedEventContainer), diff --git a/lib/containers/timeline-items/commits-container.js b/lib/views/timeline-items/commits-view.js similarity index 91% rename from lib/containers/timeline-items/commits-container.js rename to lib/views/timeline-items/commits-view.js index 420af72fe4..928ccc4e6f 100644 --- a/lib/containers/timeline-items/commits-container.js +++ b/lib/views/timeline-items/commits-view.js @@ -3,9 +3,9 @@ import {graphql, createFragmentContainer} from 'react-relay'; import PropTypes from 'prop-types'; import Octicon from '../../atom/octicon'; -import CommitContainer from './commit-container'; +import CommitContainer from '../../containers/timeline-items/commit-container'; -export class Commits extends React.Component { +export class BareCommitsView extends React.Component { static propTypes = { nodes: PropTypes.arrayOf( PropTypes.shape({ @@ -76,11 +76,9 @@ export class Commits extends React.Component { return 'Someone'; } } - } - -export default createFragmentContainer(Commits, { +export default createFragmentContainer(BareCommitsView, { nodes: graphql` fragment commitsContainer_nodes on Commit @relay(plural: true) { id author { name user { login } } diff --git a/test/containers/commits-container.test.js b/test/views/timeline-items/commits-view.test.js similarity index 82% rename from test/containers/commits-container.test.js rename to test/views/timeline-items/commits-view.test.js index e9c7a980d2..6ffaaf97bc 100644 --- a/test/containers/commits-container.test.js +++ b/test/views/timeline-items/commits-view.test.js @@ -1,15 +1,15 @@ import React from 'react'; import {shallow} from 'enzyme'; -import {Commits} from '../../lib/containers/timeline-items/commits-container'; +import {BareCommitsView} from '../../../lib/views/timeline-items/commits-view'; -describe('CommitsContainer', function() { +describe('CommitsView', function() { it('renders a header with one user name', function() { const nodes = [ {id: 1, author: {name: 'FirstName', user: {login: 'FirstLogin'}}}, {id: 2, author: {name: null, user: null}}, ]; - const app = ; + const app = ; const instance = shallow(app); assert.match(instance.text(), /FirstLogin added/); }); @@ -19,7 +19,7 @@ describe('CommitsContainer', function() { {id: 1, author: {name: 'FirstName', user: {login: 'FirstLogin'}}}, {id: 2, author: {name: 'SecondName', user: {login: 'SecondLogin'}}}, ]; - const app = ; + const app = ; const instance = shallow(app); assert.match(instance.text(), /FirstLogin and SecondLogin added/); }); @@ -30,7 +30,7 @@ describe('CommitsContainer', function() { {id: 2, author: {name: 'SecondName', user: {login: 'SecondLogin'}}}, {id: 2, author: {name: 'ThirdName', user: {login: 'ThirdLogin'}}}, ]; - const app = ; + const app = ; const instance = shallow(app); assert.match(instance.text(), /FirstLogin, SecondLogin, and others added/); }); @@ -40,7 +40,7 @@ describe('CommitsContainer', function() { {id: 1, author: {name: 'FirstName', user: {login: 'FirstLogin'}}}, {id: 2, author: {name: 'SecondName', user: null}}, ]; - const app = ; + const app = ; const instance = shallow(app); assert.match(instance.text(), /FirstLogin and SecondName added/); }); @@ -50,7 +50,7 @@ describe('CommitsContainer', function() { {id: 1, author: {name: null, user: null}}, {id: 2, author: {name: null, user: null}}, ]; - const app = ; + const app = ; const instance = shallow(app); assert.match(instance.text(), /Someone added/); }); @@ -59,7 +59,7 @@ describe('CommitsContainer', function() { const nodes = [ {id: 1, author: {name: 'FirstName', user: null}}, ]; - const app = ; + const app = ; const instance = shallow(app); assert.notMatch(instance.text(), /added/); }); From cd15e33cfb021eb4d0d8e9a58f322019b8b920de Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Jun 2018 21:42:10 -0400 Subject: [PATCH 0417/4847] CommitView --- .../timeline-items/commit-view.js} | 7 +-- lib/views/timeline-items/commits-view.js | 6 +-- test/fixtures/factories/commit-result.js | 48 +++++++++++++++++++ .../timeline-items/commit-view.test.js} | 20 ++++---- 4 files changed, 65 insertions(+), 16 deletions(-) rename lib/{containers/timeline-items/commit-container.js => views/timeline-items/commit-view.js} (92%) create mode 100644 test/fixtures/factories/commit-result.js rename test/{containers/commit-container.test.js => views/timeline-items/commit-view.test.js} (91%) diff --git a/lib/containers/timeline-items/commit-container.js b/lib/views/timeline-items/commit-view.js similarity index 92% rename from lib/containers/timeline-items/commit-container.js rename to lib/views/timeline-items/commit-view.js index cc2ceb6f5b..db96baad8f 100644 --- a/lib/containers/timeline-items/commit-container.js +++ b/lib/views/timeline-items/commit-view.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import Octicon from '../../atom/octicon'; -export class Commit extends React.Component { +export class BareCommitView extends React.Component { static propTypes = { item: PropTypes.object.isRequired, } @@ -41,6 +41,7 @@ export class Commit extends React.Component { return null; } } + render() { const commit = this.props.item; return ( @@ -64,9 +65,9 @@ export class Commit extends React.Component { } } -export default createFragmentContainer(Commit, { +export default createFragmentContainer(BareCommitView, { item: graphql` - fragment commitContainer_item on Commit { + fragment commitView_item on Commit { author { name avatarUrl user { diff --git a/lib/views/timeline-items/commits-view.js b/lib/views/timeline-items/commits-view.js index 928ccc4e6f..e9938797e8 100644 --- a/lib/views/timeline-items/commits-view.js +++ b/lib/views/timeline-items/commits-view.js @@ -3,7 +3,7 @@ import {graphql, createFragmentContainer} from 'react-relay'; import PropTypes from 'prop-types'; import Octicon from '../../atom/octicon'; -import CommitContainer from '../../containers/timeline-items/commit-container'; +import CommitView from './commit-view'; export class BareCommitsView extends React.Component { static propTypes = { @@ -46,7 +46,7 @@ export class BareCommitsView extends React.Component { renderCommits() { return this.props.nodes.map(node => { - return ; + return ; }); } @@ -82,7 +82,7 @@ export default createFragmentContainer(BareCommitsView, { nodes: graphql` fragment commitsContainer_nodes on Commit @relay(plural: true) { id author { name user { login } } - ...commitContainer_item + ...commitView_item } `, }); diff --git a/test/fixtures/factories/commit-result.js b/test/fixtures/factories/commit-result.js new file mode 100644 index 0000000000..91ea0dd1de --- /dev/null +++ b/test/fixtures/factories/commit-result.js @@ -0,0 +1,48 @@ +import IDGenerator from './id-generator'; + +export function createCommitResult(opts = {}) { + const idGen = IDGenerator.fromOpts(opts); + + const o = { + id: idGen.generate('commit'), + authorName: 'Author', + authorHasUser: true, + authorLogin: 'author0', + authorAvatarURL: 'https://avatars2.githubusercontent.com/u/0?v=1', + authoredByCommitter: true, + oid: '0000', + message: 'message', + messageHeadlineHTML: '

    headline

    ', + ...opts, + }; + + if (!o.committerLogin) { + o.committerLogin = o.authorLogin; + } + if (!o.committerName) { + o.committerName = o.authorName; + } + if (!o.committerAvatarURL) { + o.committerAvatarURL = o.authorAvatarURL; + } + if (!o.committerHasUser) { + o.committerHasUser = o.authorHasUser; + } + + return { + author: { + name: o.authorName, + avatarUrl: o.authorAvatarURL, + user: o.authorHasUser ? {login: o.authorLogin} : null, + }, + committer: { + name: o.committerName, + avatarUrl: o.committerAvatarURL, + user: o.committerHasUser ? {login: o.committerLogin} : null, + }, + authoredByCommitter: o.authoredByCommitter, + oid: o.oid, + message: o.message, + messageHeadlineHTML: o.messageHeadlineHTML, + } +} diff --git a/test/containers/commit-container.test.js b/test/views/timeline-items/commit-view.test.js similarity index 91% rename from test/containers/commit-container.test.js rename to test/views/timeline-items/commit-view.test.js index b3f453f98e..e6b5cc4161 100644 --- a/test/containers/commit-container.test.js +++ b/test/views/timeline-items/commit-view.test.js @@ -1,9 +1,9 @@ import React from 'react'; import {shallow} from 'enzyme'; -import {Commit} from '../../lib/containers/timeline-items/commit-container'; +import {BareCommitView} from '../../../lib/views/timeline-items/commit-view'; -describe('CommitContainer', function() { +describe('CommitView', function() { it('prefers displaying usernames from `user.login`', function() { const item = { author: { @@ -22,7 +22,7 @@ describe('CommitContainer', function() { message: 'commit message', messageHeadlineHTML: '

    html

    ', }; - const app = ; + const app = ; const instance = shallow(app); assert.isTrue( instance.containsMatchingElement(), @@ -47,7 +47,7 @@ describe('CommitContainer', function() { message: 'commit message', messageHeadlineHTML: '

    html

    ', }; - const app = ; + const app = ; const instance = shallow(app); assert.isTrue( instance.containsMatchingElement(), @@ -74,7 +74,7 @@ describe('CommitContainer', function() { message: 'commit message', messageHeadlineHTML: '

    html

    ', }; - const app = ; + const app = ; const instance = shallow(app); assert.isTrue( instance.containsMatchingElement(), @@ -101,7 +101,7 @@ describe('CommitContainer', function() { message: 'commit message', messageHeadlineHTML: '

    html

    ', }; - const app = ; + const app = ; const instance = shallow(app); assert.isTrue( instance.containsMatchingElement(), @@ -130,7 +130,7 @@ describe('CommitContainer', function() { message: 'commit message', messageHeadlineHTML: '

    html

    ', }; - const app = ; + const app = ; const instance = shallow(app); assert.isTrue( instance.containsMatchingElement(), @@ -157,7 +157,7 @@ describe('CommitContainer', function() { message: 'full message', messageHeadlineHTML: '

    html

    ', }; - const app = ; + const app = ; const instance = shallow(app); assert.isTrue( instance.containsMatchingElement(), @@ -181,7 +181,7 @@ describe('CommitContainer', function() { message: 'full message', messageHeadlineHTML: '

    inner HTML

    ', }; - const app = ; + const app = ; const instance = shallow(app); assert.match(instance.html(), /

    inner HTML<\/h1>/); }); @@ -203,7 +203,7 @@ describe('CommitContainer', function() { message: 'full message', messageHeadlineHTML: '

    inner HTML

    ', }; - const app = ; + const app = ; const instance = shallow(app); assert.match(instance.text(), /e6c80aa3/); }); From 7b35785e512fa6e8ba760af7255984a94a6b39d2 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 29 Jun 2018 10:42:41 -0700 Subject: [PATCH 0418/4847] add unit tests for co-author functionality in `CommitView` --- test/views/commit-view.test.js | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/views/commit-view.test.js b/test/views/commit-view.test.js index 6bef7bd4ab..f27e672cdc 100644 --- a/test/views/commit-view.test.js +++ b/test/views/commit-view.test.js @@ -1,9 +1,12 @@ import React from 'react'; import {shallow, mount} from 'enzyme'; +import Author from '../../lib/models/author' +import CoAuthorForm from '../../lib/views/co-author-form'; import {cloneRepository, buildRepository} from '../helpers'; import Commit, {nullCommit} from '../../lib/models/commit'; import Branch, {nullBranch} from '../../lib/models/branch'; +import ObserveModel from '../../lib/views/observe-model'; import UserStore from '../../lib/models/user-store'; import CommitView from '../../lib/views/commit-view'; @@ -42,6 +45,7 @@ describe('CommitView', function() { abortMerge={noop} onChangeMessage={noop} toggleExpandedCommitMessageEditor={noop} + updateSelectedCoAuthors={noop} /> ); }); @@ -50,6 +54,43 @@ describe('CommitView', function() { atomEnv.destroy(); }); + describe('coauthor stuff', function() { + let wrapper; + beforeEach(function() { + wrapper = shallow(app); + }) + it('on initial load, renders co-author toggle but not input or form', function() { + const coAuthorButton = wrapper.find('.github-CommitView-coAuthorToggle'); + assert.deepEqual(coAuthorButton.length, 1); + assert.isFalse(coAuthorButton.hasClass('focused')); + + const coAuthorInput = wrapper.find('github-CommitView-coAuthorEditor'); + assert.deepEqual(coAuthorInput.length, 0); + + const coAuthorForm = wrapper.find(CoAuthorForm); + assert.deepEqual(coAuthorForm.length, 0); + }); + it('renders co-author input when toggle is clicked', function() { + const coAuthorButton = wrapper.find('.github-CommitView-coAuthorToggle'); + coAuthorButton.simulate('click'); + + const coAuthorInput = wrapper.find(ObserveModel); + assert.deepEqual(coAuthorInput.length, 1); + }); + it('renders co-author form when a new co-author is added', function() { + const coAuthorButton = wrapper.find('.github-CommitView-coAuthorToggle'); + coAuthorButton.simulate('click'); + + const newAuthor = Author.createNew('pizza@unicorn.party', 'Pizza Unicorn'); + wrapper.instance().onSelectedCoAuthorsChanged([newAuthor]); + wrapper.update(); + + const coAuthorForm = wrapper.find(CoAuthorForm); + assert.deepEqual(coAuthorForm.length, 1); + }); + + }); + describe('when the repo is loading', function() { beforeEach(function() { app = React.cloneElement(app, {lastCommit: nullCommit}); From 1d8940eb3985bc0453f2d55accc9812f629eddf1 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 29 Jun 2018 10:48:12 -0700 Subject: [PATCH 0419/4847] fix order of args for Author constructor --- lib/controllers/git-tab-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index ee2ebc0255..96bb9f708a 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -271,7 +271,7 @@ export default class GitTabController extends React.Component { repo.setCommitMessage(lastCommit.getFullMessage()); const coAuthors = lastCommit.getCoAuthors().map(author => - new Author(author.name, author.email)); + new Author(author.email, author.name)); this.updateSelectedCoAuthors(coAuthors); return repo.undoLastCommit(); From a122be09811fa5844a520e215bed777b9f060e5c Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 29 Jun 2018 10:58:13 -0700 Subject: [PATCH 0420/4847] fix order of arguments in test --- test/controllers/git-tab-controller.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/controllers/git-tab-controller.test.js b/test/controllers/git-tab-controller.test.js index 63c3b05c37..df6188e370 100644 --- a/test/controllers/git-tab-controller.test.js +++ b/test/controllers/git-tab-controller.test.js @@ -708,7 +708,7 @@ describe('GitTabController', function() { await assert.isFulfilled(wrapper.instance().undoLastCommit()); }); - it('restores to the state prior to committing', async function() { + it.only('restores to the state prior to committing', async function() { const workdirPath = await cloneRepository('three-files'); const repository = await buildRepository(workdirPath); sinon.spy(repository, 'undoLastCommit'); @@ -747,7 +747,7 @@ describe('GitTabController', function() { commitMessages = wrapper.find('.github-RecentCommit-message').map(node => node.text()); assert.deepEqual(commitMessages, ['Initial commit']); - const expectedCoAuthor = new Author(coAuthorName, coAuthorEmail); + const expectedCoAuthor = new Author(coAuthorEmail, coAuthorName); assert.strictEqual(wrapper.find('CommitView').prop('message'), commitSubject); assert.deepEqual(wrapper.find('CommitView').prop('selectedCoAuthors'), [expectedCoAuthor]); }); From 19c116b1234cbb32ea6df753c8e480e59a61f6b1 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 29 Jun 2018 11:01:38 -0700 Subject: [PATCH 0421/4847] :fire: it.only --- test/controllers/git-tab-controller.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/controllers/git-tab-controller.test.js b/test/controllers/git-tab-controller.test.js index df6188e370..4982babb72 100644 --- a/test/controllers/git-tab-controller.test.js +++ b/test/controllers/git-tab-controller.test.js @@ -708,7 +708,7 @@ describe('GitTabController', function() { await assert.isFulfilled(wrapper.instance().undoLastCommit()); }); - it.only('restores to the state prior to committing', async function() { + it('restores to the state prior to committing', async function() { const workdirPath = await cloneRepository('three-files'); const repository = await buildRepository(workdirPath); sinon.spy(repository, 'undoLastCommit'); From 64da7dac72905940f74c4ded457b1caa0d41647e Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 29 Jun 2018 14:32:44 -0700 Subject: [PATCH 0422/4847] :shirt: --- test/views/commit-view.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/views/commit-view.test.js b/test/views/commit-view.test.js index f27e672cdc..dee22fd46e 100644 --- a/test/views/commit-view.test.js +++ b/test/views/commit-view.test.js @@ -1,7 +1,7 @@ import React from 'react'; import {shallow, mount} from 'enzyme'; -import Author from '../../lib/models/author' +import Author from '../../lib/models/author'; import CoAuthorForm from '../../lib/views/co-author-form'; import {cloneRepository, buildRepository} from '../helpers'; import Commit, {nullCommit} from '../../lib/models/commit'; @@ -58,7 +58,7 @@ describe('CommitView', function() { let wrapper; beforeEach(function() { wrapper = shallow(app); - }) + }); it('on initial load, renders co-author toggle but not input or form', function() { const coAuthorButton = wrapper.find('.github-CommitView-coAuthorToggle'); assert.deepEqual(coAuthorButton.length, 1); From 913cfb08b5998c29ba11747217fe4f722ac1a046 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 09:14:15 -0400 Subject: [PATCH 0423/4847] IssueCommentView --- .../timeline-items/issue-comment-container.js | 41 ------------- lib/controllers/issue-timeline-controller.js | 2 +- lib/controllers/pr-timeline-controller.js | 2 +- lib/views/issueish-timeline-view.js | 4 +- .../timeline-items/issue-comment-view.js | 50 ++++++++++++++++ .../timeline-items/issue-comment-view.test.js | 57 +++++++++++++++++++ 6 files changed, 111 insertions(+), 45 deletions(-) delete mode 100644 lib/containers/timeline-items/issue-comment-container.js create mode 100644 lib/views/timeline-items/issue-comment-view.js create mode 100644 test/views/timeline-items/issue-comment-view.test.js diff --git a/lib/containers/timeline-items/issue-comment-container.js b/lib/containers/timeline-items/issue-comment-container.js deleted file mode 100644 index c8cef86de4..0000000000 --- a/lib/containers/timeline-items/issue-comment-container.js +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import {graphql, createFragmentContainer} from 'react-relay'; -import PropTypes from 'prop-types'; - -import Octicon from '../../atom/octicon'; -import Timeago from '../../views/timeago'; -import GithubDotcomMarkdown from '../../views/github-dotcom-markdown'; - -export class IssueComment extends React.Component { - static propTypes = { - switchToIssueish: PropTypes.func.isRequired, - item: PropTypes.object.isRequired, - } - - render() { - const comment = this.props.item; - return ( -
    -
    - - - - {comment.author.login} commented - -
    - -
    - ); - } -} - -export default createFragmentContainer(IssueComment, { - item: graphql` - fragment issueCommentContainer_item on IssueComment { - author { - avatarUrl login - } - bodyHTML createdAt - } - `, -}); diff --git a/lib/controllers/issue-timeline-controller.js b/lib/controllers/issue-timeline-controller.js index 5a84346722..652327a0b1 100644 --- a/lib/controllers/issue-timeline-controller.js +++ b/lib/controllers/issue-timeline-controller.js @@ -19,7 +19,7 @@ export default createPaginationContainer(IssueishTimelineView, { node { __typename ...commitsView_nodes - ...issueCommentContainer_item + ...issueCommentView_item ...crossReferencedEventsContainer_nodes } } diff --git a/lib/controllers/pr-timeline-controller.js b/lib/controllers/pr-timeline-controller.js index b613221de4..79ce825589 100644 --- a/lib/controllers/pr-timeline-controller.js +++ b/lib/controllers/pr-timeline-controller.js @@ -18,7 +18,7 @@ export default createPaginationContainer(IssueishTimelineView, { node { __typename ...commitsView_nodes - ...issueCommentContainer_item + ...issueCommentView_item ...mergedEventContainer_item ...headRefForcePushedEventContainer_item ...commitCommentThreadContainer_item diff --git a/lib/views/issueish-timeline-view.js b/lib/views/issueish-timeline-view.js index a2985b2d72..58bc3ae2cc 100644 --- a/lib/views/issueish-timeline-view.js +++ b/lib/views/issueish-timeline-view.js @@ -5,7 +5,7 @@ import {RelayConnectionPropType} from '../prop-types'; import {autobind} from '../helpers'; import Octicon from '../atom/octicon'; import CommitsView from './../views/timeline-items/commits-view.js'; -import IssueCommentContainer from './../containers/timeline-items/issue-comment-container.js'; +import IssueCommentView from './../views/timeline-items/issue-comment-view.js'; import MergedEventContainer from './../containers/timeline-items/merged-event-container.js'; import HeadRefForcePushedEventContainer from './../containers/timeline-items/head-ref-force-pushed-event-container.js'; import CrossReferencedEventsContainer from './../containers/timeline-items/cross-referenced-events-container.js'; @@ -51,7 +51,7 @@ export function collectionRenderer(Component, styleAsTimelineItem = true) { const timelineItems = { Commit: CommitsView, CommitCommentThread: collectionRenderer(CommitCommentThreadView, false), - IssueComment: collectionRenderer(IssueCommentContainer, false), + IssueComment: collectionRenderer(IssueCommentView, false), MergedEvent: collectionRenderer(MergedEventContainer), HeadRefForcePushedEvent: collectionRenderer(HeadRefForcePushedEventContainer), CrossReferencedEvent: CrossReferencedEventsContainer, diff --git a/lib/views/timeline-items/issue-comment-view.js b/lib/views/timeline-items/issue-comment-view.js new file mode 100644 index 0000000000..a65fa24cf8 --- /dev/null +++ b/lib/views/timeline-items/issue-comment-view.js @@ -0,0 +1,50 @@ +import React from 'react'; +import {graphql, createFragmentContainer} from 'react-relay'; +import PropTypes from 'prop-types'; + +import Octicon from '../../atom/octicon'; +import Timeago from '../timeago'; +import GithubDotcomMarkdown from '../github-dotcom-markdown'; + +export class BareIssueCommentView extends React.Component { + static propTypes = { + switchToIssueish: PropTypes.func.isRequired, + item: PropTypes.shape({ + author: PropTypes.shape({ + avatarUrl: PropTypes.string.isRequired, + login: PropTypes.string.isRequired, + }), + bodyHTML: PropTypes.string.isRequired, + createdAt: PropTypes.string.isRequired, + }).isRequired, + } + + render() { + const comment = this.props.item; + const author = comment.author; + + return ( +
    +
    + + {author && } + + {author ? author.login : 'someone'} commented + +
    + +
    + ); + } +} + +export default createFragmentContainer(BareIssueCommentView, { + item: graphql` + fragment issueCommentView_item on IssueComment { + author { + avatarUrl login + } + bodyHTML createdAt + } + `, +}); diff --git a/test/views/timeline-items/issue-comment-view.test.js b/test/views/timeline-items/issue-comment-view.test.js new file mode 100644 index 0000000000..2c85e14204 --- /dev/null +++ b/test/views/timeline-items/issue-comment-view.test.js @@ -0,0 +1,57 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BareIssueCommentView} from '../../../lib/views/timeline-items/issue-comment-view'; + +describe('IssueCommentView', function() { + function buildApp(opts, overrideProps = {}) { + const o = { + includeAuthor: true, + authorLogin: 'author', + authorAvatarURL: 'https://avatars.com/u/1', + bodyHTML: '

    body

    ', + createdAt: '2018-07-02T09:00:00Z', + ...opts, + }; + + const props = { + item: { + bodyHTML: o.bodyHTML, + createdAt: o.createdAt, + }, + switchToIssueish: () => {}, + ...overrideProps, + }; + + if (o.includeAuthor) { + props.item.author = { + login: o.authorLogin, + avatarUrl: o.authorAvatarURL, + }; + } + + return ( + + ); + } + + it('renders the comment data', function() { + const wrapper = shallow(buildApp({})); + + const avatarImg = wrapper.find('img.author-avatar'); + assert.strictEqual(avatarImg.prop('src'), 'https://avatars.com/u/1'); + assert.strictEqual(avatarImg.prop('title'), 'author'); + + assert.match(wrapper.find('.comment-message-header').text(), /^author commented/); + assert.strictEqual(wrapper.find('Timeago').prop('time'), '2018-07-02T09:00:00Z'); + + assert.strictEqual(wrapper.find('GithubDotcomMarkdown').prop('html'), '

    body

    '); + }); + + it('renders when no author is provided', function() { + const wrapper = shallow(buildApp({includeAuthor: false})); + + assert.isFalse(wrapper.find('img.author-avatar').exists()); + assert.match(wrapper.find('.comment-message-header').text(), /^someone commented/); + }); +}); From 2dd2f5b077c4a10f4568608897366cf40821b0f9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 09:39:59 -0400 Subject: [PATCH 0424/4847] MergedEventView --- lib/controllers/pr-timeline-controller.js | 2 +- lib/views/issueish-timeline-view.js | 8 +-- .../timeline-items/merged-event-view.js} | 33 +++++++--- .../timeline-items/merged-event-view.test.js | 63 +++++++++++++++++++ 4 files changed, 91 insertions(+), 15 deletions(-) rename lib/{containers/timeline-items/merged-event-container.js => views/timeline-items/merged-event-view.js} (57%) create mode 100644 test/views/timeline-items/merged-event-view.test.js diff --git a/lib/controllers/pr-timeline-controller.js b/lib/controllers/pr-timeline-controller.js index 79ce825589..30e03ea485 100644 --- a/lib/controllers/pr-timeline-controller.js +++ b/lib/controllers/pr-timeline-controller.js @@ -19,7 +19,7 @@ export default createPaginationContainer(IssueishTimelineView, { __typename ...commitsView_nodes ...issueCommentView_item - ...mergedEventContainer_item + ...mergedEventView_item ...headRefForcePushedEventContainer_item ...commitCommentThreadContainer_item ...crossReferencedEventsContainer_nodes diff --git a/lib/views/issueish-timeline-view.js b/lib/views/issueish-timeline-view.js index 58bc3ae2cc..4781512bda 100644 --- a/lib/views/issueish-timeline-view.js +++ b/lib/views/issueish-timeline-view.js @@ -4,9 +4,9 @@ import PropTypes from 'prop-types'; import {RelayConnectionPropType} from '../prop-types'; import {autobind} from '../helpers'; import Octicon from '../atom/octicon'; -import CommitsView from './../views/timeline-items/commits-view.js'; -import IssueCommentView from './../views/timeline-items/issue-comment-view.js'; -import MergedEventContainer from './../containers/timeline-items/merged-event-container.js'; +import CommitsView from './timeline-items/commits-view.js'; +import IssueCommentView from './timeline-items/issue-comment-view.js'; +import MergedEventView from './timeline-items/merged-event-view.js'; import HeadRefForcePushedEventContainer from './../containers/timeline-items/head-ref-force-pushed-event-container.js'; import CrossReferencedEventsContainer from './../containers/timeline-items/cross-referenced-events-container.js'; import CommitCommentThreadView from './../views/timeline-items/commit-comment-thread-view'; @@ -52,7 +52,7 @@ const timelineItems = { Commit: CommitsView, CommitCommentThread: collectionRenderer(CommitCommentThreadView, false), IssueComment: collectionRenderer(IssueCommentView, false), - MergedEvent: collectionRenderer(MergedEventContainer), + MergedEvent: collectionRenderer(MergedEventView), HeadRefForcePushedEvent: collectionRenderer(HeadRefForcePushedEventContainer), CrossReferencedEvent: CrossReferencedEventsContainer, }; diff --git a/lib/containers/timeline-items/merged-event-container.js b/lib/views/timeline-items/merged-event-view.js similarity index 57% rename from lib/containers/timeline-items/merged-event-container.js rename to lib/views/timeline-items/merged-event-view.js index d992fc1904..0e44e632f1 100644 --- a/lib/containers/timeline-items/merged-event-container.js +++ b/lib/views/timeline-items/merged-event-view.js @@ -1,44 +1,57 @@ -import React from 'react'; +import React, {Fragment} from 'react'; import {graphql, createFragmentContainer} from 'react-relay'; import PropTypes from 'prop-types'; import Octicon from '../../atom/octicon'; import Timeago from '../../views/timeago'; -export class MergedEvent extends React.Component { +export class BareMergedEventView extends React.Component { static propTypes = { item: PropTypes.shape({ actor: PropTypes.shape({ avatarUrl: PropTypes.string.isRequired, login: PropTypes.string.isRequired, - }).isRequired, + }), commit: PropTypes.shape({ oid: PropTypes.string.isRequired, - }).isRequired, + }), mergeRefName: PropTypes.string.isRequired, createdAt: PropTypes.string.isRequired, }).isRequired, } render() { - const {actor, commit, mergeRefName, createdAt} = this.props.item; + const {actor, mergeRefName, createdAt} = this.props.item; return (
    - + {actor && } - {actor.login} merged - commit {commit.oid.slice(0, 8)} into + {actor ? actor.login : 'someone'} merged + {this.renderCommit()} into {' '}{mergeRefName} on
    ); } + + renderCommit() { + const {commit} = this.props.item; + if (!commit) { + return 'a commit'; + } + + return ( + + commit {commit.oid.slice(0, 8)} + + ); + } } -export default createFragmentContainer(MergedEvent, { +export default createFragmentContainer(BareMergedEventView, { item: graphql` - fragment mergedEventContainer_item on MergedEvent { + fragment mergedEventView_item on MergedEvent { actor { avatarUrl login } diff --git a/test/views/timeline-items/merged-event-view.test.js b/test/views/timeline-items/merged-event-view.test.js new file mode 100644 index 0000000000..b66d726acf --- /dev/null +++ b/test/views/timeline-items/merged-event-view.test.js @@ -0,0 +1,63 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BareMergedEventView} from '../../../lib/views/timeline-items/merged-event-view'; + +describe('MergedEventView', function() { + function buildApp(opts, overrideProps = {}) { + const o = { + includeActor: true, + includeCommit: true, + actorLogin: 'actor', + actorAvatarUrl: 'https://avatars.com/u/100', + commitOid: '0000ffff0000ffff', + mergeRefName: 'some-ref', + ...opts, + }; + + const props = { + item: { + mergeRefName: o.mergeRefName, + createdAt: '2018-07-02T09:00:00Z', + }, + ...overrideProps, + }; + + if (o.includeActor) { + props.item.actor = { + login: o.actorLogin, + avatarUrl: o.actorAvatarUrl, + }; + } + + if (o.includeCommit) { + props.item.commit = { + oid: o.commitOid, + }; + } + + return ; + } + + it('renders event data', function() { + const wrapper = shallow(buildApp({})); + + const avatarImg = wrapper.find('img.author-avatar'); + assert.strictEqual(avatarImg.prop('src'), 'https://avatars.com/u/100'); + assert.strictEqual(avatarImg.prop('title'), 'actor'); + + assert.strictEqual(wrapper.find('.username').text(), 'actor'); + assert.strictEqual(wrapper.find('.sha').text(), '0000ffff'); + assert.strictEqual(wrapper.find('.merge-ref').text(), 'some-ref'); + + assert.strictEqual(wrapper.find('Timeago').prop('time'), '2018-07-02T09:00:00Z'); + }); + + it('renders correctly without an actor or commit', function() { + const wrapper = shallow(buildApp({includeActor: false, includeCommit: false})); + + assert.isFalse(wrapper.find('img.author-avatar').exists()); + assert.strictEqual(wrapper.find('.username').text(), 'someone'); + assert.isFalse(wrapper.find('.sha').exists()); + }); +}); From f20550dddd51ce793cf5be6909b82e37ad05bb90 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 10:24:20 -0400 Subject: [PATCH 0425/4847] HeadRefForcePushedEventView --- lib/controllers/pr-timeline-controller.js | 6 +- lib/views/issueish-timeline-view.js | 6 +- .../head-ref-force-pushed-event-view.js} | 34 ++++--- .../head-ref-force-pushed-event-view.test.js | 96 +++++++++++++++++++ 4 files changed, 123 insertions(+), 19 deletions(-) rename lib/{containers/timeline-items/head-ref-force-pushed-event-container.js => views/timeline-items/head-ref-force-pushed-event-view.js} (66%) create mode 100644 test/views/timeline-items/head-ref-force-pushed-event-view.test.js diff --git a/lib/controllers/pr-timeline-controller.js b/lib/controllers/pr-timeline-controller.js index 30e03ea485..79bc38414c 100644 --- a/lib/controllers/pr-timeline-controller.js +++ b/lib/controllers/pr-timeline-controller.js @@ -10,7 +10,7 @@ export default createPaginationContainer(IssueishTimelineView, { timelineCursor: {type: "String"} ) { url - ...headRefForcePushedEventContainer_issueish + ...headRefForcePushedEventView_issueish timeline(first: $timelineCount, after: $timelineCursor) @connection(key: "prTimelineContainer_timeline") { pageInfo { endCursor hasNextPage } edges { @@ -20,8 +20,8 @@ export default createPaginationContainer(IssueishTimelineView, { ...commitsView_nodes ...issueCommentView_item ...mergedEventView_item - ...headRefForcePushedEventContainer_item - ...commitCommentThreadContainer_item + ...headRefForcePushedEventView_item + ...commitCommentThreadView_item ...crossReferencedEventsContainer_nodes } } diff --git a/lib/views/issueish-timeline-view.js b/lib/views/issueish-timeline-view.js index 4781512bda..7ddcd47034 100644 --- a/lib/views/issueish-timeline-view.js +++ b/lib/views/issueish-timeline-view.js @@ -7,9 +7,9 @@ import Octicon from '../atom/octicon'; import CommitsView from './timeline-items/commits-view.js'; import IssueCommentView from './timeline-items/issue-comment-view.js'; import MergedEventView from './timeline-items/merged-event-view.js'; -import HeadRefForcePushedEventContainer from './../containers/timeline-items/head-ref-force-pushed-event-container.js'; +import HeadRefForcePushedEventView from './timeline-items/head-ref-force-pushed-event-view.js'; import CrossReferencedEventsContainer from './../containers/timeline-items/cross-referenced-events-container.js'; -import CommitCommentThreadView from './../views/timeline-items/commit-comment-thread-view'; +import CommitCommentThreadView from './timeline-items/commit-comment-thread-view'; export function collectionRenderer(Component, styleAsTimelineItem = true) { return class GroupedComponent extends React.Component { @@ -53,7 +53,7 @@ const timelineItems = { CommitCommentThread: collectionRenderer(CommitCommentThreadView, false), IssueComment: collectionRenderer(IssueCommentView, false), MergedEvent: collectionRenderer(MergedEventView), - HeadRefForcePushedEvent: collectionRenderer(HeadRefForcePushedEventContainer), + HeadRefForcePushedEvent: collectionRenderer(HeadRefForcePushedEventView), CrossReferencedEvent: CrossReferencedEventsContainer, }; diff --git a/lib/containers/timeline-items/head-ref-force-pushed-event-container.js b/lib/views/timeline-items/head-ref-force-pushed-event-view.js similarity index 66% rename from lib/containers/timeline-items/head-ref-force-pushed-event-container.js rename to lib/views/timeline-items/head-ref-force-pushed-event-view.js index 8cf6a0ce4b..d52de9a769 100644 --- a/lib/containers/timeline-items/head-ref-force-pushed-event-container.js +++ b/lib/views/timeline-items/head-ref-force-pushed-event-view.js @@ -3,28 +3,28 @@ import {graphql, createFragmentContainer} from 'react-relay'; import PropTypes from 'prop-types'; import Octicon from '../../atom/octicon'; -import Timeago from '../../views/timeago'; +import Timeago from '../timeago'; -export class HeadRefForcePushedEvent extends React.Component { +export class BareHeadRefForcePushedEventView extends React.Component { static propTypes = { item: PropTypes.shape({ actor: PropTypes.shape({ avatarUrl: PropTypes.string.isRequired, login: PropTypes.string.isRequired, - }).isRequired, + }), beforeCommit: PropTypes.shape({ oid: PropTypes.string.isRequired, - }).isRequired, + }), afterCommit: PropTypes.shape({ oid: PropTypes.string.isRequired, - }).isRequired, + }), createdAt: PropTypes.string.isRequired, }).isRequired, issueish: PropTypes.shape({ headRefName: PropTypes.string.isRequired, headRepositoryOwner: PropTypes.shape({ login: PropTypes.string.isRequired, - }).isRequired, + }), repository: PropTypes.shape({ owner: PropTypes.shape({ login: PropTypes.string.isRequired, @@ -40,21 +40,29 @@ export class HeadRefForcePushedEvent extends React.Component { return (
    - + {actor && } - {actor.login} force-pushed + {actor ? actor.login : 'someone'} force-pushed the {branchPrefix + headRefName} branch - from {beforeCommit.oid.slice(0, 8)} to - {' '}{afterCommit.oid.slice(0, 8)} on + from {this.renderCommit(beforeCommit, 'an old commit')} to + {' '}{this.renderCommit(afterCommit, 'a new commit')} at
    ); } + + renderCommit(commit, description) { + if (!commit) { + return description; + } + + return {commit.oid.slice(0, 8)}; + } } -export default createFragmentContainer(HeadRefForcePushedEvent, { +export default createFragmentContainer(BareHeadRefForcePushedEventView, { issueish: graphql` - fragment headRefForcePushedEventContainer_issueish on PullRequest { + fragment headRefForcePushedEventView_issueish on PullRequest { headRefName headRepositoryOwner { login } repository { owner { login } } @@ -62,7 +70,7 @@ export default createFragmentContainer(HeadRefForcePushedEvent, { `, item: graphql` - fragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent { + fragment headRefForcePushedEventView_item on HeadRefForcePushedEvent { actor { avatarUrl login } beforeCommit { oid } afterCommit { oid } diff --git a/test/views/timeline-items/head-ref-force-pushed-event-view.test.js b/test/views/timeline-items/head-ref-force-pushed-event-view.test.js new file mode 100644 index 0000000000..515779ace6 --- /dev/null +++ b/test/views/timeline-items/head-ref-force-pushed-event-view.test.js @@ -0,0 +1,96 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BareHeadRefForcePushedEventView} from '../../../lib/views/timeline-items/head-ref-force-pushed-event-view'; + +describe('HeadRefForcePushedEventView', function() { + function buildApp(opts, overrideProps = {}) { + const o = { + includeActor: true, + includeBeforeCommit: true, + includeAfterCommit: true, + actorAvatarUrl: 'https://avatars.com/u/200', + actorLogin: 'actor', + beforeCommitOid: '0000111100001111', + afterCommitOid: '0000222200002222', + createdAt: '2018-07-02T09:00:00Z', + headRefName: 'head-ref', + headRepositoryOwnerLogin: 'head-repo-owner', + repositoryOwnerLogin: 'repo-owner', + ...opts, + }; + + const props = { + item: { + actor: null, + beforeCommit: null, + afterCommit: null, + createdAt: o.createdAt, + }, + issueish: { + headRefName: o.headRefName, + headRepositoryOwner: { + login: o.headRepositoryOwnerLogin, + }, + repository: { + owner: { + login: o.repositoryOwnerLogin, + }, + }, + }, + ...overrideProps, + }; + + if (o.includeActor && !props.item.actor) { + props.item.actor = { + avatarUrl: o.actorAvatarUrl, + login: o.actorLogin, + }; + } + + if (o.includeBeforeCommit && !props.item.beforeCommit) { + props.item.beforeCommit = { + oid: o.beforeCommitOid, + }; + } + + if (o.includeAfterCommit && !props.item.afterCommit) { + props.item.afterCommit = { + oid: o.afterCommitOid, + }; + } + + return ; + } + + it('renders all event data', function() { + const wrapper = shallow(buildApp({})); + + const avatarImg = wrapper.find('img.author-avatar'); + assert.strictEqual(avatarImg.prop('src'), 'https://avatars.com/u/200'); + assert.strictEqual(avatarImg.prop('title'), 'actor'); + + assert.strictEqual(wrapper.find('.username').text(), 'actor'); + assert.match(wrapper.find('.head-ref-force-pushed-event').text(), /force-pushed the head-repo-owner:head-ref/); + assert.deepEqual(wrapper.find('.sha').map(n => n.text()), ['00001111', '00002222']); + assert.strictEqual(wrapper.find('Timeago').prop('time'), '2018-07-02T09:00:00Z'); + }); + + it('omits the branch prefix when the head and base repositories match', function() { + const wrapper = shallow(buildApp({ + headRepositoryOwnerLogin: 'same', + repositoryOwnerLogin: 'same', + })); + + assert.match(wrapper.find('.head-ref-force-pushed-event').text(), /force-pushed the head-ref/); + }); + + it('renders with a missing actor and before and after commits', function() { + const wrapper = shallow(buildApp({includeActor: false, includeBeforeCommit: false, includeAfterCommit: false})); + + assert.isFalse(wrapper.find('img.author-avatar').exists()); + assert.strictEqual(wrapper.find('.username').text(), 'someone'); + assert.isFalse(wrapper.find('.sha').exists()); + assert.match(wrapper.find('.head-ref-force-pushed-event').text(), /an old commit to a new commit/); + }); +}); From 286170c1e07e519c05fe55c944fc78c205027df4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 12:02:29 -0400 Subject: [PATCH 0426/4847] CrossReferencedEvent(s)?View --- .../commitCommentContainer_item.graphql.js | 112 ----------- ...mmitCommentThreadContainer_item.graphql.js | 112 ----------- .../commitContainer_item.graphql.js | 132 ------------- .../commitsContainer_nodes.graphql.js | 89 --------- ...ssReferencedEventContainer_item.graphql.js | 179 ------------------ ...ReferencedEventsContainer_nodes.graphql.js | 152 --------------- ...cePushedEventContainer_issueish.graphql.js | 88 --------- ...fForcePushedEventContainer_item.graphql.js | 104 ---------- .../issueCommentContainer_item.graphql.js | 75 -------- .../mergedEventContainer_item.graphql.js | 96 ---------- lib/controllers/issue-timeline-controller.js | 2 +- lib/controllers/pr-timeline-controller.js | 2 +- lib/views/issueish-timeline-view.js | 4 +- .../commit-comment-thread-view.js | 4 +- .../cross-referenced-event-view.js} | 17 +- .../cross-referenced-events-view.js} | 32 ++-- .../cross-referenced-event-result.js | 64 +++++++ .../cross-referenced-event-view.test.js | 55 ++++++ .../cross-referenced-events-view.test.js | 90 +++++++++ 19 files changed, 237 insertions(+), 1172 deletions(-) delete mode 100644 lib/containers/timeline-items/__generated__/commitCommentContainer_item.graphql.js delete mode 100644 lib/containers/timeline-items/__generated__/commitCommentThreadContainer_item.graphql.js delete mode 100644 lib/containers/timeline-items/__generated__/commitContainer_item.graphql.js delete mode 100644 lib/containers/timeline-items/__generated__/commitsContainer_nodes.graphql.js delete mode 100644 lib/containers/timeline-items/__generated__/crossReferencedEventContainer_item.graphql.js delete mode 100644 lib/containers/timeline-items/__generated__/crossReferencedEventsContainer_nodes.graphql.js delete mode 100644 lib/containers/timeline-items/__generated__/headRefForcePushedEventContainer_issueish.graphql.js delete mode 100644 lib/containers/timeline-items/__generated__/headRefForcePushedEventContainer_item.graphql.js delete mode 100644 lib/containers/timeline-items/__generated__/issueCommentContainer_item.graphql.js delete mode 100644 lib/containers/timeline-items/__generated__/mergedEventContainer_item.graphql.js rename lib/{containers/timeline-items/cross-referenced-event-container.js => views/timeline-items/cross-referenced-event-view.js} (83%) rename lib/{containers/timeline-items/cross-referenced-events-container.js => views/timeline-items/cross-referenced-events-view.js} (72%) create mode 100644 test/fixtures/factories/cross-referenced-event-result.js create mode 100644 test/views/timeline-items/cross-referenced-event-view.test.js create mode 100644 test/views/timeline-items/cross-referenced-events-view.test.js diff --git a/lib/containers/timeline-items/__generated__/commitCommentContainer_item.graphql.js b/lib/containers/timeline-items/__generated__/commitCommentContainer_item.graphql.js deleted file mode 100644 index 9f6bc7ac9b..0000000000 --- a/lib/containers/timeline-items/__generated__/commitCommentContainer_item.graphql.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type commitCommentContainer_item$ref: FragmentReference; -export type commitCommentContainer_item = {| - +author: ?{| - +login: string, - +avatarUrl: any, - |}, - +commit: ?{| - +oid: any - |}, - +bodyHTML: any, - +createdAt: any, - +path: ?string, - +position: ?number, - +$refType: commitCommentContainer_item$ref, -|}; -*/ - - -const node/*: ConcreteFragment*/ = { - "kind": "Fragment", - "name": "commitCommentContainer_item", - "type": "CommitComment", - "metadata": null, - "argumentDefinitions": [], - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "oid", - "args": null, - "storageKey": null - } - ] - }, - { - "kind": "ScalarField", - "alias": null, - "name": "bodyHTML", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "path", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "position", - "args": null, - "storageKey": null - } - ] -}; -// prettier-ignore -(node/*: any*/).hash = '216f58bfc441dffdedf7a42038aa9caf'; -module.exports = node; diff --git a/lib/containers/timeline-items/__generated__/commitCommentThreadContainer_item.graphql.js b/lib/containers/timeline-items/__generated__/commitCommentThreadContainer_item.graphql.js deleted file mode 100644 index 5097220916..0000000000 --- a/lib/containers/timeline-items/__generated__/commitCommentThreadContainer_item.graphql.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -type commitCommentContainer_item$ref = any; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type commitCommentThreadContainer_item$ref: FragmentReference; -export type commitCommentThreadContainer_item = {| - +commit: {| - +oid: any - |}, - +comments: {| - +edges: ?$ReadOnlyArray - |}, - +$refType: commitCommentThreadContainer_item$ref, -|}; -*/ - - -const node/*: ConcreteFragment*/ = { - "kind": "Fragment", - "name": "commitCommentThreadContainer_item", - "type": "CommitCommentThread", - "metadata": null, - "argumentDefinitions": [], - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "oid", - "args": null, - "storageKey": null - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "comments", - "storageKey": "comments(first:100)", - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 100, - "type": "Int" - } - ], - "concreteType": "CommitCommentConnection", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "edges", - "storageKey": null, - "args": null, - "concreteType": "CommitCommentEdge", - "plural": true, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "node", - "storageKey": null, - "args": null, - "concreteType": "CommitComment", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null - }, - { - "kind": "FragmentSpread", - "name": "commitCommentContainer_item", - "args": null - } - ] - } - ] - } - ] - } - ] -}; -// prettier-ignore -(node/*: any*/).hash = '03b9b3efb7a1c1fc0ed3831c4cbb1717'; -module.exports = node; diff --git a/lib/containers/timeline-items/__generated__/commitContainer_item.graphql.js b/lib/containers/timeline-items/__generated__/commitContainer_item.graphql.js deleted file mode 100644 index 6f8a75d3dd..0000000000 --- a/lib/containers/timeline-items/__generated__/commitContainer_item.graphql.js +++ /dev/null @@ -1,132 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type commitContainer_item$ref: FragmentReference; -export type commitContainer_item = {| - +author: ?{| - +name: ?string, - +avatarUrl: any, - +user: ?{| - +login: string - |}, - |}, - +committer: ?{| - +name: ?string, - +avatarUrl: any, - +user: ?{| - +login: string - |}, - |}, - +authoredByCommitter: boolean, - +oid: any, - +message: string, - +messageHeadlineHTML: any, - +$refType: commitContainer_item$ref, -|}; -*/ - - -const node/*: ConcreteFragment*/ = (function(){ -var v0 = [ - { - "kind": "ScalarField", - "alias": null, - "name": "name", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "user", - "storageKey": null, - "args": null, - "concreteType": "User", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null - } - ] - } -]; -return { - "kind": "Fragment", - "name": "commitContainer_item", - "type": "Commit", - "metadata": null, - "argumentDefinitions": [], - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": "GitActor", - "plural": false, - "selections": v0 - }, - { - "kind": "LinkedField", - "alias": null, - "name": "committer", - "storageKey": null, - "args": null, - "concreteType": "GitActor", - "plural": false, - "selections": v0 - }, - { - "kind": "ScalarField", - "alias": null, - "name": "authoredByCommitter", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "oid", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "message", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "messageHeadlineHTML", - "args": null, - "storageKey": null - } - ] -}; -})(); -// prettier-ignore -(node/*: any*/).hash = 'fdf46513f47aeb1dbcaa568912e94880'; -module.exports = node; diff --git a/lib/containers/timeline-items/__generated__/commitsContainer_nodes.graphql.js b/lib/containers/timeline-items/__generated__/commitsContainer_nodes.graphql.js deleted file mode 100644 index 61ec121f3d..0000000000 --- a/lib/containers/timeline-items/__generated__/commitsContainer_nodes.graphql.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -type commitContainer_item$ref = any; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type commitsContainer_nodes$ref: FragmentReference; -export type commitsContainer_nodes = $ReadOnlyArray<{| - +id: string, - +author: ?{| - +name: ?string, - +user: ?{| - +login: string - |}, - |}, - +$fragmentRefs: commitContainer_item$ref, - +$refType: commitsContainer_nodes$ref, -|}>; -*/ - - -const node/*: ConcreteFragment*/ = { - "kind": "Fragment", - "name": "commitsContainer_nodes", - "type": "Commit", - "metadata": { - "plural": true - }, - "argumentDefinitions": [], - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": "GitActor", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "name", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "user", - "storageKey": null, - "args": null, - "concreteType": "User", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null - } - ] - } - ] - }, - { - "kind": "FragmentSpread", - "name": "commitContainer_item", - "args": null - } - ] -}; -// prettier-ignore -(node/*: any*/).hash = '78a12a58f4b4be13e743e096ced0ea65'; -module.exports = node; diff --git a/lib/containers/timeline-items/__generated__/crossReferencedEventContainer_item.graphql.js b/lib/containers/timeline-items/__generated__/crossReferencedEventContainer_item.graphql.js deleted file mode 100644 index a8a2ee3110..0000000000 --- a/lib/containers/timeline-items/__generated__/crossReferencedEventContainer_item.graphql.js +++ /dev/null @@ -1,179 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -export type IssueState = "CLOSED" | "OPEN" | "%future added value"; -export type PullRequestState = "CLOSED" | "MERGED" | "OPEN" | "%future added value"; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type crossReferencedEventContainer_item$ref: FragmentReference; -export type crossReferencedEventContainer_item = {| - +id: string, - +isCrossRepository: boolean, - +source: {| - +__typename: string, - +repository?: {| - +name: string, - +isPrivate: boolean, - +owner: {| - +login: string - |}, - |}, - +number?: number, - +title?: string, - +url?: any, - +issueState?: IssueState, - +prState?: PullRequestState, - |}, - +$refType: crossReferencedEventContainer_item$ref, -|}; -*/ - - -const node/*: ConcreteFragment*/ = (function(){ -var v0 = { - "kind": "ScalarField", - "alias": null, - "name": "number", - "args": null, - "storageKey": null -}, -v1 = { - "kind": "ScalarField", - "alias": null, - "name": "title", - "args": null, - "storageKey": null -}, -v2 = { - "kind": "ScalarField", - "alias": null, - "name": "url", - "args": null, - "storageKey": null -}; -return { - "kind": "Fragment", - "name": "crossReferencedEventContainer_item", - "type": "CrossReferencedEvent", - "metadata": null, - "argumentDefinitions": [], - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "isCrossRepository", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "source", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "__typename", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "repository", - "storageKey": null, - "args": null, - "concreteType": "Repository", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "name", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "isPrivate", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "owner", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null - } - ] - } - ] - }, - { - "kind": "InlineFragment", - "type": "PullRequest", - "selections": [ - v0, - v1, - v2, - { - "kind": "ScalarField", - "alias": "prState", - "name": "state", - "args": null, - "storageKey": null - } - ] - }, - { - "kind": "InlineFragment", - "type": "Issue", - "selections": [ - v0, - v1, - v2, - { - "kind": "ScalarField", - "alias": "issueState", - "name": "state", - "args": null, - "storageKey": null - } - ] - } - ] - } - ] -}; -})(); -// prettier-ignore -(node/*: any*/).hash = 'e5545cc9fa40175078d84db718798211'; -module.exports = node; diff --git a/lib/containers/timeline-items/__generated__/crossReferencedEventsContainer_nodes.graphql.js b/lib/containers/timeline-items/__generated__/crossReferencedEventsContainer_nodes.graphql.js deleted file mode 100644 index 4c1669bb53..0000000000 --- a/lib/containers/timeline-items/__generated__/crossReferencedEventsContainer_nodes.graphql.js +++ /dev/null @@ -1,152 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -type crossReferencedEventContainer_item$ref = any; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type crossReferencedEventsContainer_nodes$ref: FragmentReference; -export type crossReferencedEventsContainer_nodes = $ReadOnlyArray<{| - +id: string, - +referencedAt: any, - +isCrossRepository: boolean, - +actor: ?{| - +login: string, - +avatarUrl: any, - |}, - +source: {| - +__typename: string, - +repository?: {| - +name: string, - +owner: {| - +login: string - |}, - |}, - |}, - +$fragmentRefs: crossReferencedEventContainer_item$ref, - +$refType: crossReferencedEventsContainer_nodes$ref, -|}>; -*/ - - -const node/*: ConcreteFragment*/ = (function(){ -var v0 = { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null -}; -return { - "kind": "Fragment", - "name": "crossReferencedEventsContainer_nodes", - "type": "CrossReferencedEvent", - "metadata": { - "plural": true - }, - "argumentDefinitions": [], - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "referencedAt", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "isCrossRepository", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "actor", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v0, - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "source", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "__typename", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "repository", - "storageKey": null, - "args": null, - "concreteType": "Repository", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "name", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "owner", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v0 - ] - } - ] - } - ] - }, - { - "kind": "FragmentSpread", - "name": "crossReferencedEventContainer_item", - "args": null - } - ] -}; -})(); -// prettier-ignore -(node/*: any*/).hash = 'd431ba25343ab1bf40cd18887625de30'; -module.exports = node; diff --git a/lib/containers/timeline-items/__generated__/headRefForcePushedEventContainer_issueish.graphql.js b/lib/containers/timeline-items/__generated__/headRefForcePushedEventContainer_issueish.graphql.js deleted file mode 100644 index 7acd493d23..0000000000 --- a/lib/containers/timeline-items/__generated__/headRefForcePushedEventContainer_issueish.graphql.js +++ /dev/null @@ -1,88 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type headRefForcePushedEventContainer_issueish$ref: FragmentReference; -export type headRefForcePushedEventContainer_issueish = {| - +headRefName: string, - +headRepositoryOwner: ?{| - +login: string - |}, - +repository: {| - +owner: {| - +login: string - |} - |}, - +$refType: headRefForcePushedEventContainer_issueish$ref, -|}; -*/ - - -const node/*: ConcreteFragment*/ = (function(){ -var v0 = [ - { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null - } -]; -return { - "kind": "Fragment", - "name": "headRefForcePushedEventContainer_issueish", - "type": "PullRequest", - "metadata": null, - "argumentDefinitions": [], - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "headRefName", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "headRepositoryOwner", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": v0 - }, - { - "kind": "LinkedField", - "alias": null, - "name": "repository", - "storageKey": null, - "args": null, - "concreteType": "Repository", - "plural": false, - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "owner", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": v0 - } - ] - } - ] -}; -})(); -// prettier-ignore -(node/*: any*/).hash = '65fdbfd9990a45ef17e4becff0cf2071'; -module.exports = node; diff --git a/lib/containers/timeline-items/__generated__/headRefForcePushedEventContainer_item.graphql.js b/lib/containers/timeline-items/__generated__/headRefForcePushedEventContainer_item.graphql.js deleted file mode 100644 index 69df138576..0000000000 --- a/lib/containers/timeline-items/__generated__/headRefForcePushedEventContainer_item.graphql.js +++ /dev/null @@ -1,104 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type headRefForcePushedEventContainer_item$ref: FragmentReference; -export type headRefForcePushedEventContainer_item = {| - +actor: ?{| - +avatarUrl: any, - +login: string, - |}, - +beforeCommit: ?{| - +oid: any - |}, - +afterCommit: ?{| - +oid: any - |}, - +createdAt: any, - +$refType: headRefForcePushedEventContainer_item$ref, -|}; -*/ - - -const node/*: ConcreteFragment*/ = (function(){ -var v0 = [ - { - "kind": "ScalarField", - "alias": null, - "name": "oid", - "args": null, - "storageKey": null - } -]; -return { - "kind": "Fragment", - "name": "headRefForcePushedEventContainer_item", - "type": "HeadRefForcePushedEvent", - "metadata": null, - "argumentDefinitions": [], - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "actor", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "beforeCommit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v0 - }, - { - "kind": "LinkedField", - "alias": null, - "name": "afterCommit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v0 - }, - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - } - ] -}; -})(); -// prettier-ignore -(node/*: any*/).hash = 'da2dd156c4d8c274cb835b34b2c2ddcd'; -module.exports = node; diff --git a/lib/containers/timeline-items/__generated__/issueCommentContainer_item.graphql.js b/lib/containers/timeline-items/__generated__/issueCommentContainer_item.graphql.js deleted file mode 100644 index 01031b0ea8..0000000000 --- a/lib/containers/timeline-items/__generated__/issueCommentContainer_item.graphql.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type issueCommentContainer_item$ref: FragmentReference; -export type issueCommentContainer_item = {| - +author: ?{| - +avatarUrl: any, - +login: string, - |}, - +bodyHTML: any, - +createdAt: any, - +$refType: issueCommentContainer_item$ref, -|}; -*/ - - -const node/*: ConcreteFragment*/ = { - "kind": "Fragment", - "name": "issueCommentContainer_item", - "type": "IssueComment", - "metadata": null, - "argumentDefinitions": [], - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null - } - ] - }, - { - "kind": "ScalarField", - "alias": null, - "name": "bodyHTML", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - } - ] -}; -// prettier-ignore -(node/*: any*/).hash = '3076203f6fb038831251a85865bf9182'; -module.exports = node; diff --git a/lib/containers/timeline-items/__generated__/mergedEventContainer_item.graphql.js b/lib/containers/timeline-items/__generated__/mergedEventContainer_item.graphql.js deleted file mode 100644 index 86948f1dfc..0000000000 --- a/lib/containers/timeline-items/__generated__/mergedEventContainer_item.graphql.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * @flow - */ - -/* eslint-disable */ - -'use strict'; - -/*:: -import type { ConcreteFragment } from 'relay-runtime'; -import type { FragmentReference } from "relay-runtime"; -declare export opaque type mergedEventContainer_item$ref: FragmentReference; -export type mergedEventContainer_item = {| - +actor: ?{| - +avatarUrl: any, - +login: string, - |}, - +commit: ?{| - +oid: any - |}, - +mergeRefName: string, - +createdAt: any, - +$refType: mergedEventContainer_item$ref, -|}; -*/ - - -const node/*: ConcreteFragment*/ = { - "kind": "Fragment", - "name": "mergedEventContainer_item", - "type": "MergedEvent", - "metadata": null, - "argumentDefinitions": [], - "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "actor", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null - } - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "oid", - "args": null, - "storageKey": null - } - ] - }, - { - "kind": "ScalarField", - "alias": null, - "name": "mergeRefName", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - } - ] -}; -// prettier-ignore -(node/*: any*/).hash = 'd12a40dca27e3ccc4a1d72399b836784'; -module.exports = node; diff --git a/lib/controllers/issue-timeline-controller.js b/lib/controllers/issue-timeline-controller.js index 652327a0b1..9afec57f2b 100644 --- a/lib/controllers/issue-timeline-controller.js +++ b/lib/controllers/issue-timeline-controller.js @@ -20,7 +20,7 @@ export default createPaginationContainer(IssueishTimelineView, { __typename ...commitsView_nodes ...issueCommentView_item - ...crossReferencedEventsContainer_nodes + ...crossReferencedEventsView_nodes } } } diff --git a/lib/controllers/pr-timeline-controller.js b/lib/controllers/pr-timeline-controller.js index 79bc38414c..4cb15c6b2d 100644 --- a/lib/controllers/pr-timeline-controller.js +++ b/lib/controllers/pr-timeline-controller.js @@ -22,7 +22,7 @@ export default createPaginationContainer(IssueishTimelineView, { ...mergedEventView_item ...headRefForcePushedEventView_item ...commitCommentThreadView_item - ...crossReferencedEventsContainer_nodes + ...crossReferencedEventsView_nodes } } } diff --git a/lib/views/issueish-timeline-view.js b/lib/views/issueish-timeline-view.js index 7ddcd47034..4563791168 100644 --- a/lib/views/issueish-timeline-view.js +++ b/lib/views/issueish-timeline-view.js @@ -8,7 +8,7 @@ import CommitsView from './timeline-items/commits-view.js'; import IssueCommentView from './timeline-items/issue-comment-view.js'; import MergedEventView from './timeline-items/merged-event-view.js'; import HeadRefForcePushedEventView from './timeline-items/head-ref-force-pushed-event-view.js'; -import CrossReferencedEventsContainer from './../containers/timeline-items/cross-referenced-events-container.js'; +import CrossReferencedEventsView from './timeline-items/cross-referenced-events-view.js'; import CommitCommentThreadView from './timeline-items/commit-comment-thread-view'; export function collectionRenderer(Component, styleAsTimelineItem = true) { @@ -54,7 +54,7 @@ const timelineItems = { IssueComment: collectionRenderer(IssueCommentView, false), MergedEvent: collectionRenderer(MergedEventView), HeadRefForcePushedEvent: collectionRenderer(HeadRefForcePushedEventView), - CrossReferencedEvent: CrossReferencedEventsContainer, + CrossReferencedEvent: CrossReferencedEventsView, }; const TimelineConnectionPropType = RelayConnectionPropType( diff --git a/lib/views/timeline-items/commit-comment-thread-view.js b/lib/views/timeline-items/commit-comment-thread-view.js index d731ffe07a..7b7d988e5e 100644 --- a/lib/views/timeline-items/commit-comment-thread-view.js +++ b/lib/views/timeline-items/commit-comment-thread-view.js @@ -2,7 +2,7 @@ import React from 'react'; import {graphql, createFragmentContainer} from 'react-relay'; import PropTypes from 'prop-types'; -import CommitCommentContainer from '../../views/timeline-items/commit-comment-view'; +import CommitCommentView from './commit-comment-view'; export class BareCommitCommentThreadView extends React.Component { static propTypes = { @@ -26,7 +26,7 @@ export class BareCommitCommentThreadView extends React.Component { return (
    {item.comments.edges.map((edge, i) => ( -
    -
    - {xref.source.repository.isPrivate ? - : ''} -
    + {repo.isPrivate + ? ( +
    + +
    + ) : ''}
    @@ -65,9 +66,9 @@ export class CrossReferencedEvent extends React.Component { } -export default createFragmentContainer(CrossReferencedEvent, { +export default createFragmentContainer(BareCrossReferencedEventView, { item: graphql` - fragment crossReferencedEventContainer_item on CrossReferencedEvent { + fragment crossReferencedEventView_item on CrossReferencedEvent { id isCrossRepository source { __typename diff --git a/lib/containers/timeline-items/cross-referenced-events-container.js b/lib/views/timeline-items/cross-referenced-events-view.js similarity index 72% rename from lib/containers/timeline-items/cross-referenced-events-container.js rename to lib/views/timeline-items/cross-referenced-events-view.js index 8e7134cfae..df39cc85e4 100644 --- a/lib/containers/timeline-items/cross-referenced-events-container.js +++ b/lib/views/timeline-items/cross-referenced-events-view.js @@ -4,9 +4,9 @@ import PropTypes from 'prop-types'; import Octicon from '../../atom/octicon'; import Timeago from '../../views/timeago'; -import CrossReferencedEventContainer from './cross-referenced-event-container'; +import CrossReferencedEventView from './cross-referenced-event-view'; -export class CrossReferencedEvents extends React.Component { +export class BareCrossReferencedEventsView extends React.Component { static propTypes = { nodes: PropTypes.arrayOf( PropTypes.shape({ @@ -16,7 +16,7 @@ export class CrossReferencedEvents extends React.Component { actor: PropTypes.shape({ avatarUrl: PropTypes.string.isRequired, login: PropTypes.string.isRequired, - }).isRequired, + }), source: PropTypes.shape({ __typename: PropTypes.oneOf(['Issue', 'PullRequest']).isRequired, repository: PropTypes.shape({ @@ -49,17 +49,10 @@ export class CrossReferencedEvents extends React.Component { if (this.props.nodes.length > 1) { return This was referenced ; } else { - let type = null; - switch (first.source.__typename) { - case 'PullRequest': - type = 'pull request'; - break; - case 'Issue': - type = 'issue'; - break; - default: - throw new Error(`Invalid type: ${first.source.__typename}`); - } + const type = { + PullRequest: 'a pull request', + Issue: 'an issue', + }[first.source.__typename]; let xrefClause = ''; if (first.isCrossRepository) { const repo = first.source.repository; @@ -70,7 +63,8 @@ export class CrossReferencedEvents extends React.Component { return ( - {first.actor.login} referenced this {type} {xrefClause} + {first.actor.login} referenced this from {type} {xrefClause} + ); } @@ -78,15 +72,15 @@ export class CrossReferencedEvents extends React.Component { renderEvents() { return this.props.nodes.map(node => { - return ; + return ; }); } } -export default createFragmentContainer(CrossReferencedEvents, { +export default createFragmentContainer(BareCrossReferencedEventsView, { nodes: graphql` - fragment crossReferencedEventsContainer_nodes on CrossReferencedEvent @relay(plural: true) { + fragment crossReferencedEventsView_nodes on CrossReferencedEvent @relay(plural: true) { id referencedAt isCrossRepository actor { login avatarUrl } source { @@ -97,7 +91,7 @@ export default createFragmentContainer(CrossReferencedEvents, { } } } - ...crossReferencedEventContainer_item + ...crossReferencedEventView_item } `, }); diff --git a/test/fixtures/factories/cross-referenced-event-result.js b/test/fixtures/factories/cross-referenced-event-result.js new file mode 100644 index 0000000000..b07a2188bc --- /dev/null +++ b/test/fixtures/factories/cross-referenced-event-result.js @@ -0,0 +1,64 @@ +import IDGenerator from './id-generator'; + +export function createCrossReferencedEventResult(opts) { + const idGen = IDGenerator.fromOpts(opts); + + const o = { + id: idGen.generate('xref'), + includeActor: true, + isCrossRepository: true, + isPullRequest: true, + referencedAt: '2018-07-02T09:00:00Z', + number: 1, + title: 'title', + actorLogin: 'actor', + actorAvatarUrl: 'https://avatars.com/u/300', + repositoryName: 'repo', + repositoryIsPrivate: false, + repositoryOwnerLogin: 'owner', + ...opts, + }; + + if (o.isPullRequest) { + if (!o.url) { + o.url = `https://github.com/${o.repositoryOwnerLogin}/${o.repositoryName}/pulls/${o.number}`; + } + + if (!o.prState) { + o.prState = 'OPEN'; + } + } else { + if (!o.url) { + o.url = `https://github.com/${o.repositoryOwnerLogin}/${o.repositoryName}/issues/${o.number}`; + } + + if (!o.issueState) { + o.issueState = 'OPEN'; + } + } + + return { + id: o.id, + referencedAt: o.referencedAt, + isCrossRepository: o.isCrossRepository, + actor: !o.includeActor ? null : { + avatarUrl: o.actorAvatarUrl, + login: o.actorLogin, + }, + source: { + __typename: o.isPullRequest ? 'PullRequest' : 'Issue', + number: o.number, + title: o.title, + url: o.url, + issueState: o.issueState, + prState: o.prState, + repository: { + isPrivate: o.repositoryIsPrivate, + owner: { + login: o.repositoryOwnerLogin, + }, + name: o.repositoryName, + }, + }, + }; +}; diff --git a/test/views/timeline-items/cross-referenced-event-view.test.js b/test/views/timeline-items/cross-referenced-event-view.test.js new file mode 100644 index 0000000000..e745b31246 --- /dev/null +++ b/test/views/timeline-items/cross-referenced-event-view.test.js @@ -0,0 +1,55 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BareCrossReferencedEventView} from '../../../lib/views/timeline-items/cross-referenced-event-view'; +import {createCrossReferencedEventResult} from '../../fixtures/factories/cross-referenced-event-result'; + +describe('CrossReferencedEventView', function() { + function buildApp(opts) { + return ; + } + + it('renders cross-reference data for a cross-repository reference', function() { + const wrapper = shallow(buildApp({ + isCrossRepository: true, + number: 5, + title: 'the title', + url: 'https://github.com/aaa/bbb/pulls/5', + repositoryName: 'repo', + repositoryOwnerLogin: 'owner', + prState: 'MERGED', + })); + + assert.strictEqual(wrapper.find('.cross-referenced-event-label-title').text(), 'the title'); + + const link = wrapper.find('IssueishLink'); + assert.strictEqual(link.prop('url'), 'https://github.com/aaa/bbb/pulls/5'); + assert.strictEqual(link.children().text(), 'owner/repo#5'); + + assert.isFalse(wrapper.find('.cross-referenced-event-private').exists()); + + const badge = wrapper.find('IssueishBadge'); + assert.strictEqual(badge.prop('type'), 'PullRequest'); + assert.strictEqual(badge.prop('state'), 'MERGED'); + }); + + it('renders a shorter issueish reference number for intra-repository references', function() { + const wrapper = shallow(buildApp({ + isCrossRepository: false, + number: 6, + url: 'https://github.com/aaa/bbb/pulls/6', + })); + + const link = wrapper.find('IssueishLink'); + assert.strictEqual(link.prop('url'), 'https://github.com/aaa/bbb/pulls/6'); + assert.strictEqual(link.children().text(), '#6'); + }); + + it('renders a lock on references from private sources', function() { + const wrapper = shallow(buildApp({ + repositoryIsPrivate: true, + })); + + assert.isTrue(wrapper.find('.cross-referenced-event-private Octicon[icon="lock"]')); + }); +}); diff --git a/test/views/timeline-items/cross-referenced-events-view.test.js b/test/views/timeline-items/cross-referenced-events-view.test.js new file mode 100644 index 0000000000..4834306516 --- /dev/null +++ b/test/views/timeline-items/cross-referenced-events-view.test.js @@ -0,0 +1,90 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BareCrossReferencedEventsView} from '../../../lib/views/timeline-items/cross-referenced-events-view'; +import {createCrossReferencedEventResult} from '../../fixtures/factories/cross-referenced-event-result'; + +describe('CrossReferencedEventsView', function() { + function buildApp(opts) { + return ( + + ); + } + + it('renders a child component for each grouped child event', function() { + const wrapper = shallow(buildApp({nodeOpts: [{}, {}, {}]})); + assert.lengthOf(wrapper.find('Relay(BareCrossReferencedEventView)'), 3); + }); + + it('generates a summary based on a single pull request cross-reference', function() { + const wrapper = shallow(buildApp({ + nodeOpts: [ + { + includeActor: true, + isPullRequest: true, + isCrossRepository: true, + actorLogin: 'me', + actorAvatarUrl: 'https://avatars.com/u/1', + repositoryOwnerLogin: 'aaa', + repositoryName: 'bbb', + referencedAt: '2018-07-02T09:00:00Z', + }, + ], + })); + + const avatarImg = wrapper.find('img.author-avatar'); + assert.strictEqual(avatarImg.prop('src'), 'https://avatars.com/u/1'); + assert.strictEqual(avatarImg.prop('title'), 'me'); + + assert.strictEqual(wrapper.find('strong').at(0).text(), 'me'); + + assert.isTrue( + wrapper.find('span').someWhere(s => /referenced this from a pull request in aaa\/bbb/.test(s.text())), + ); + + assert.strictEqual(wrapper.find('Timeago').prop('time'), '2018-07-02T09:00:00Z'); + }); + + it('generates a summary based on a single issue cross-reference', function() { + const wrapper = shallow(buildApp({ + nodeOpts: [ + { + isPullRequest: false, + isCrossRepository: true, + actorLogin: 'you', + actorAvatarUrl: 'https://avatars.com/u/2', + repositoryOwnerLogin: 'ccc', + repositoryName: 'ddd', + }, + ], + })); + + const avatarImg = wrapper.find('img.author-avatar'); + assert.strictEqual(avatarImg.prop('src'), 'https://avatars.com/u/2'); + assert.strictEqual(avatarImg.prop('title'), 'you'); + + assert.strictEqual(wrapper.find('strong').at(0).text(), 'you'); + + assert.isTrue( + wrapper.find('span').someWhere(s => /referenced this from an issue in ccc\/ddd/.test(s.text())), + ); + }); + + it('omits the head repository blurb if the reference is not cross-repository', function() { + const wrapper = shallow(buildApp({ + nodeOpts: [ + { + isCrossRepository: false, + repositoryOwnerLogin: 'ccc', + repositoryName: 'ddd', + }, + ], + })); + + assert.isFalse( + wrapper.find('span').someWhere(s => /in ccc\/ddd/.test(s.text())), + ); + }); +}); From 38e27226428940ea0457038ba8639639ed3d1eed Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 15:11:57 -0400 Subject: [PATCH 0427/4847] Tests for GithubDotcomMarkdown --- lib/views/github-dotcom-markdown.js | 35 +++----- test/views/github-dotcom-markdown.test.js | 104 ++++++++++++++++++++++ 2 files changed, 116 insertions(+), 23 deletions(-) create mode 100644 test/views/github-dotcom-markdown.test.js diff --git a/lib/views/github-dotcom-markdown.js b/lib/views/github-dotcom-markdown.js index 8900ed423a..6d5e3d136e 100644 --- a/lib/views/github-dotcom-markdown.js +++ b/lib/views/github-dotcom-markdown.js @@ -11,13 +11,17 @@ import {autobind} from '../helpers'; export default class GithubDotcomMarkdown extends React.Component { static propTypes = { - html: PropTypes.string, - markdown: PropTypes.string, + html: PropTypes.string.isRequired, switchToIssueish: PropTypes.func.isRequired, + handleClickEvent: PropTypes.func, + openIssueishLinkInNewTab: PropTypes.func, + openLinkInBrowser: PropTypes.func, } - static contextTypes = { - relayEnvironment: PropTypes.object.isRequired, + static defaultProps = { + handleClickEvent, + openIssueishLinkInNewTab, + openLinkInBrowser, } constructor(props) { @@ -31,23 +35,14 @@ export default class GithubDotcomMarkdown extends React.Component { 'github:open-link-in-browser': this.openLinkInBrowser, 'github:open-link-in-this-tab': this.openLinkInThisTab, }); - this.checkPropValidity(); this.setupComponentHandlers(); this.setupTooltipHandlers(); } componentDidUpdate() { - this.checkPropValidity(); this.setupTooltipHandlers(); } - checkPropValidity() { - if (this.props.html !== undefined && this.props.markdown !== undefined) { - // eslint-disable-next-line no-console - console.error('Only one of `html` or `markdown` may be provided to `GithubDotcomMarkdown`'); - } - } - setupComponentHandlers() { this.component.addEventListener('click', this.handleClick); this.componentHandlers = new Disposable(() => { @@ -88,29 +83,23 @@ export default class GithubDotcomMarkdown extends React.Component { } render() { - const {html, markdown} = this.props; - const renderedHtml = html !== undefined ? html : this.markdownToHtml(markdown); return (
    { this.component = c; }} - dangerouslySetInnerHTML={{__html: renderedHtml}} + dangerouslySetInnerHTML={{__html: this.props.html}} /> ); } - markdownToHtml(markdown = '') { - return 'WARNING: cannot yet convert markdown to HTML 😅'; - } - handleClick(event) { if (event.target.dataset.url) { - handleClickEvent(event, event.target.dataset.url); + this.props.handleClickEvent(event, event.target.dataset.url); } } openLinkInNewTab(event) { - return openIssueishLinkInNewTab(event.target.dataset.url); + return this.props.openIssueishLinkInNewTab(event.target.dataset.url); } openLinkInThisTab(event) { @@ -119,6 +108,6 @@ export default class GithubDotcomMarkdown extends React.Component { } openLinkInBrowser(event) { - return openLinkInBrowser(event.target.getAttribute('href')); + return this.props.openLinkInBrowser(event.target.getAttribute('href')); } } diff --git a/test/views/github-dotcom-markdown.test.js b/test/views/github-dotcom-markdown.test.js new file mode 100644 index 0000000000..d198e43086 --- /dev/null +++ b/test/views/github-dotcom-markdown.test.js @@ -0,0 +1,104 @@ +import React from 'react'; +import {mount} from 'enzyme'; + +import GithubDotcomMarkdown from '../../lib/views/github-dotcom-markdown'; + +describe('GithubDotcomMarkdown', function() { + function buildApp(overloadProps = {}) { + return ( + content

    '} + switchToIssueish={() => {}} + handleClickEvent={() => {}} + openIssueishLinkInNewTab={() => {}} + openLinkInBrowser={() => {}} + {...overloadProps} + /> + ); + } + + it('embeds pre-rendered markdown into a div', function() { + const wrapper = mount(buildApp({ + html: '
    something
    ', + })); + + assert.include(wrapper.find('.github-DotComMarkdownHtml').html(), '
    something
    '); + }); + + it('intercepts click events on issueish links', function() { + const handleClickEvent = sinon.stub(); + + const wrapper = mount(buildApp({ + html: ` +

    + This text has + + an issueish link + + and + + a non-issuish link + + and + + a user mention + + in it +

    + `, + handleClickEvent, + })); + + wrapper.update(); + + const issueishLink = wrapper.getDOMNode().querySelector('a.issue-link'); + issueishLink.dispatchEvent(new MouseEvent('click', { + bubbles: true, + cancelable: true, + })); + + assert.strictEqual(handleClickEvent.callCount, 1); + + const nonIssueishLink = wrapper.getDOMNode().querySelector('a.other'); + nonIssueishLink.dispatchEvent(new MouseEvent('click', { + bubbles: true, + cancelable: true, + })); + + assert.strictEqual(handleClickEvent.callCount, 1); + + wrapper.unmount(); + }); + + it('registers command handlers', function() { + const openIssueishLinkInNewTab = sinon.stub(); + const openLinkInBrowser = sinon.stub(); + const switchToIssueish = sinon.stub(); + + const wrapper = mount(buildApp({ + html: ` +

    + #123 +

    + `, + openIssueishLinkInNewTab, + openLinkInBrowser, + switchToIssueish, + })); + + const link = wrapper.getDOMNode().querySelector('a'); + const href = 'https://github.com/aaa/bbb/issue/123'; + + atom.commands.dispatch(link, 'github:open-link-in-new-tab'); + assert.isTrue(openIssueishLinkInNewTab.calledWith(href)); + + atom.commands.dispatch(link, 'github:open-link-in-this-tab'); + assert.isTrue(switchToIssueish.calledWith('aaa', 'bbb', 123)); + + atom.commands.dispatch(link, 'github:open-link-in-browser'); + assert.isTrue(openLinkInBrowser.calledWith(href)); + }); +}); From 147e2e9a741367f539781db382e6497edb46f17e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 15:40:10 -0400 Subject: [PATCH 0428/4847] Re-generate Relay fragments --- .../issueishDetailContainerQuery.graphql.js | 68 +++---- .../issueTimelineControllerQuery.graphql.js} | 50 ++--- .../issueTimelineController_issue.graphql.js} | 26 +-- .../prTimelineControllerQuery.graphql.js} | 68 +++---- ...TimelineController_pullRequest.graphql.js} | 42 ++-- lib/controllers/issue-timeline-controller.js | 8 +- lib/controllers/pr-timeline-controller.js | 6 +- .../issueishDetailViewRefetchQuery.graphql.js | 68 +++---- .../issueishDetailView_issueish.graphql.js | 16 +- .../prStatusContextView_context.graphql.js} | 10 +- .../prStatusesViewRefetchQuery.graphql.js} | 32 ++-- .../prStatusesView_pullRequest.graphql.js} | 16 +- lib/views/issueish-detail-view.js | 6 +- lib/views/pr-statuses-view.js | 6 +- .../commitCommentThreadView_item.graphql.js | 112 +++++++++++ .../commitCommentView_item.graphql.js | 112 +++++++++++ .../__generated__/commitView_item.graphql.js | 132 +++++++++++++ .../commitsView_nodes.graphql.js | 89 +++++++++ .../crossReferencedEventView_item.graphql.js | 179 ++++++++++++++++++ ...crossReferencedEventsView_nodes.graphql.js | 152 +++++++++++++++ ...efForcePushedEventView_issueish.graphql.js | 88 +++++++++ ...eadRefForcePushedEventView_item.graphql.js | 104 ++++++++++ .../issueCommentView_item.graphql.js | 75 ++++++++ .../mergedEventView_item.graphql.js | 96 ++++++++++ lib/views/timeline-items/commits-view.js | 2 +- .../current-pull-request-container.test.js | 4 +- .../commit-comment-thread-view.test.js | 2 +- 27 files changed, 1354 insertions(+), 215 deletions(-) rename lib/{containers/__generated__/issueTimelineContainerQuery.graphql.js => controllers/__generated__/issueTimelineControllerQuery.graphql.js} (83%) rename lib/{containers/__generated__/issueTimelineContainer_issue.graphql.js => controllers/__generated__/issueTimelineController_issue.graphql.js} (81%) rename lib/{containers/__generated__/prTimelineContainerQuery.graphql.js => controllers/__generated__/prTimelineControllerQuery.graphql.js} (81%) rename lib/{containers/__generated__/prTimelineContainer_pullRequest.graphql.js => controllers/__generated__/prTimelineController_pullRequest.graphql.js} (73%) rename lib/{containers/__generated__/prStatusContextContainer_context.graphql.js => views/__generated__/prStatusContextView_context.graphql.js} (79%) rename lib/{containers/__generated__/prStatusesContainerRefetchQuery.graphql.js => views/__generated__/prStatusesViewRefetchQuery.graphql.js} (81%) rename lib/{containers/__generated__/prStatusesContainer_pullRequest.graphql.js => views/__generated__/prStatusesView_pullRequest.graphql.js} (87%) create mode 100644 lib/views/timeline-items/__generated__/commitCommentThreadView_item.graphql.js create mode 100644 lib/views/timeline-items/__generated__/commitCommentView_item.graphql.js create mode 100644 lib/views/timeline-items/__generated__/commitView_item.graphql.js create mode 100644 lib/views/timeline-items/__generated__/commitsView_nodes.graphql.js create mode 100644 lib/views/timeline-items/__generated__/crossReferencedEventView_item.graphql.js create mode 100644 lib/views/timeline-items/__generated__/crossReferencedEventsView_nodes.graphql.js create mode 100644 lib/views/timeline-items/__generated__/headRefForcePushedEventView_issueish.graphql.js create mode 100644 lib/views/timeline-items/__generated__/headRefForcePushedEventView_item.graphql.js create mode 100644 lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js create mode 100644 lib/views/timeline-items/__generated__/mergedEventView_item.graphql.js diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index f85399804e..ea3ff136ea 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash a9c4813acc6ce1b1808984294ef26262 + * @relayHash d84672cec1e64616fc80f4bc4e135943 */ /* eslint-disable */ @@ -97,10 +97,10 @@ fragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest { id } } - ...issueTimelineContainer_issue_1wZIw + ...issueTimelineController_issue_1wZIw } ... on PullRequest { - ...prStatusesContainer_pullRequest + ...prStatusesView_pullRequest state number title @@ -119,7 +119,7 @@ fragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest { id } } - ...prTimelineContainer_pullRequest_1wZIw + ...prTimelineController_pullRequest_1wZIw } ... on UniformResourceLocatable { url @@ -134,7 +134,7 @@ fragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest { } } -fragment issueTimelineContainer_issue_1wZIw on Issue { +fragment issueTimelineController_issue_1wZIw on Issue { url timeline { pageInfo { @@ -145,9 +145,9 @@ fragment issueTimelineContainer_issue_1wZIw on Issue { cursor node { __typename - ...commitsContainer_nodes - ...issueCommentContainer_item - ...crossReferencedEventsContainer_nodes + ...commitsView_nodes + ...issueCommentView_item + ...crossReferencedEventsView_nodes ... on Node { id } @@ -156,7 +156,7 @@ fragment issueTimelineContainer_issue_1wZIw on Issue { } } -fragment prStatusesContainer_pullRequest on PullRequest { +fragment prStatusesView_pullRequest on PullRequest { id commits(last: 1) { edges { @@ -167,7 +167,7 @@ fragment prStatusesContainer_pullRequest on PullRequest { contexts { id state - ...prStatusContextContainer_context + ...prStatusContextView_context } id } @@ -179,9 +179,9 @@ fragment prStatusesContainer_pullRequest on PullRequest { } } -fragment prTimelineContainer_pullRequest_1wZIw on PullRequest { +fragment prTimelineController_pullRequest_1wZIw on PullRequest { url - ...headRefForcePushedEventContainer_issueish + ...headRefForcePushedEventView_issueish timeline { pageInfo { endCursor @@ -191,12 +191,12 @@ fragment prTimelineContainer_pullRequest_1wZIw on PullRequest { cursor node { __typename - ...commitsContainer_nodes - ...issueCommentContainer_item - ...mergedEventContainer_item - ...headRefForcePushedEventContainer_item - ...commitCommentThreadContainer_item - ...crossReferencedEventsContainer_nodes + ...commitsView_nodes + ...issueCommentView_item + ...mergedEventView_item + ...headRefForcePushedEventView_item + ...commitCommentThreadView_item + ...crossReferencedEventsView_nodes ... on Node { id } @@ -205,7 +205,7 @@ fragment prTimelineContainer_pullRequest_1wZIw on PullRequest { } } -fragment headRefForcePushedEventContainer_issueish on PullRequest { +fragment headRefForcePushedEventView_issueish on PullRequest { headRefName headRepositoryOwner { __typename @@ -222,7 +222,7 @@ fragment headRefForcePushedEventContainer_issueish on PullRequest { } } -fragment commitsContainer_nodes on Commit { +fragment commitsView_nodes on Commit { id author { name @@ -231,10 +231,10 @@ fragment commitsContainer_nodes on Commit { id } } - ...commitContainer_item + ...commitView_item } -fragment issueCommentContainer_item on IssueComment { +fragment issueCommentView_item on IssueComment { author { __typename avatarUrl @@ -247,7 +247,7 @@ fragment issueCommentContainer_item on IssueComment { createdAt } -fragment mergedEventContainer_item on MergedEvent { +fragment mergedEventView_item on MergedEvent { actor { __typename avatarUrl @@ -264,7 +264,7 @@ fragment mergedEventContainer_item on MergedEvent { createdAt } -fragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent { +fragment headRefForcePushedEventView_item on HeadRefForcePushedEvent { actor { __typename avatarUrl @@ -284,7 +284,7 @@ fragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent { createdAt } -fragment commitCommentThreadContainer_item on CommitCommentThread { +fragment commitCommentThreadView_item on CommitCommentThread { commit { oid id @@ -293,13 +293,13 @@ fragment commitCommentThreadContainer_item on CommitCommentThread { edges { node { id - ...commitCommentContainer_item + ...commitCommentView_item } } } } -fragment crossReferencedEventsContainer_nodes on CrossReferencedEvent { +fragment crossReferencedEventsView_nodes on CrossReferencedEvent { id referencedAt isCrossRepository @@ -328,10 +328,10 @@ fragment crossReferencedEventsContainer_nodes on CrossReferencedEvent { id } } - ...crossReferencedEventContainer_item + ...crossReferencedEventView_item } -fragment crossReferencedEventContainer_item on CrossReferencedEvent { +fragment crossReferencedEventView_item on CrossReferencedEvent { id isCrossRepository source { @@ -366,7 +366,7 @@ fragment crossReferencedEventContainer_item on CrossReferencedEvent { } } -fragment commitCommentContainer_item on CommitComment { +fragment commitCommentView_item on CommitComment { author { __typename login @@ -385,7 +385,7 @@ fragment commitCommentContainer_item on CommitComment { position } -fragment commitContainer_item on Commit { +fragment commitView_item on Commit { author { name avatarUrl @@ -408,7 +408,7 @@ fragment commitContainer_item on Commit { messageHeadlineHTML } -fragment prStatusContextContainer_context on StatusContext { +fragment prStatusContextView_context on StatusContext { context description state @@ -882,7 +882,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_146t2V\n id\n }\n}\n\nfragment issueishDetailController_repository_146t2V on Repository {\n ...issueishDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishDetailView_issueish_1wZIw\n }\n ... on PullRequest {\n title\n number\n ...issueishDetailView_issueish_1wZIw\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue_1wZIw\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest_1wZIw\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue_1wZIw on Issue {\n url\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest_1wZIw on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_146t2V\n id\n }\n}\n\nfragment issueishDetailController_repository_146t2V on Repository {\n ...issueishDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishDetailView_issueish_1wZIw\n }\n ... on PullRequest {\n title\n number\n ...issueishDetailView_issueish_1wZIw\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_1wZIw\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_1wZIw\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_1wZIw on Issue {\n url\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_1wZIw on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1318,7 +1318,7 @@ return { "name": "timeline", "args": null, "handle": "connection", - "key": "IssueTimelineContainer_timeline", + "key": "IssueTimelineController_timeline", "filters": null }, v29 diff --git a/lib/containers/__generated__/issueTimelineContainerQuery.graphql.js b/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js similarity index 83% rename from lib/containers/__generated__/issueTimelineContainerQuery.graphql.js rename to lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js index 398b331bdc..0a6b3ee49e 100644 --- a/lib/containers/__generated__/issueTimelineContainerQuery.graphql.js +++ b/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 85104935d05bb29ddc26ffbdb96ba4c7 + * @relayHash 19c3a66679dcd6a6d56adf3a29f8b2ef */ /* eslint-disable */ @@ -9,22 +9,22 @@ /*:: import type { ConcreteRequest } from 'relay-runtime'; -type issueTimelineContainer_issue$ref = any; -export type issueTimelineContainerQueryVariables = {| +type issueTimelineController_issue$ref = any; +export type issueTimelineControllerQueryVariables = {| timelineCount: number, timelineCursor?: ?string, url: any, |}; -export type issueTimelineContainerQueryResponse = {| +export type issueTimelineControllerQueryResponse = {| +resource: ?{| - +$fragmentRefs: issueTimelineContainer_issue$ref + +$fragmentRefs: issueTimelineController_issue$ref |} |}; */ /* -query issueTimelineContainerQuery( +query issueTimelineControllerQuery( $timelineCount: Int! $timelineCursor: String $url: URI! @@ -32,7 +32,7 @@ query issueTimelineContainerQuery( resource(url: $url) { __typename ... on Issue { - ...issueTimelineContainer_issue_3D8CP9 + ...issueTimelineController_issue_3D8CP9 } ... on Node { id @@ -40,7 +40,7 @@ query issueTimelineContainerQuery( } } -fragment issueTimelineContainer_issue_3D8CP9 on Issue { +fragment issueTimelineController_issue_3D8CP9 on Issue { url timeline(first: $timelineCount, after: $timelineCursor) { pageInfo { @@ -51,9 +51,9 @@ fragment issueTimelineContainer_issue_3D8CP9 on Issue { cursor node { __typename - ...commitsContainer_nodes - ...issueCommentContainer_item - ...crossReferencedEventsContainer_nodes + ...commitsView_nodes + ...issueCommentView_item + ...crossReferencedEventsView_nodes ... on Node { id } @@ -62,7 +62,7 @@ fragment issueTimelineContainer_issue_3D8CP9 on Issue { } } -fragment commitsContainer_nodes on Commit { +fragment commitsView_nodes on Commit { id author { name @@ -71,10 +71,10 @@ fragment commitsContainer_nodes on Commit { id } } - ...commitContainer_item + ...commitView_item } -fragment issueCommentContainer_item on IssueComment { +fragment issueCommentView_item on IssueComment { author { __typename avatarUrl @@ -87,7 +87,7 @@ fragment issueCommentContainer_item on IssueComment { createdAt } -fragment crossReferencedEventsContainer_nodes on CrossReferencedEvent { +fragment crossReferencedEventsView_nodes on CrossReferencedEvent { id referencedAt isCrossRepository @@ -116,10 +116,10 @@ fragment crossReferencedEventsContainer_nodes on CrossReferencedEvent { id } } - ...crossReferencedEventContainer_item + ...crossReferencedEventView_item } -fragment crossReferencedEventContainer_item on CrossReferencedEvent { +fragment crossReferencedEventView_item on CrossReferencedEvent { id isCrossRepository source { @@ -154,7 +154,7 @@ fragment crossReferencedEventContainer_item on CrossReferencedEvent { } } -fragment commitContainer_item on Commit { +fragment commitView_item on Commit { author { name avatarUrl @@ -279,13 +279,13 @@ v10 = { return { "kind": "Request", "operationKind": "query", - "name": "issueTimelineContainerQuery", + "name": "issueTimelineControllerQuery", "id": null, - "text": "query issueTimelineContainerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on Issue {\n ...issueTimelineContainer_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueTimelineContainer_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", + "text": "query issueTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on Issue {\n ...issueTimelineController_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", - "name": "issueTimelineContainerQuery", + "name": "issueTimelineControllerQuery", "type": "Query", "metadata": null, "argumentDefinitions": v0, @@ -305,7 +305,7 @@ return { "selections": [ { "kind": "FragmentSpread", - "name": "issueTimelineContainer_issue", + "name": "issueTimelineController_issue", "args": [ { "kind": "Variable", @@ -329,7 +329,7 @@ return { }, "operation": { "kind": "Operation", - "name": "issueTimelineContainerQuery", + "name": "issueTimelineControllerQuery", "argumentDefinitions": v0, "selections": [ { @@ -658,7 +658,7 @@ return { } ], "handle": "connection", - "key": "IssueTimelineContainer_timeline", + "key": "IssueTimelineController_timeline", "filters": null } ] @@ -670,5 +670,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'b1f3d85143779075e165dde0e8811da7'; +(node/*: any*/).hash = '5a04d82da4187ed75fb5e133f79b4ab4'; module.exports = node; diff --git a/lib/containers/__generated__/issueTimelineContainer_issue.graphql.js b/lib/controllers/__generated__/issueTimelineController_issue.graphql.js similarity index 81% rename from lib/containers/__generated__/issueTimelineContainer_issue.graphql.js rename to lib/controllers/__generated__/issueTimelineController_issue.graphql.js index 55c9f57cee..ce083d4b85 100644 --- a/lib/containers/__generated__/issueTimelineContainer_issue.graphql.js +++ b/lib/controllers/__generated__/issueTimelineController_issue.graphql.js @@ -8,12 +8,12 @@ /*:: import type { ConcreteFragment } from 'relay-runtime'; -type commitsContainer_nodes$ref = any; -type crossReferencedEventsContainer_nodes$ref = any; -type issueCommentContainer_item$ref = any; +type commitsView_nodes$ref = any; +type crossReferencedEventsView_nodes$ref = any; +type issueCommentView_item$ref = any; import type { FragmentReference } from "relay-runtime"; -declare export opaque type issueTimelineContainer_issue$ref: FragmentReference; -export type issueTimelineContainer_issue = {| +declare export opaque type issueTimelineController_issue$ref: FragmentReference; +export type issueTimelineController_issue = {| +url: any, +timeline: {| +pageInfo: {| @@ -24,18 +24,18 @@ export type issueTimelineContainer_issue = {| +cursor: string, +node: ?{| +__typename: string, - +$fragmentRefs: commitsContainer_nodes$ref & issueCommentContainer_item$ref & crossReferencedEventsContainer_nodes$ref, + +$fragmentRefs: commitsView_nodes$ref & issueCommentView_item$ref & crossReferencedEventsView_nodes$ref, |}, |}>, |}, - +$refType: issueTimelineContainer_issue$ref, + +$refType: issueTimelineController_issue$ref, |}; */ const node/*: ConcreteFragment*/ = { "kind": "Fragment", - "name": "issueTimelineContainer_issue", + "name": "issueTimelineController_issue", "type": "Issue", "metadata": { "connection": [ @@ -74,7 +74,7 @@ const node/*: ConcreteFragment*/ = { { "kind": "LinkedField", "alias": "timeline", - "name": "__IssueTimelineContainer_timeline_connection", + "name": "__IssueTimelineController_timeline_connection", "storageKey": null, "args": null, "concreteType": "IssueTimelineConnection", @@ -139,17 +139,17 @@ const node/*: ConcreteFragment*/ = { }, { "kind": "FragmentSpread", - "name": "commitsContainer_nodes", + "name": "commitsView_nodes", "args": null }, { "kind": "FragmentSpread", - "name": "issueCommentContainer_item", + "name": "issueCommentView_item", "args": null }, { "kind": "FragmentSpread", - "name": "crossReferencedEventsContainer_nodes", + "name": "crossReferencedEventsView_nodes", "args": null } ] @@ -161,5 +161,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = 'a5a1bce672bac668e82bcc9ab97ebc7e'; +(node/*: any*/).hash = '91a0aa63cb74691005a4ed6dc3f7aa16'; module.exports = node; diff --git a/lib/containers/__generated__/prTimelineContainerQuery.graphql.js b/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js similarity index 81% rename from lib/containers/__generated__/prTimelineContainerQuery.graphql.js rename to lib/controllers/__generated__/prTimelineControllerQuery.graphql.js index 2f1bd277f2..705d4efe52 100644 --- a/lib/containers/__generated__/prTimelineContainerQuery.graphql.js +++ b/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash a6c8a5736596f39e03e83fe3ad707fef + * @relayHash 3fb91f9b6850bc8de8a7c65508590a21 */ /* eslint-disable */ @@ -9,28 +9,28 @@ /*:: import type { ConcreteRequest } from 'relay-runtime'; -type prTimelineContainer_pullRequest$ref = any; -export type prTimelineContainerQueryVariables = {| +type prTimelineController_pullRequest$ref = any; +export type prTimelineControllerQueryVariables = {| timelineCount: number, timelineCursor?: ?string, url: any, |}; -export type prTimelineContainerQueryResponse = {| +export type prTimelineControllerQueryResponse = {| +resource: ?{| - +$fragmentRefs: prTimelineContainer_pullRequest$ref + +$fragmentRefs: prTimelineController_pullRequest$ref |} |}; */ /* -query prTimelineContainerQuery( +query prTimelineControllerQuery( $url: URI! ) { resource(url: $url) { __typename ... on PullRequest { - ...prTimelineContainer_pullRequest + ...prTimelineController_pullRequest } ... on Node { id @@ -38,9 +38,9 @@ query prTimelineContainerQuery( } } -fragment prTimelineContainer_pullRequest on PullRequest { +fragment prTimelineController_pullRequest on PullRequest { url - ...headRefForcePushedEventContainer_issueish + ...headRefForcePushedEventView_issueish timeline { pageInfo { endCursor @@ -50,12 +50,12 @@ fragment prTimelineContainer_pullRequest on PullRequest { cursor node { __typename - ...commitsContainer_nodes - ...issueCommentContainer_item - ...mergedEventContainer_item - ...headRefForcePushedEventContainer_item - ...commitCommentThreadContainer_item - ...crossReferencedEventsContainer_nodes + ...commitsView_nodes + ...issueCommentView_item + ...mergedEventView_item + ...headRefForcePushedEventView_item + ...commitCommentThreadView_item + ...crossReferencedEventsView_nodes ... on Node { id } @@ -64,7 +64,7 @@ fragment prTimelineContainer_pullRequest on PullRequest { } } -fragment headRefForcePushedEventContainer_issueish on PullRequest { +fragment headRefForcePushedEventView_issueish on PullRequest { headRefName headRepositoryOwner { __typename @@ -81,7 +81,7 @@ fragment headRefForcePushedEventContainer_issueish on PullRequest { } } -fragment commitsContainer_nodes on Commit { +fragment commitsView_nodes on Commit { id author { name @@ -90,10 +90,10 @@ fragment commitsContainer_nodes on Commit { id } } - ...commitContainer_item + ...commitView_item } -fragment issueCommentContainer_item on IssueComment { +fragment issueCommentView_item on IssueComment { author { __typename avatarUrl @@ -106,7 +106,7 @@ fragment issueCommentContainer_item on IssueComment { createdAt } -fragment mergedEventContainer_item on MergedEvent { +fragment mergedEventView_item on MergedEvent { actor { __typename avatarUrl @@ -123,7 +123,7 @@ fragment mergedEventContainer_item on MergedEvent { createdAt } -fragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent { +fragment headRefForcePushedEventView_item on HeadRefForcePushedEvent { actor { __typename avatarUrl @@ -143,7 +143,7 @@ fragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent { createdAt } -fragment commitCommentThreadContainer_item on CommitCommentThread { +fragment commitCommentThreadView_item on CommitCommentThread { commit { oid id @@ -152,13 +152,13 @@ fragment commitCommentThreadContainer_item on CommitCommentThread { edges { node { id - ...commitCommentContainer_item + ...commitCommentView_item } } } } -fragment crossReferencedEventsContainer_nodes on CrossReferencedEvent { +fragment crossReferencedEventsView_nodes on CrossReferencedEvent { id referencedAt isCrossRepository @@ -187,10 +187,10 @@ fragment crossReferencedEventsContainer_nodes on CrossReferencedEvent { id } } - ...crossReferencedEventContainer_item + ...crossReferencedEventView_item } -fragment crossReferencedEventContainer_item on CrossReferencedEvent { +fragment crossReferencedEventView_item on CrossReferencedEvent { id isCrossRepository source { @@ -225,7 +225,7 @@ fragment crossReferencedEventContainer_item on CrossReferencedEvent { } } -fragment commitCommentContainer_item on CommitComment { +fragment commitCommentView_item on CommitComment { author { __typename login @@ -244,7 +244,7 @@ fragment commitCommentContainer_item on CommitComment { position } -fragment commitContainer_item on Commit { +fragment commitView_item on Commit { author { name avatarUrl @@ -441,13 +441,13 @@ v20 = { return { "kind": "Request", "operationKind": "query", - "name": "prTimelineContainerQuery", + "name": "prTimelineControllerQuery", "id": null, - "text": "query prTimelineContainerQuery(\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineContainer_pullRequest\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", + "text": "query prTimelineControllerQuery(\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineController_pullRequest\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineController_pullRequest on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", - "name": "prTimelineContainerQuery", + "name": "prTimelineControllerQuery", "type": "Query", "metadata": null, "argumentDefinitions": v0, @@ -467,7 +467,7 @@ return { "selections": [ { "kind": "FragmentSpread", - "name": "prTimelineContainer_pullRequest", + "name": "prTimelineController_pullRequest", "args": null } ] @@ -478,7 +478,7 @@ return { }, "operation": { "kind": "Operation", - "name": "prTimelineContainerQuery", + "name": "prTimelineControllerQuery", "argumentDefinitions": v0, "selections": [ { @@ -901,5 +901,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '9f077f784e71ae1c58801246cf9e3b68'; +(node/*: any*/).hash = '70b5c2eb56b15708ffbd13c2d97b80a6'; module.exports = node; diff --git a/lib/containers/__generated__/prTimelineContainer_pullRequest.graphql.js b/lib/controllers/__generated__/prTimelineController_pullRequest.graphql.js similarity index 73% rename from lib/containers/__generated__/prTimelineContainer_pullRequest.graphql.js rename to lib/controllers/__generated__/prTimelineController_pullRequest.graphql.js index 2e0c84df1f..097342a016 100644 --- a/lib/containers/__generated__/prTimelineContainer_pullRequest.graphql.js +++ b/lib/controllers/__generated__/prTimelineController_pullRequest.graphql.js @@ -8,16 +8,16 @@ /*:: import type { ConcreteFragment } from 'relay-runtime'; -type commitCommentThreadContainer_item$ref = any; -type commitsContainer_nodes$ref = any; -type crossReferencedEventsContainer_nodes$ref = any; -type headRefForcePushedEventContainer_issueish$ref = any; -type headRefForcePushedEventContainer_item$ref = any; -type issueCommentContainer_item$ref = any; -type mergedEventContainer_item$ref = any; +type commitCommentThreadView_item$ref = any; +type commitsView_nodes$ref = any; +type crossReferencedEventsView_nodes$ref = any; +type headRefForcePushedEventView_issueish$ref = any; +type headRefForcePushedEventView_item$ref = any; +type issueCommentView_item$ref = any; +type mergedEventView_item$ref = any; import type { FragmentReference } from "relay-runtime"; -declare export opaque type prTimelineContainer_pullRequest$ref: FragmentReference; -export type prTimelineContainer_pullRequest = {| +declare export opaque type prTimelineController_pullRequest$ref: FragmentReference; +export type prTimelineController_pullRequest = {| +url: any, +timeline: {| +pageInfo: {| @@ -28,19 +28,19 @@ export type prTimelineContainer_pullRequest = {| +cursor: string, +node: ?{| +__typename: string, - +$fragmentRefs: commitsContainer_nodes$ref & issueCommentContainer_item$ref & mergedEventContainer_item$ref & headRefForcePushedEventContainer_item$ref & commitCommentThreadContainer_item$ref & crossReferencedEventsContainer_nodes$ref, + +$fragmentRefs: commitsView_nodes$ref & issueCommentView_item$ref & mergedEventView_item$ref & headRefForcePushedEventView_item$ref & commitCommentThreadView_item$ref & crossReferencedEventsView_nodes$ref, |}, |}>, |}, - +$fragmentRefs: headRefForcePushedEventContainer_issueish$ref, - +$refType: prTimelineContainer_pullRequest$ref, + +$fragmentRefs: headRefForcePushedEventView_issueish$ref, + +$refType: prTimelineController_pullRequest$ref, |}; */ const node/*: ConcreteFragment*/ = { "kind": "Fragment", - "name": "prTimelineContainer_pullRequest", + "name": "prTimelineController_pullRequest", "type": "PullRequest", "metadata": { "connection": [ @@ -78,7 +78,7 @@ const node/*: ConcreteFragment*/ = { }, { "kind": "FragmentSpread", - "name": "headRefForcePushedEventContainer_issueish", + "name": "headRefForcePushedEventView_issueish", "args": null }, { @@ -149,32 +149,32 @@ const node/*: ConcreteFragment*/ = { }, { "kind": "FragmentSpread", - "name": "commitsContainer_nodes", + "name": "commitsView_nodes", "args": null }, { "kind": "FragmentSpread", - "name": "issueCommentContainer_item", + "name": "issueCommentView_item", "args": null }, { "kind": "FragmentSpread", - "name": "mergedEventContainer_item", + "name": "mergedEventView_item", "args": null }, { "kind": "FragmentSpread", - "name": "headRefForcePushedEventContainer_item", + "name": "headRefForcePushedEventView_item", "args": null }, { "kind": "FragmentSpread", - "name": "commitCommentThreadContainer_item", + "name": "commitCommentThreadView_item", "args": null }, { "kind": "FragmentSpread", - "name": "crossReferencedEventsContainer_nodes", + "name": "crossReferencedEventsView_nodes", "args": null } ] @@ -186,5 +186,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = 'ecf0555355586b59e8595a955dcaf5e4'; +(node/*: any*/).hash = 'e2137d027447cba05e42f3d8bae6643d'; module.exports = node; diff --git a/lib/controllers/issue-timeline-controller.js b/lib/controllers/issue-timeline-controller.js index 9afec57f2b..df370ca8db 100644 --- a/lib/controllers/issue-timeline-controller.js +++ b/lib/controllers/issue-timeline-controller.js @@ -4,7 +4,7 @@ import IssueishTimelineView from '../views/issueish-timeline-view'; export default createPaginationContainer(IssueishTimelineView, { issue: graphql` - fragment issueTimelineContainer_issue on Issue + fragment issueTimelineController_issue on Issue @argumentDefinitions( timelineCount: {type: "Int"}, timelineCursor: {type: "String"} @@ -12,7 +12,7 @@ export default createPaginationContainer(IssueishTimelineView, { url timeline( first: $timelineCount, after: $timelineCursor - ) @connection(key: "IssueTimelineContainer_timeline") { + ) @connection(key: "IssueTimelineController_timeline") { pageInfo { endCursor hasNextPage } edges { cursor @@ -45,10 +45,10 @@ export default createPaginationContainer(IssueishTimelineView, { }; }, query: graphql` - query issueTimelineContainerQuery($timelineCount: Int!, $timelineCursor: String, $url: URI!) { + query issueTimelineControllerQuery($timelineCount: Int!, $timelineCursor: String, $url: URI!) { resource(url: $url) { ... on Issue { - ...issueTimelineContainer_issue @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) + ...issueTimelineController_issue @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) } } } diff --git a/lib/controllers/pr-timeline-controller.js b/lib/controllers/pr-timeline-controller.js index 4cb15c6b2d..acdd7e5413 100644 --- a/lib/controllers/pr-timeline-controller.js +++ b/lib/controllers/pr-timeline-controller.js @@ -4,7 +4,7 @@ import IssueishTimelineView from '../views/issueish-timeline-view'; export default createPaginationContainer(IssueishTimelineView, { pullRequest: graphql` - fragment prTimelineContainer_pullRequest on PullRequest + fragment prTimelineController_pullRequest on PullRequest @argumentDefinitions( timelineCount: {type: "Int"}, timelineCursor: {type: "String"} @@ -47,10 +47,10 @@ export default createPaginationContainer(IssueishTimelineView, { }; }, query: graphql` - query prTimelineContainerQuery($timelineCount: Int! $timelineCursor: String $url: URI!) { + query prTimelineControllerQuery($timelineCount: Int! $timelineCursor: String $url: URI!) { resource(url: $url) { ... on PullRequest { - ...prTimelineContainer_pullRequest + ...prTimelineController_pullRequest } } } diff --git a/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js index efa007bf53..ae5d7909bf 100644 --- a/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 1fec69af8de0cc21e82edc72a3aa6f54 + * @relayHash 84069f78e531f794e9f37c33bd9522ca */ /* eslint-disable */ @@ -81,10 +81,10 @@ fragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest { id } } - ...issueTimelineContainer_issue_3D8CP9 + ...issueTimelineController_issue_3D8CP9 } ... on PullRequest { - ...prStatusesContainer_pullRequest + ...prStatusesView_pullRequest state number title @@ -103,7 +103,7 @@ fragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest { id } } - ...prTimelineContainer_pullRequest_3D8CP9 + ...prTimelineController_pullRequest_3D8CP9 } ... on UniformResourceLocatable { url @@ -118,7 +118,7 @@ fragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest { } } -fragment issueTimelineContainer_issue_3D8CP9 on Issue { +fragment issueTimelineController_issue_3D8CP9 on Issue { url timeline(first: $timelineCount, after: $timelineCursor) { pageInfo { @@ -129,9 +129,9 @@ fragment issueTimelineContainer_issue_3D8CP9 on Issue { cursor node { __typename - ...commitsContainer_nodes - ...issueCommentContainer_item - ...crossReferencedEventsContainer_nodes + ...commitsView_nodes + ...issueCommentView_item + ...crossReferencedEventsView_nodes ... on Node { id } @@ -140,7 +140,7 @@ fragment issueTimelineContainer_issue_3D8CP9 on Issue { } } -fragment prStatusesContainer_pullRequest on PullRequest { +fragment prStatusesView_pullRequest on PullRequest { id commits(last: 1) { edges { @@ -151,7 +151,7 @@ fragment prStatusesContainer_pullRequest on PullRequest { contexts { id state - ...prStatusContextContainer_context + ...prStatusContextView_context } id } @@ -163,9 +163,9 @@ fragment prStatusesContainer_pullRequest on PullRequest { } } -fragment prTimelineContainer_pullRequest_3D8CP9 on PullRequest { +fragment prTimelineController_pullRequest_3D8CP9 on PullRequest { url - ...headRefForcePushedEventContainer_issueish + ...headRefForcePushedEventView_issueish timeline(first: $timelineCount, after: $timelineCursor) { pageInfo { endCursor @@ -175,12 +175,12 @@ fragment prTimelineContainer_pullRequest_3D8CP9 on PullRequest { cursor node { __typename - ...commitsContainer_nodes - ...issueCommentContainer_item - ...mergedEventContainer_item - ...headRefForcePushedEventContainer_item - ...commitCommentThreadContainer_item - ...crossReferencedEventsContainer_nodes + ...commitsView_nodes + ...issueCommentView_item + ...mergedEventView_item + ...headRefForcePushedEventView_item + ...commitCommentThreadView_item + ...crossReferencedEventsView_nodes ... on Node { id } @@ -189,7 +189,7 @@ fragment prTimelineContainer_pullRequest_3D8CP9 on PullRequest { } } -fragment headRefForcePushedEventContainer_issueish on PullRequest { +fragment headRefForcePushedEventView_issueish on PullRequest { headRefName headRepositoryOwner { __typename @@ -206,7 +206,7 @@ fragment headRefForcePushedEventContainer_issueish on PullRequest { } } -fragment commitsContainer_nodes on Commit { +fragment commitsView_nodes on Commit { id author { name @@ -215,10 +215,10 @@ fragment commitsContainer_nodes on Commit { id } } - ...commitContainer_item + ...commitView_item } -fragment issueCommentContainer_item on IssueComment { +fragment issueCommentView_item on IssueComment { author { __typename avatarUrl @@ -231,7 +231,7 @@ fragment issueCommentContainer_item on IssueComment { createdAt } -fragment mergedEventContainer_item on MergedEvent { +fragment mergedEventView_item on MergedEvent { actor { __typename avatarUrl @@ -248,7 +248,7 @@ fragment mergedEventContainer_item on MergedEvent { createdAt } -fragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent { +fragment headRefForcePushedEventView_item on HeadRefForcePushedEvent { actor { __typename avatarUrl @@ -268,7 +268,7 @@ fragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent { createdAt } -fragment commitCommentThreadContainer_item on CommitCommentThread { +fragment commitCommentThreadView_item on CommitCommentThread { commit { oid id @@ -277,13 +277,13 @@ fragment commitCommentThreadContainer_item on CommitCommentThread { edges { node { id - ...commitCommentContainer_item + ...commitCommentView_item } } } } -fragment crossReferencedEventsContainer_nodes on CrossReferencedEvent { +fragment crossReferencedEventsView_nodes on CrossReferencedEvent { id referencedAt isCrossRepository @@ -312,10 +312,10 @@ fragment crossReferencedEventsContainer_nodes on CrossReferencedEvent { id } } - ...crossReferencedEventContainer_item + ...crossReferencedEventView_item } -fragment crossReferencedEventContainer_item on CrossReferencedEvent { +fragment crossReferencedEventView_item on CrossReferencedEvent { id isCrossRepository source { @@ -350,7 +350,7 @@ fragment crossReferencedEventContainer_item on CrossReferencedEvent { } } -fragment commitCommentContainer_item on CommitComment { +fragment commitCommentView_item on CommitComment { author { __typename login @@ -369,7 +369,7 @@ fragment commitCommentContainer_item on CommitComment { position } -fragment commitContainer_item on Commit { +fragment commitView_item on Commit { author { name avatarUrl @@ -392,7 +392,7 @@ fragment commitContainer_item on Commit { messageHeadlineHTML } -fragment prStatusContextContainer_context on StatusContext { +fragment prStatusContextView_context on StatusContext { context description state @@ -840,7 +840,7 @@ return { "operationKind": "query", "name": "issueishDetailViewRefetchQuery", "id": null, - "text": "query issueishDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishDetailView_repository\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishDetailView_issueish_3D8CP9\n id\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineContainer_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineContainer_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineContainer_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineContainer_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventContainer_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsContainer_nodes\n ...issueCommentContainer_item\n ...mergedEventContainer_item\n ...headRefForcePushedEventContainer_item\n ...commitCommentThreadContainer_item\n ...crossReferencedEventsContainer_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventContainer_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsContainer_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitContainer_item\n}\n\nfragment issueCommentContainer_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventContainer_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventContainer_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadContainer_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentContainer_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsContainer_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventContainer_item\n}\n\nfragment crossReferencedEventContainer_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentContainer_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitContainer_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishDetailView_repository\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishDetailView_issueish_3D8CP9\n id\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1334,7 +1334,7 @@ return { "name": "timeline", "args": v17, "handle": "connection", - "key": "IssueTimelineContainer_timeline", + "key": "IssueTimelineController_timeline", "filters": null } ] diff --git a/lib/views/__generated__/issueishDetailView_issueish.graphql.js b/lib/views/__generated__/issueishDetailView_issueish.graphql.js index 2c88baf126..981cd78045 100644 --- a/lib/views/__generated__/issueishDetailView_issueish.graphql.js +++ b/lib/views/__generated__/issueishDetailView_issueish.graphql.js @@ -8,9 +8,9 @@ /*:: import type { ConcreteFragment } from 'relay-runtime'; -type issueTimelineContainer_issue$ref = any; -type prStatusesContainer_pullRequest$ref = any; -type prTimelineContainer_pullRequest$ref = any; +type issueTimelineController_issue$ref = any; +type prStatusesView_pullRequest$ref = any; +type prTimelineController_pullRequest$ref = any; export type IssueState = "CLOSED" | "OPEN" | "%future added value"; export type PullRequestState = "CLOSED" | "MERGED" | "OPEN" | "%future added value"; export type ReactionContent = "CONFUSED" | "HEART" | "HOORAY" | "LAUGH" | "THUMBS_DOWN" | "THUMBS_UP" | "%future added value"; @@ -35,7 +35,7 @@ export type issueishDetailView_issueish = {| +avatarUrl: any, +url?: any, |}, - +$fragmentRefs: issueTimelineContainer_issue$ref & prStatusesContainer_pullRequest$ref & prTimelineContainer_pullRequest$ref, + +$fragmentRefs: issueTimelineController_issue$ref & prStatusesView_pullRequest$ref & prTimelineController_pullRequest$ref, +$refType: issueishDetailView_issueish$ref, |}; */ @@ -206,7 +206,7 @@ return { "selections": [ { "kind": "FragmentSpread", - "name": "prStatusesContainer_pullRequest", + "name": "prStatusesView_pullRequest", "args": null }, v1, @@ -216,7 +216,7 @@ return { v6, { "kind": "FragmentSpread", - "name": "prTimelineContainer_pullRequest", + "name": "prTimelineController_pullRequest", "args": v7 } ] @@ -232,7 +232,7 @@ return { v6, { "kind": "FragmentSpread", - "name": "issueTimelineContainer_issue", + "name": "issueTimelineController_issue", "args": v7 } ] @@ -241,5 +241,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '4030ff81df8e392b072a39440744e2bb'; +(node/*: any*/).hash = 'cc2a04ddfc3249b138025f067ba42363'; module.exports = node; diff --git a/lib/containers/__generated__/prStatusContextContainer_context.graphql.js b/lib/views/__generated__/prStatusContextView_context.graphql.js similarity index 79% rename from lib/containers/__generated__/prStatusContextContainer_context.graphql.js rename to lib/views/__generated__/prStatusContextView_context.graphql.js index 1e6fb32fcf..c85134d3fa 100644 --- a/lib/containers/__generated__/prStatusContextContainer_context.graphql.js +++ b/lib/views/__generated__/prStatusContextView_context.graphql.js @@ -10,20 +10,20 @@ import type { ConcreteFragment } from 'relay-runtime'; export type StatusState = "ERROR" | "EXPECTED" | "FAILURE" | "PENDING" | "SUCCESS" | "%future added value"; import type { FragmentReference } from "relay-runtime"; -declare export opaque type prStatusContextContainer_context$ref: FragmentReference; -export type prStatusContextContainer_context = {| +declare export opaque type prStatusContextView_context$ref: FragmentReference; +export type prStatusContextView_context = {| +context: string, +description: ?string, +state: StatusState, +targetUrl: ?any, - +$refType: prStatusContextContainer_context$ref, + +$refType: prStatusContextView_context$ref, |}; */ const node/*: ConcreteFragment*/ = { "kind": "Fragment", - "name": "prStatusContextContainer_context", + "name": "prStatusContextView_context", "type": "StatusContext", "metadata": null, "argumentDefinitions": [], @@ -59,5 +59,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = '6e319fea6086be70e756c722f5f2dbd0'; +(node/*: any*/).hash = 'e729074e494e07b59b4a177416eb7a3c'; module.exports = node; diff --git a/lib/containers/__generated__/prStatusesContainerRefetchQuery.graphql.js b/lib/views/__generated__/prStatusesViewRefetchQuery.graphql.js similarity index 81% rename from lib/containers/__generated__/prStatusesContainerRefetchQuery.graphql.js rename to lib/views/__generated__/prStatusesViewRefetchQuery.graphql.js index d89c76a7b6..aa3ba531f6 100644 --- a/lib/containers/__generated__/prStatusesContainerRefetchQuery.graphql.js +++ b/lib/views/__generated__/prStatusesViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash b4dcba32e85af2e67fe2eeb89782148f + * @relayHash 785a8d24aba2ef8a8145215f0bff78a0 */ /* eslint-disable */ @@ -9,32 +9,32 @@ /*:: import type { ConcreteRequest } from 'relay-runtime'; -type prStatusesContainer_pullRequest$ref = any; -export type prStatusesContainerRefetchQueryVariables = {| +type prStatusesView_pullRequest$ref = any; +export type prStatusesViewRefetchQueryVariables = {| id: string |}; -export type prStatusesContainerRefetchQueryResponse = {| +export type prStatusesViewRefetchQueryResponse = {| +node: ?{| - +$fragmentRefs: prStatusesContainer_pullRequest$ref + +$fragmentRefs: prStatusesView_pullRequest$ref |} |}; */ /* -query prStatusesContainerRefetchQuery( +query prStatusesViewRefetchQuery( $id: ID! ) { node(id: $id) { __typename ... on PullRequest { - ...prStatusesContainer_pullRequest + ...prStatusesView_pullRequest } id } } -fragment prStatusesContainer_pullRequest on PullRequest { +fragment prStatusesView_pullRequest on PullRequest { id commits(last: 1) { edges { @@ -45,7 +45,7 @@ fragment prStatusesContainer_pullRequest on PullRequest { contexts { id state - ...prStatusContextContainer_context + ...prStatusContextView_context } id } @@ -57,7 +57,7 @@ fragment prStatusesContainer_pullRequest on PullRequest { } } -fragment prStatusContextContainer_context on StatusContext { +fragment prStatusContextView_context on StatusContext { context description state @@ -99,13 +99,13 @@ v3 = { return { "kind": "Request", "operationKind": "query", - "name": "prStatusesContainerRefetchQuery", + "name": "prStatusesViewRefetchQuery", "id": null, - "text": "query prStatusesContainerRefetchQuery(\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequest {\n ...prStatusesContainer_pullRequest\n }\n id\n }\n}\n\nfragment prStatusesContainer_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextContainer_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prStatusContextContainer_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query prStatusesViewRefetchQuery(\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequest {\n ...prStatusesView_pullRequest\n }\n id\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", - "name": "prStatusesContainerRefetchQuery", + "name": "prStatusesViewRefetchQuery", "type": "Query", "metadata": null, "argumentDefinitions": v0, @@ -125,7 +125,7 @@ return { "selections": [ { "kind": "FragmentSpread", - "name": "prStatusesContainer_pullRequest", + "name": "prStatusesView_pullRequest", "args": null } ] @@ -136,7 +136,7 @@ return { }, "operation": { "kind": "Operation", - "name": "prStatusesContainerRefetchQuery", + "name": "prStatusesViewRefetchQuery", "argumentDefinitions": v0, "selections": [ { @@ -269,5 +269,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '51243357f05d34f1acb9fccf2df72af6'; +(node/*: any*/).hash = 'a7600333b3bc426d899c4d0183095a1f'; module.exports = node; diff --git a/lib/containers/__generated__/prStatusesContainer_pullRequest.graphql.js b/lib/views/__generated__/prStatusesView_pullRequest.graphql.js similarity index 87% rename from lib/containers/__generated__/prStatusesContainer_pullRequest.graphql.js rename to lib/views/__generated__/prStatusesView_pullRequest.graphql.js index d0216b3511..47eea48386 100644 --- a/lib/containers/__generated__/prStatusesContainer_pullRequest.graphql.js +++ b/lib/views/__generated__/prStatusesView_pullRequest.graphql.js @@ -8,11 +8,11 @@ /*:: import type { ConcreteFragment } from 'relay-runtime'; -type prStatusContextContainer_context$ref = any; +type prStatusContextView_context$ref = any; export type StatusState = "ERROR" | "EXPECTED" | "FAILURE" | "PENDING" | "SUCCESS" | "%future added value"; import type { FragmentReference } from "relay-runtime"; -declare export opaque type prStatusesContainer_pullRequest$ref: FragmentReference; -export type prStatusesContainer_pullRequest = {| +declare export opaque type prStatusesView_pullRequest$ref: FragmentReference; +export type prStatusesView_pullRequest = {| +id: string, +commits: {| +edges: ?$ReadOnlyArray, |} |} |} |}> |}, - +$refType: prStatusesContainer_pullRequest$ref, + +$refType: prStatusesView_pullRequest$ref, |}; */ @@ -52,7 +52,7 @@ v1 = { }; return { "kind": "Fragment", - "name": "prStatusesContainer_pullRequest", + "name": "prStatusesView_pullRequest", "type": "PullRequest", "metadata": null, "argumentDefinitions": [], @@ -124,7 +124,7 @@ return { v1, { "kind": "FragmentSpread", - "name": "prStatusContextContainer_context", + "name": "prStatusContextView_context", "args": null } ] @@ -143,5 +143,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '5140fedecb47f62c0adb19a2543aa6d6'; +(node/*: any*/).hash = '205d1672362f0eb428061beae088734c'; module.exports = node; diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index 0a92f73164..f08fe2be26 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -216,11 +216,11 @@ export default createRefetchContainer(BareIssueishDetailView, { ... on Bot { url } } - ...issueTimelineContainer_issue @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) + ...issueTimelineController_issue @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) } ... on PullRequest { - ...prStatusesContainer_pullRequest + ...prStatusesView_pullRequest state number title bodyHTML author { login avatarUrl @@ -228,7 +228,7 @@ export default createRefetchContainer(BareIssueishDetailView, { ... on Bot { url } } - ...prTimelineContainer_pullRequest @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) + ...prTimelineController_pullRequest @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) } ... on UniformResourceLocatable { url } diff --git a/lib/views/pr-statuses-view.js b/lib/views/pr-statuses-view.js index 62b4a15984..68c2ccc66b 100644 --- a/lib/views/pr-statuses-view.js +++ b/lib/views/pr-statuses-view.js @@ -179,7 +179,7 @@ export class BarePrStatusesView extends React.Component { export default createRefetchContainer(BarePrStatusesView, { pullRequest: graphql` - fragment prStatusesContainer_pullRequest on PullRequest { + fragment prStatusesView_pullRequest on PullRequest { id commits(last:1) { edges { @@ -200,10 +200,10 @@ export default createRefetchContainer(BarePrStatusesView, { } `, }, graphql` - query prStatusesContainerRefetchQuery($id: ID!) { + query prStatusesViewRefetchQuery($id: ID!) { node(id: $id) { ... on PullRequest { - ...prStatusesContainer_pullRequest + ...prStatusesView_pullRequest } } } diff --git a/lib/views/timeline-items/__generated__/commitCommentThreadView_item.graphql.js b/lib/views/timeline-items/__generated__/commitCommentThreadView_item.graphql.js new file mode 100644 index 0000000000..608c31f35c --- /dev/null +++ b/lib/views/timeline-items/__generated__/commitCommentThreadView_item.graphql.js @@ -0,0 +1,112 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +type commitCommentView_item$ref = any; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type commitCommentThreadView_item$ref: FragmentReference; +export type commitCommentThreadView_item = {| + +commit: {| + +oid: any + |}, + +comments: {| + +edges: ?$ReadOnlyArray + |}, + +$refType: commitCommentThreadView_item$ref, +|}; +*/ + + +const node/*: ConcreteFragment*/ = { + "kind": "Fragment", + "name": "commitCommentThreadView_item", + "type": "CommitCommentThread", + "metadata": null, + "argumentDefinitions": [], + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "oid", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": "comments(first:100)", + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 100, + "type": "Int" + } + ], + "concreteType": "CommitCommentConnection", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "edges", + "storageKey": null, + "args": null, + "concreteType": "CommitCommentEdge", + "plural": true, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "node", + "storageKey": null, + "args": null, + "concreteType": "CommitComment", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null + }, + { + "kind": "FragmentSpread", + "name": "commitCommentView_item", + "args": null + } + ] + } + ] + } + ] + } + ] +}; +// prettier-ignore +(node/*: any*/).hash = '8d9762b31747ddf9be48e163b09a45bc'; +module.exports = node; diff --git a/lib/views/timeline-items/__generated__/commitCommentView_item.graphql.js b/lib/views/timeline-items/__generated__/commitCommentView_item.graphql.js new file mode 100644 index 0000000000..9d47e87acf --- /dev/null +++ b/lib/views/timeline-items/__generated__/commitCommentView_item.graphql.js @@ -0,0 +1,112 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type commitCommentView_item$ref: FragmentReference; +export type commitCommentView_item = {| + +author: ?{| + +login: string, + +avatarUrl: any, + |}, + +commit: ?{| + +oid: any + |}, + +bodyHTML: any, + +createdAt: any, + +path: ?string, + +position: ?number, + +$refType: commitCommentView_item$ref, +|}; +*/ + + +const node/*: ConcreteFragment*/ = { + "kind": "Fragment", + "name": "commitCommentView_item", + "type": "CommitComment", + "metadata": null, + "argumentDefinitions": [], + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "oid", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "bodyHTML", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "path", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "position", + "args": null, + "storageKey": null + } + ] +}; +// prettier-ignore +(node/*: any*/).hash = 'f3e868b343fe8d6fee958d5339b554dc'; +module.exports = node; diff --git a/lib/views/timeline-items/__generated__/commitView_item.graphql.js b/lib/views/timeline-items/__generated__/commitView_item.graphql.js new file mode 100644 index 0000000000..345dbbcaf4 --- /dev/null +++ b/lib/views/timeline-items/__generated__/commitView_item.graphql.js @@ -0,0 +1,132 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type commitView_item$ref: FragmentReference; +export type commitView_item = {| + +author: ?{| + +name: ?string, + +avatarUrl: any, + +user: ?{| + +login: string + |}, + |}, + +committer: ?{| + +name: ?string, + +avatarUrl: any, + +user: ?{| + +login: string + |}, + |}, + +authoredByCommitter: boolean, + +oid: any, + +message: string, + +messageHeadlineHTML: any, + +$refType: commitView_item$ref, +|}; +*/ + + +const node/*: ConcreteFragment*/ = (function(){ +var v0 = [ + { + "kind": "ScalarField", + "alias": null, + "name": "name", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "user", + "storageKey": null, + "args": null, + "concreteType": "User", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + } + ] + } +]; +return { + "kind": "Fragment", + "name": "commitView_item", + "type": "Commit", + "metadata": null, + "argumentDefinitions": [], + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": "GitActor", + "plural": false, + "selections": v0 + }, + { + "kind": "LinkedField", + "alias": null, + "name": "committer", + "storageKey": null, + "args": null, + "concreteType": "GitActor", + "plural": false, + "selections": v0 + }, + { + "kind": "ScalarField", + "alias": null, + "name": "authoredByCommitter", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "oid", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "message", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "messageHeadlineHTML", + "args": null, + "storageKey": null + } + ] +}; +})(); +// prettier-ignore +(node/*: any*/).hash = 'e58543afc5a89f1abb41ae37873a5e0a'; +module.exports = node; diff --git a/lib/views/timeline-items/__generated__/commitsView_nodes.graphql.js b/lib/views/timeline-items/__generated__/commitsView_nodes.graphql.js new file mode 100644 index 0000000000..b4224f2b98 --- /dev/null +++ b/lib/views/timeline-items/__generated__/commitsView_nodes.graphql.js @@ -0,0 +1,89 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +type commitView_item$ref = any; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type commitsView_nodes$ref: FragmentReference; +export type commitsView_nodes = $ReadOnlyArray<{| + +id: string, + +author: ?{| + +name: ?string, + +user: ?{| + +login: string + |}, + |}, + +$fragmentRefs: commitView_item$ref, + +$refType: commitsView_nodes$ref, +|}>; +*/ + + +const node/*: ConcreteFragment*/ = { + "kind": "Fragment", + "name": "commitsView_nodes", + "type": "Commit", + "metadata": { + "plural": true + }, + "argumentDefinitions": [], + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": "GitActor", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "name", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "user", + "storageKey": null, + "args": null, + "concreteType": "User", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + } + ] + } + ] + }, + { + "kind": "FragmentSpread", + "name": "commitView_item", + "args": null + } + ] +}; +// prettier-ignore +(node/*: any*/).hash = 'd0a17f07d02df54341e950344ec41a7f'; +module.exports = node; diff --git a/lib/views/timeline-items/__generated__/crossReferencedEventView_item.graphql.js b/lib/views/timeline-items/__generated__/crossReferencedEventView_item.graphql.js new file mode 100644 index 0000000000..aa95dffc61 --- /dev/null +++ b/lib/views/timeline-items/__generated__/crossReferencedEventView_item.graphql.js @@ -0,0 +1,179 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +export type IssueState = "CLOSED" | "OPEN" | "%future added value"; +export type PullRequestState = "CLOSED" | "MERGED" | "OPEN" | "%future added value"; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type crossReferencedEventView_item$ref: FragmentReference; +export type crossReferencedEventView_item = {| + +id: string, + +isCrossRepository: boolean, + +source: {| + +__typename: string, + +repository?: {| + +name: string, + +isPrivate: boolean, + +owner: {| + +login: string + |}, + |}, + +number?: number, + +title?: string, + +url?: any, + +issueState?: IssueState, + +prState?: PullRequestState, + |}, + +$refType: crossReferencedEventView_item$ref, +|}; +*/ + + +const node/*: ConcreteFragment*/ = (function(){ +var v0 = { + "kind": "ScalarField", + "alias": null, + "name": "number", + "args": null, + "storageKey": null +}, +v1 = { + "kind": "ScalarField", + "alias": null, + "name": "title", + "args": null, + "storageKey": null +}, +v2 = { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null +}; +return { + "kind": "Fragment", + "name": "crossReferencedEventView_item", + "type": "CrossReferencedEvent", + "metadata": null, + "argumentDefinitions": [], + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "isCrossRepository", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "source", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "__typename", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": null, + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "name", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "isPrivate", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "owner", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + } + ] + } + ] + }, + { + "kind": "InlineFragment", + "type": "PullRequest", + "selections": [ + v0, + v1, + v2, + { + "kind": "ScalarField", + "alias": "prState", + "name": "state", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "InlineFragment", + "type": "Issue", + "selections": [ + v0, + v1, + v2, + { + "kind": "ScalarField", + "alias": "issueState", + "name": "state", + "args": null, + "storageKey": null + } + ] + } + ] + } + ] +}; +})(); +// prettier-ignore +(node/*: any*/).hash = 'b90b8c9f0acee56516e7413263cf7f51'; +module.exports = node; diff --git a/lib/views/timeline-items/__generated__/crossReferencedEventsView_nodes.graphql.js b/lib/views/timeline-items/__generated__/crossReferencedEventsView_nodes.graphql.js new file mode 100644 index 0000000000..de1bcffdd1 --- /dev/null +++ b/lib/views/timeline-items/__generated__/crossReferencedEventsView_nodes.graphql.js @@ -0,0 +1,152 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +type crossReferencedEventView_item$ref = any; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type crossReferencedEventsView_nodes$ref: FragmentReference; +export type crossReferencedEventsView_nodes = $ReadOnlyArray<{| + +id: string, + +referencedAt: any, + +isCrossRepository: boolean, + +actor: ?{| + +login: string, + +avatarUrl: any, + |}, + +source: {| + +__typename: string, + +repository?: {| + +name: string, + +owner: {| + +login: string + |}, + |}, + |}, + +$fragmentRefs: crossReferencedEventView_item$ref, + +$refType: crossReferencedEventsView_nodes$ref, +|}>; +*/ + + +const node/*: ConcreteFragment*/ = (function(){ +var v0 = { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null +}; +return { + "kind": "Fragment", + "name": "crossReferencedEventsView_nodes", + "type": "CrossReferencedEvent", + "metadata": { + "plural": true + }, + "argumentDefinitions": [], + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "referencedAt", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "isCrossRepository", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "actor", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v0, + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "source", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "__typename", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": null, + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "name", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "owner", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v0 + ] + } + ] + } + ] + }, + { + "kind": "FragmentSpread", + "name": "crossReferencedEventView_item", + "args": null + } + ] +}; +})(); +// prettier-ignore +(node/*: any*/).hash = '5bbb7b39e10559bac4af2d6f9ff7a9e2'; +module.exports = node; diff --git a/lib/views/timeline-items/__generated__/headRefForcePushedEventView_issueish.graphql.js b/lib/views/timeline-items/__generated__/headRefForcePushedEventView_issueish.graphql.js new file mode 100644 index 0000000000..096a04ceac --- /dev/null +++ b/lib/views/timeline-items/__generated__/headRefForcePushedEventView_issueish.graphql.js @@ -0,0 +1,88 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type headRefForcePushedEventView_issueish$ref: FragmentReference; +export type headRefForcePushedEventView_issueish = {| + +headRefName: string, + +headRepositoryOwner: ?{| + +login: string + |}, + +repository: {| + +owner: {| + +login: string + |} + |}, + +$refType: headRefForcePushedEventView_issueish$ref, +|}; +*/ + + +const node/*: ConcreteFragment*/ = (function(){ +var v0 = [ + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + } +]; +return { + "kind": "Fragment", + "name": "headRefForcePushedEventView_issueish", + "type": "PullRequest", + "metadata": null, + "argumentDefinitions": [], + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "headRefName", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "headRepositoryOwner", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": v0 + }, + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": null, + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "owner", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": v0 + } + ] + } + ] +}; +})(); +// prettier-ignore +(node/*: any*/).hash = '4c639070afc4a02cedf062d836d0dd7f'; +module.exports = node; diff --git a/lib/views/timeline-items/__generated__/headRefForcePushedEventView_item.graphql.js b/lib/views/timeline-items/__generated__/headRefForcePushedEventView_item.graphql.js new file mode 100644 index 0000000000..ee92dc785c --- /dev/null +++ b/lib/views/timeline-items/__generated__/headRefForcePushedEventView_item.graphql.js @@ -0,0 +1,104 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type headRefForcePushedEventView_item$ref: FragmentReference; +export type headRefForcePushedEventView_item = {| + +actor: ?{| + +avatarUrl: any, + +login: string, + |}, + +beforeCommit: ?{| + +oid: any + |}, + +afterCommit: ?{| + +oid: any + |}, + +createdAt: any, + +$refType: headRefForcePushedEventView_item$ref, +|}; +*/ + + +const node/*: ConcreteFragment*/ = (function(){ +var v0 = [ + { + "kind": "ScalarField", + "alias": null, + "name": "oid", + "args": null, + "storageKey": null + } +]; +return { + "kind": "Fragment", + "name": "headRefForcePushedEventView_item", + "type": "HeadRefForcePushedEvent", + "metadata": null, + "argumentDefinitions": [], + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "actor", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "beforeCommit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v0 + }, + { + "kind": "LinkedField", + "alias": null, + "name": "afterCommit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v0 + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + } + ] +}; +})(); +// prettier-ignore +(node/*: any*/).hash = 'fc403545674c57c1997c870805101ffb'; +module.exports = node; diff --git a/lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js b/lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js new file mode 100644 index 0000000000..6f68a9f803 --- /dev/null +++ b/lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js @@ -0,0 +1,75 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type issueCommentView_item$ref: FragmentReference; +export type issueCommentView_item = {| + +author: ?{| + +avatarUrl: any, + +login: string, + |}, + +bodyHTML: any, + +createdAt: any, + +$refType: issueCommentView_item$ref, +|}; +*/ + + +const node/*: ConcreteFragment*/ = { + "kind": "Fragment", + "name": "issueCommentView_item", + "type": "IssueComment", + "metadata": null, + "argumentDefinitions": [], + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "bodyHTML", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + } + ] +}; +// prettier-ignore +(node/*: any*/).hash = '802c96476c5abd33c8c2470b2424a584'; +module.exports = node; diff --git a/lib/views/timeline-items/__generated__/mergedEventView_item.graphql.js b/lib/views/timeline-items/__generated__/mergedEventView_item.graphql.js new file mode 100644 index 0000000000..1d1fa6d560 --- /dev/null +++ b/lib/views/timeline-items/__generated__/mergedEventView_item.graphql.js @@ -0,0 +1,96 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type mergedEventView_item$ref: FragmentReference; +export type mergedEventView_item = {| + +actor: ?{| + +avatarUrl: any, + +login: string, + |}, + +commit: ?{| + +oid: any + |}, + +mergeRefName: string, + +createdAt: any, + +$refType: mergedEventView_item$ref, +|}; +*/ + + +const node/*: ConcreteFragment*/ = { + "kind": "Fragment", + "name": "mergedEventView_item", + "type": "MergedEvent", + "metadata": null, + "argumentDefinitions": [], + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "actor", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "oid", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "mergeRefName", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + } + ] +}; +// prettier-ignore +(node/*: any*/).hash = 'd265decf08c14d96c2ec47fd5852a956'; +module.exports = node; diff --git a/lib/views/timeline-items/commits-view.js b/lib/views/timeline-items/commits-view.js index e9938797e8..7d296507cc 100644 --- a/lib/views/timeline-items/commits-view.js +++ b/lib/views/timeline-items/commits-view.js @@ -80,7 +80,7 @@ export class BareCommitsView extends React.Component { export default createFragmentContainer(BareCommitsView, { nodes: graphql` - fragment commitsContainer_nodes on Commit @relay(plural: true) { + fragment commitsView_nodes on Commit @relay(plural: true) { id author { name user { login } } ...commitView_item } diff --git a/test/containers/current-pull-request-container.test.js b/test/containers/current-pull-request-container.test.js index ddc8420361..08fdb0df0e 100644 --- a/test/containers/current-pull-request-container.test.js +++ b/test/containers/current-pull-request-container.test.js @@ -159,7 +159,7 @@ describe('CurrentPullRequestContainer', function() { assert.deepEqual(controller.prop('results').map(result => result.number), [10]); }); - it('filters out pull requests opened on different repositories', async function() { + it.only('filters out pull requests opened on different repositories', async function() { const repository = createRepositoryResult({id: 'upstream-repo'}); const {resolve, promise} = useResults( @@ -172,7 +172,7 @@ describe('CurrentPullRequestContainer', function() { await promise; wrapper.update(); - const numbers = wrapper.find('.github-IssueishList-item--number').map(n => n.text()); + const numbers = wrapper.find('IssueishListView').prop('issueishes').map(i => i.number()); assert.deepEqual(numbers, ['#11']); }); diff --git a/test/views/timeline-items/commit-comment-thread-view.test.js b/test/views/timeline-items/commit-comment-thread-view.test.js index 7e75e24ab9..b80c1942a4 100644 --- a/test/views/timeline-items/commit-comment-thread-view.test.js +++ b/test/views/timeline-items/commit-comment-thread-view.test.js @@ -24,7 +24,7 @@ describe('CommitCommentThreadView', function() { ], })); - const commentViews = wrapper.find('Relay(CommitComment)'); + const commentViews = wrapper.find('Relay(BareCommitCommentView)'); assert.deepEqual(commentViews.map(c => c.prop('item').author.login), ['user0', 'user1', 'user2']); From 5b8f2263eaa88d2695bd50e5c5f6ef9e327a5cbd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 15:45:59 -0400 Subject: [PATCH 0429/4847] PRs need distinct IDs --- test/containers/current-pull-request-container.test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/containers/current-pull-request-container.test.js b/test/containers/current-pull-request-container.test.js index 08fdb0df0e..2b61307b8a 100644 --- a/test/containers/current-pull-request-container.test.js +++ b/test/containers/current-pull-request-container.test.js @@ -159,12 +159,12 @@ describe('CurrentPullRequestContainer', function() { assert.deepEqual(controller.prop('results').map(result => result.number), [10]); }); - it.only('filters out pull requests opened on different repositories', async function() { + it('filters out pull requests opened on different repositories', async function() { const repository = createRepositoryResult({id: 'upstream-repo'}); const {resolve, promise} = useResults( - {number: 11, repositoryID: 'upstream-repo'}, - {number: 22, repositoryID: 'someones-fork'}, + {id: 'pr0', number: 11, repositoryID: 'upstream-repo'}, + {id: 'pr1', number: 22, repositoryID: 'someones-fork'}, ); const wrapper = mount(buildApp({repository})); @@ -172,8 +172,8 @@ describe('CurrentPullRequestContainer', function() { await promise; wrapper.update(); - const numbers = wrapper.find('IssueishListView').prop('issueishes').map(i => i.number()); - assert.deepEqual(numbers, ['#11']); + const numbers = wrapper.find('IssueishListView').prop('issueishes').map(i => i.getNumber()); + assert.deepEqual(numbers, [11]); }); it('performs the query again when a remote operation completes', async function() { From 5b18049edb260411ed53be4c052217949e17e811 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 15:52:00 -0400 Subject: [PATCH 0430/4847] Missing .exists() --- test/views/timeline-items/cross-referenced-event-view.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/views/timeline-items/cross-referenced-event-view.test.js b/test/views/timeline-items/cross-referenced-event-view.test.js index e745b31246..b68e869fb8 100644 --- a/test/views/timeline-items/cross-referenced-event-view.test.js +++ b/test/views/timeline-items/cross-referenced-event-view.test.js @@ -50,6 +50,6 @@ describe('CrossReferencedEventView', function() { repositoryIsPrivate: true, })); - assert.isTrue(wrapper.find('.cross-referenced-event-private Octicon[icon="lock"]')); + assert.isTrue(wrapper.find('.cross-referenced-event-private Octicon[icon="lock"]').exists()); }); }); From 3e811a958bc9e1c282acc1d60d5c5083659310d4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 15:53:00 -0400 Subject: [PATCH 0431/4847] idGen isn't a function --- test/fixtures/factories/pull-request-result.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/factories/pull-request-result.js b/test/fixtures/factories/pull-request-result.js index 75e63e3043..1a265d875c 100644 --- a/test/fixtures/factories/pull-request-result.js +++ b/test/fixtures/factories/pull-request-result.js @@ -137,7 +137,7 @@ export function createPullRequestDetailResult(attrs = {}) { bodyHTML: '

    body

    ', author: { __typename: 'User', - id: idGen('user'), + id: idGen.generate('user'), login: o.authorLogin, avatarUrl: o.authorAvatarURL, url: `https://github.com/${o.authorLogin}`, From c274eb8c585409d86499df50127e7392074b8bcb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 15:55:32 -0400 Subject: [PATCH 0432/4847] Component name changes --- test/views/issueish-detail-view.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/views/issueish-detail-view.test.js b/test/views/issueish-detail-view.test.js index 7c0b3eff75..c522425cff 100644 --- a/test/views/issueish-detail-view.test.js +++ b/test/views/issueish-detail-view.test.js @@ -32,7 +32,7 @@ describe('IssueishDetailView', function() { assert.strictEqual(link.text(), 'user0/repo#100'); assert.strictEqual(link.prop('href'), 'https://github.com/user0/repo/pull/100'); - assert.isDefined(wrapper.find('Relay(PrStatuses)[displayType="check"]').prop('pullRequest')); + assert.isDefined(wrapper.find('Relay(BarePrStatusesView)[displayType="check"]').prop('pullRequest')); const avatarLink = wrapper.find('.github-IssueishDetailView-avatar'); assert.strictEqual(avatarLink.prop('href'), 'https://github.com/author0'); @@ -51,7 +51,7 @@ describe('IssueishDetailView', function() { assert.isNull(wrapper.find('Relay(IssueishTimelineView)').prop('issue')); assert.isNotNull(wrapper.find('Relay(IssueishTimelineView)').prop('pullRequest')); - assert.isNotNull(wrapper.find('Relay(PrStatuses)[displayType="full"]').prop('pullRequest')); + assert.isNotNull(wrapper.find('Relay(BarePrStatusesView)[displayType="full"]').prop('pullRequest')); }); it('renders issue information', function() { From 68415e27860b3df54240979b0024ec22bc189597 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 15:57:04 -0400 Subject: [PATCH 0433/4847] More PR ids --- test/containers/issueish-search-container.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/containers/issueish-search-container.test.js b/test/containers/issueish-search-container.test.js index e682a5193f..c9aaa1c596 100644 --- a/test/containers/issueish-search-container.test.js +++ b/test/containers/issueish-search-container.test.js @@ -112,8 +112,8 @@ describe('IssueishSearchContainer', function() { search: { issueCount: 2, nodes: [ - createPullRequestResult({number: 1}), - createPullRequestResult({number: 2}), + createPullRequestResult({id: 'pr0', number: 1}), + createPullRequestResult({id: 'pr1', number: 2}), ], }, }); From a29511a836702277f8609d1a7afd291256cc7851 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 2 Jul 2018 15:59:15 -0400 Subject: [PATCH 0434/4847] More component names --- test/views/issueish-timeline-view.test.js | 10 +++++----- test/views/pr-statuses-view.test.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/views/issueish-timeline-view.test.js b/test/views/issueish-timeline-view.test.js index d170e84173..819fa9c422 100644 --- a/test/views/issueish-timeline-view.test.js +++ b/test/views/issueish-timeline-view.test.js @@ -71,19 +71,19 @@ describe('IssueishTimelineView', function() { ], })); - const commitGroup0 = wrapper.find('Relay(Commits)').filterWhere(c => c.prop('nodes').length === 2); + const commitGroup0 = wrapper.find('Relay(BareCommitsView)').filterWhere(c => c.prop('nodes').length === 2); assert.deepEqual(commitGroup0.prop('nodes').map(n => n.id), [0, 1]); - const commentGroup0 = wrapper.find('Grouped(Relay(IssueComment))').filterWhere(c => c.prop('nodes').length === 1); + const commentGroup0 = wrapper.find('Grouped(Relay(BareIssueCommentView))').filterWhere(c => c.prop('nodes').length === 1); assert.deepEqual(commentGroup0.prop('nodes').map(n => n.id), [2]); - const mergedGroup = wrapper.find('Grouped(Relay(MergedEvent))').filterWhere(c => c.prop('nodes').length === 1); + const mergedGroup = wrapper.find('Grouped(Relay(BareMergedEventView))').filterWhere(c => c.prop('nodes').length === 1); assert.deepEqual(mergedGroup.prop('nodes').map(n => n.id), [3]); - const commitGroup1 = wrapper.find('Relay(Commits)').filterWhere(c => c.prop('nodes').length === 4); + const commitGroup1 = wrapper.find('Relay(BareCommitsView)').filterWhere(c => c.prop('nodes').length === 4); assert.deepEqual(commitGroup1.prop('nodes').map(n => n.id), [4, 5, 6, 7]); - const commentGroup1 = wrapper.find('Grouped(Relay(IssueComment))').filterWhere(c => c.prop('nodes').length === 2); + const commentGroup1 = wrapper.find('Grouped(Relay(BareIssueCommentView))').filterWhere(c => c.prop('nodes').length === 2); assert.deepEqual(commentGroup1.prop('nodes').map(n => n.id), [8, 9]); }); diff --git a/test/views/pr-statuses-view.test.js b/test/views/pr-statuses-view.test.js index dfd5ac33a2..4bd9f2509b 100644 --- a/test/views/pr-statuses-view.test.js +++ b/test/views/pr-statuses-view.test.js @@ -109,7 +109,7 @@ describe('PrStatusesView', function() { it('renders a context view for each status context', function() { const wrapper = shallow(buildApp({summaryState: 'FAILURE', states: ['SUCCESS', 'FAILURE', 'ERROR']})); - const contextViews = wrapper.find('Relay(PrStatusContext)'); + const contextViews = wrapper.find('Relay(BarePrStatusContextView)'); assert.deepEqual(contextViews.map(v => v.prop('context').state), ['SUCCESS', 'FAILURE', 'ERROR']); }); From 4ddf13f3d92e91d215809f7950fb5fbe715f265a Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 2 Jul 2018 14:06:04 -0700 Subject: [PATCH 0435/4847] add `metrics-reporter` to `package.json` as a consumed service. --- package.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/package.json b/package.json index e58ae43530..a94b49f198 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,13 @@ "fetch-schema": "node script/fetch-schema", "relay": "relay-compiler --src ./lib --schema graphql/schema.graphql" }, + "consumedServices": { + "metrics-reporter": { + "versions": { + "^1.1.0": "consumeReporter" + } + } + }, "engines": { "atom": ">=1.18.0" }, From bd887eac3c588d35cbf93d799579afe40e77bd6a Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 2 Jul 2018 14:23:56 -0700 Subject: [PATCH 0436/4847] consumedServices already existed. Oops. --- package.json | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index a94b49f198..8f394a05f3 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,6 @@ "fetch-schema": "node script/fetch-schema", "relay": "relay-compiler --src ./lib --schema graphql/schema.graphql" }, - "consumedServices": { - "metrics-reporter": { - "versions": { - "^1.1.0": "consumeReporter" - } - } - }, "engines": { "atom": ">=1.18.0" }, @@ -103,6 +96,11 @@ "versions": { "^1.0.0": "consumeStatusBar" } + }, + "metrics-reporter": { + "versions": { + "^1.1.0": "consumeReporter" + } } }, "configSchema": { From 7c66926f74f33e863efdaccfb14c839467ce3890 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 2 Jul 2018 17:12:55 -0700 Subject: [PATCH 0437/4847] add `ReporterProxy` class --- lib/github-package.js | 5 ++++ lib/reporter-proxy.js | 59 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 lib/reporter-proxy.js diff --git a/lib/github-package.js b/lib/github-package.js index 2937a9992d..567a4d2b53 100644 --- a/lib/github-package.js +++ b/lib/github-package.js @@ -21,6 +21,7 @@ import ContextMenuInterceptor from './context-menu-interceptor'; import AsyncQueue from './async-queue'; import WorkerManager from './worker-manager'; import getRepoPipelineManager from './get-repo-pipeline-manager'; +import {reporterProxy} from './reporter-proxy'; const defaultState = { newProject: true, @@ -310,6 +311,10 @@ export default class GithubPackage { this.rerender(); } + consumeReporter(reporter) { + reporterProxy.setReporter(reporter); + } + createGitTimingsView() { return StubItem.create('git-timings-view', { title: 'GitHub Package Timings View', diff --git a/lib/reporter-proxy.js b/lib/reporter-proxy.js new file mode 100644 index 0000000000..e08c8c7266 --- /dev/null +++ b/lib/reporter-proxy.js @@ -0,0 +1,59 @@ +// this class allows us to call reporter methods +// before the reporter is actually loaded, since we don't want to +// assume that the metrics package will load before the GitHub package. + +// maybe this should be an object instead of a class. +// IDK. +class ReporterProxy { + constructor() { + this.reporter = null; + this.events = []; + this.timings = []; + this.counters = []; + } + + // function that is called after the reporter is actually loaded, to + // set the reporter and send anydata that have accumulated while it was loading. + setReporter(reporter) { + this.reporter = reporter; + + this.events.forEach((customEvent) => { + this.reporter.addCustomEvent(...customEvent); + }); + + this.timings.forEach((timing) => { + this.reporter.addTiming(...timing); + }); + + this.counters.forEach((counterName) => { + this.reporter.incrementCounter(counterName); + }); + } +} + +export const reporterProxy = new ReporterProxy(); + +export const incrementCounter = function(counterName) { + if (reporterProxy.reporter) { + reporterProxy.reporter.incrementCounter(counterName); + } + else { + reporterProxy.counters.push(counterName); + } +} + +export const addTiming = function(eventType, durationInMilliseconds, metadata = {}) { + if (reporterProxy.reporter) { + reporterProxy.reporter.addTiming(eventType, durationInMilliseconds, metadata); + } else { + reporterProxy.timings.push({ eventType, durationInMilliseconds, metadata}); + } +} + +export const addEvent = function(eventType, event) { + if (reporterProxy.reporter) { + reporterProxy.reporter.addCustomEvent(eventType, event); + } else { + reporterProxy.events.push({ eventType, event }); + } +} From b46cf3c713fadbc091c892ba3201d0b9c0af5561 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 2 Jul 2018 18:07:36 -0700 Subject: [PATCH 0438/4847] send an event when a commit happens. --- lib/git-shell-out-strategy.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index a5f7cb48a2..f74927c030 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -13,6 +13,7 @@ import {parse as parseStatus} from 'what-the-status'; import GitPromptServer from './git-prompt-server'; import GitTempDir from './git-temp-dir'; import AsyncQueue from './async-queue'; +import {addEvent} from './reporter-proxy'; import { getDugitePath, getSharedModulePath, getAtomHelperPath, extractCoAuthorsAndRawCommitMessage, fileExists, isFileExecutable, isFileSymlink, isBinary, @@ -473,7 +474,10 @@ export default class GitShellOutStrategy { if (amend) { args.push('--amend'); } if (allowEmpty) { args.push('--allow-empty'); } - return this.gpgExec(args, {writeOperation: true}); + const returnValue = await this.gpgExec(args, {writeOperation: true}); + // todo: if the commit fails for some reason, don't increment the counter here. + addEvent('commit', {coAuthors: coAuthors && coAuthors.length || 0}); + return returnValue; } addCoAuthorsToMessage(message, coAuthors = []) { From 7063957b2fff26645eb37b8dd8ebeac0830a2024 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 08:17:24 -0400 Subject: [PATCH 0439/4847] getURI() is never called --- lib/items/issueish-pane-item.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/items/issueish-pane-item.js b/lib/items/issueish-pane-item.js index 4a1d7e809b..e25b69743e 100644 --- a/lib/items/issueish-pane-item.js +++ b/lib/items/issueish-pane-item.js @@ -95,10 +95,6 @@ export default class IssueishPaneItem extends Component { }; } - getURI() { - return this.constructor.buildURI(this.props.host, this.props.owner, this.props.repo, this.props.issueishNumber); - } - getTitle() { return this.title; } From 5072a76878416d1f7166512317698c4b9668fc53 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 08:23:53 -0400 Subject: [PATCH 0440/4847] Exercise the logout prop --- lib/containers/issueish-detail-container.js | 4 ++-- test/containers/issueish-detail-container.test.js | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index 2189fc3abb..6f974ba96b 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -127,10 +127,10 @@ export default class IssueishDetailContainer extends React.Component { } handleLogin(token) { - this.props.loginModel.setToken(this.props.host, token); + return this.props.loginModel.setToken(this.props.host, token); } handleLogout() { - this.props.loginModel.removeToken(this.props.host); + return this.props.loginModel.removeToken(this.props.host); } } diff --git a/test/containers/issueish-detail-container.test.js b/test/containers/issueish-detail-container.test.js index 7a8d20ec16..81bef738d3 100644 --- a/test/containers/issueish-detail-container.test.js +++ b/test/containers/issueish-detail-container.test.js @@ -5,7 +5,7 @@ import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import {issueishDetailContainerProps} from '../fixtures/props/issueish-pane-props'; import {createPullRequestDetailResult} from '../fixtures/factories/pull-request-result'; import GithubLoginModel from '../../lib/models/github-login-model'; -import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; +import {InMemoryStrategy, UNAUTHENTICATED} from '../../lib/shared/keytar-strategy'; import IssueishDetailContainer from '../../lib/containers/issueish-detail-container'; describe('IssueishDetailContainer', function() { @@ -99,7 +99,12 @@ describe('IssueishDetailContainer', function() { await promise.catch(() => {}); await assert.async.isTrue(wrapper.update().find('QueryErrorView').exists()); - assert.strictEqual(wrapper.find('QueryErrorView').prop('error'), e); + const ev = wrapper.find('QueryErrorView'); + assert.strictEqual(ev.prop('error'), e); + + assert.strictEqual(await loginModel.getToken('https://api.github.com'), '1234'); + await ev.prop('logout')(); + assert.strictEqual(await loginModel.getToken('https://api.github.com'), UNAUTHENTICATED); }); it('passes GraphQL query results to an IssueishDetailController', async function() { From 2e2e2e23e80c698ea207c426a887d9a83b96acdc Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 08:29:12 -0400 Subject: [PATCH 0441/4847] Cover the no-reply email case --- test/views/timeline-items/commit-view.test.js | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/test/views/timeline-items/commit-view.test.js b/test/views/timeline-items/commit-view.test.js index e6b5cc4161..6cabe0f44b 100644 --- a/test/views/timeline-items/commit-view.test.js +++ b/test/views/timeline-items/commit-view.test.js @@ -84,7 +84,7 @@ describe('CommitView', function() { ); }); - it('ignores committer when it authored by GitHub', function() { + it('ignores the committer when it is authored by GitHub', function() { const item = { author: { name: 'author_name', avatarUrl: '', @@ -111,6 +111,33 @@ describe('CommitView', function() { ); }); + it('ignores the committer when it uses the GitHub no-reply address', function() { + const item = { + author: { + name: 'author_name', avatarUrl: '', + user: { + login: 'author_login', + }, + }, + committer: { + name: 'Someone', email: 'noreply@github.com', avatarUrl: '', + user: null, + }, + oid: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', + authoredByCommitter: false, + message: 'commit message', + messageHeadlineHTML: '

    html

    ', + }; + const app = ; + const instance = shallow(app); + assert.isTrue( + instance.containsMatchingElement(), + ); + assert.isFalse( + instance.containsMatchingElement(), + ); + }); + it('renders avatar URLs', function() { const item = { author: { From 19aa6bcf2d9da08a17921f9de1a16ff1a6be3120 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 08:34:20 -0400 Subject: [PATCH 0442/4847] Use setProps() instead of update() to trigger componentDidUpdate --- test/views/github-dotcom-markdown.test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/views/github-dotcom-markdown.test.js b/test/views/github-dotcom-markdown.test.js index d198e43086..7b99cc7854 100644 --- a/test/views/github-dotcom-markdown.test.js +++ b/test/views/github-dotcom-markdown.test.js @@ -52,8 +52,6 @@ describe('GithubDotcomMarkdown', function() { handleClickEvent, })); - wrapper.update(); - const issueishLink = wrapper.getDOMNode().querySelector('a.issue-link'); issueishLink.dispatchEvent(new MouseEvent('click', { bubbles: true, @@ -70,6 +68,10 @@ describe('GithubDotcomMarkdown', function() { assert.strictEqual(handleClickEvent.callCount, 1); + // Force a componentDidUpdate to exercise tooltip handler re-registration + wrapper.setProps({}); + + // Unmount to unsubscribe wrapper.unmount(); }); From 69528513d58ce697a37f27a5e80bfe96f7699b40 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 08:53:18 -0400 Subject: [PATCH 0443/4847] Fixture repository with a .com remote --- test/fixtures/repo-dotcom-remote/aaa.txt | 1 + test/fixtures/repo-dotcom-remote/bbb.txt | 1 + test/fixtures/repo-dotcom-remote/ccc.txt | 1 + .../repo-dotcom-remote/dot-git/COMMIT_EDITMSG | 1 + test/fixtures/repo-dotcom-remote/dot-git/HEAD | 1 + test/fixtures/repo-dotcom-remote/dot-git/config | 10 ++++++++++ .../repo-dotcom-remote/dot-git/description | 1 + test/fixtures/repo-dotcom-remote/dot-git/index | Bin 0 -> 281 bytes .../repo-dotcom-remote/dot-git/info/exclude | 6 ++++++ .../fixtures/repo-dotcom-remote/dot-git/logs/HEAD | 1 + .../dot-git/logs/refs/heads/master | 1 + .../2a/81e58dd15cf000600574f01fce31a3468de3d2 | Bin 0 -> 789 bytes .../72/943a16fb2c8f38f9dde202b7a70ccc19c52f34 | Bin 0 -> 19 bytes .../b2/a7546679fdf79ca0eb7bfbee1e1bb342487380 | Bin 0 -> 19 bytes .../b3/81b181f9e34b91baa95e9d357ec40c56ee37fa | Bin 0 -> 109 bytes .../f7/61ec192d9f0dca3329044b96ebdb12839dbff6 | Bin 0 -> 19 bytes .../repo-dotcom-remote/dot-git/refs/heads/master | 1 + 17 files changed, 25 insertions(+) create mode 100644 test/fixtures/repo-dotcom-remote/aaa.txt create mode 100644 test/fixtures/repo-dotcom-remote/bbb.txt create mode 100644 test/fixtures/repo-dotcom-remote/ccc.txt create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/COMMIT_EDITMSG create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/HEAD create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/config create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/description create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/index create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/info/exclude create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/logs/HEAD create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/logs/refs/heads/master create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/objects/2a/81e58dd15cf000600574f01fce31a3468de3d2 create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34 create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/objects/b2/a7546679fdf79ca0eb7bfbee1e1bb342487380 create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/objects/b3/81b181f9e34b91baa95e9d357ec40c56ee37fa create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/objects/f7/61ec192d9f0dca3329044b96ebdb12839dbff6 create mode 100644 test/fixtures/repo-dotcom-remote/dot-git/refs/heads/master diff --git a/test/fixtures/repo-dotcom-remote/aaa.txt b/test/fixtures/repo-dotcom-remote/aaa.txt new file mode 100644 index 0000000000..72943a16fb --- /dev/null +++ b/test/fixtures/repo-dotcom-remote/aaa.txt @@ -0,0 +1 @@ +aaa diff --git a/test/fixtures/repo-dotcom-remote/bbb.txt b/test/fixtures/repo-dotcom-remote/bbb.txt new file mode 100644 index 0000000000..f761ec192d --- /dev/null +++ b/test/fixtures/repo-dotcom-remote/bbb.txt @@ -0,0 +1 @@ +bbb diff --git a/test/fixtures/repo-dotcom-remote/ccc.txt b/test/fixtures/repo-dotcom-remote/ccc.txt new file mode 100644 index 0000000000..b2a7546679 --- /dev/null +++ b/test/fixtures/repo-dotcom-remote/ccc.txt @@ -0,0 +1 @@ +ccc diff --git a/test/fixtures/repo-dotcom-remote/dot-git/COMMIT_EDITMSG b/test/fixtures/repo-dotcom-remote/dot-git/COMMIT_EDITMSG new file mode 100644 index 0000000000..8026076649 --- /dev/null +++ b/test/fixtures/repo-dotcom-remote/dot-git/COMMIT_EDITMSG @@ -0,0 +1 @@ +initial commit diff --git a/test/fixtures/repo-dotcom-remote/dot-git/HEAD b/test/fixtures/repo-dotcom-remote/dot-git/HEAD new file mode 100644 index 0000000000..cb089cd89a --- /dev/null +++ b/test/fixtures/repo-dotcom-remote/dot-git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/test/fixtures/repo-dotcom-remote/dot-git/config b/test/fixtures/repo-dotcom-remote/dot-git/config new file mode 100644 index 0000000000..562e0de5b0 --- /dev/null +++ b/test/fixtures/repo-dotcom-remote/dot-git/config @@ -0,0 +1,10 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = git@github.com:owner/repo.git + fetch = +refs/heads/*:refs/remotes/origin/* diff --git a/test/fixtures/repo-dotcom-remote/dot-git/description b/test/fixtures/repo-dotcom-remote/dot-git/description new file mode 100644 index 0000000000..498b267a8c --- /dev/null +++ b/test/fixtures/repo-dotcom-remote/dot-git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/test/fixtures/repo-dotcom-remote/dot-git/index b/test/fixtures/repo-dotcom-remote/dot-git/index new file mode 100644 index 0000000000000000000000000000000000000000..6d8781392adb10b5d60f512540101dbbd9f49378 GIT binary patch literal 281 zcmZ?q402{*U|<4b=4k7JiJBK!^kFn30|N`o(qoYf42??|7#P0-)rbHwOVJc7vEMrV z7C-MkV%ol(=Zxf0eG>-u#Kc6sl8O?b0-*k>OqN$YVKmg7XmoSFC%%!?ozHv9Sd+zj z+Uwgw&2#sEV_;88NG>+0X{ 1530622117 -0400 commit (initial): initial commit diff --git a/test/fixtures/repo-dotcom-remote/dot-git/logs/refs/heads/master b/test/fixtures/repo-dotcom-remote/dot-git/logs/refs/heads/master new file mode 100644 index 0000000000..a021157a5a --- /dev/null +++ b/test/fixtures/repo-dotcom-remote/dot-git/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 2a81e58dd15cf000600574f01fce31a3468de3d2 Ash Wilson 1530622117 -0400 commit (initial): initial commit diff --git a/test/fixtures/repo-dotcom-remote/dot-git/objects/2a/81e58dd15cf000600574f01fce31a3468de3d2 b/test/fixtures/repo-dotcom-remote/dot-git/objects/2a/81e58dd15cf000600574f01fce31a3468de3d2 new file mode 100644 index 0000000000000000000000000000000000000000..338a00439c1d9de46e3b98252a3643a466003706 GIT binary patch literal 789 zcmV+w1M2*E0iBb{&ZAZkg|p@#r^qU}+59fa!1E0wc-8mjp;&r*%;^%Omk9;@)35zb9JhmIixlZt#e>nr)nly!lATDPg19 z@*Fn(%Hz)Z+3-%x#wHxqH8?eEea_S0P!MI^-94o6uDqM&QIF}6c@*k6G;Xx_@`%!S zQ&Fj+*Bt}pbYq%B780@34|b&SgGtnsJsG%pidHEqlzo46mpt+st`X1dnk!IuH0SQG z)h&IA7?7q*8P4Ie;K$c9l|v<-<1OE6nwb01N(Nbe-p^W7oyTTlIWJygU!tvb4X%p` zZ;ti3p@_C69WRBw$Ci}~4Uv-e_2JK5UsvAqT0O0O#fwSAeOvP~Qo8ypjC9_q^THs? z6azbN>FoN@_H;8(yd~wQWrTO`=r@uE-^N>56=R`7QcIi|&EkeGVgH(-OD>GjNk0x4 zXsx506+u3PRoMu1qz7pBj`QI%lPx+K&b$=woK7PK@6n>Q2fshLFo6foqq;te5e9~0 zy&AF9kqx5#oV*jy%7r$S@JIC?#jmQlKaN`vsRax+r{C1;iC literal 0 HcmV?d00001 diff --git a/test/fixtures/repo-dotcom-remote/dot-git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34 b/test/fixtures/repo-dotcom-remote/dot-git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34 new file mode 100644 index 0000000000000000000000000000000000000000..dcc78722fe99ad70a05819b5545d5242f0216e2c GIT binary patch literal 19 acmbx-;s%2N literal 0 HcmV?d00001 diff --git a/test/fixtures/repo-dotcom-remote/dot-git/objects/b2/a7546679fdf79ca0eb7bfbee1e1bb342487380 b/test/fixtures/repo-dotcom-remote/dot-git/objects/b2/a7546679fdf79ca0eb7bfbee1e1bb342487380 new file mode 100644 index 0000000000000000000000000000000000000000..c396a515ee487a5dd4f5cb867e883c57650f6c76 GIT binary patch literal 19 acmb7Fl8__FfcPQQAkWo)GMhdVJMnnCH7mV-{R-pM@-w7^PG`9 zs&4{Sl9ZGLR`NaZjil~;-c!b!EZ);z-xg|~yZ;+hNpf;BSjnd4A!(I=zt36ly88D! PIqA(#9>om+GXX6}Fg`NS literal 0 HcmV?d00001 diff --git a/test/fixtures/repo-dotcom-remote/dot-git/objects/f7/61ec192d9f0dca3329044b96ebdb12839dbff6 b/test/fixtures/repo-dotcom-remote/dot-git/objects/f7/61ec192d9f0dca3329044b96ebdb12839dbff6 new file mode 100644 index 0000000000000000000000000000000000000000..725953ba39b33c01be52b9ae433dbf9175029578 GIT binary patch literal 19 acmb Date: Tue, 3 Jul 2018 06:20:50 -0700 Subject: [PATCH 0444/4847] Merge pull request #1561 from atom/dw-fix-nightly-tests Add support for nightly channel --- lib/helpers.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/helpers.js b/lib/helpers.js index 6109ee9c0c..b346d6bd83 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -72,10 +72,18 @@ export function getPackageRoot() { } } +function getAtomAppName() { + const match = atom.getVersion().match(/beta|nightly/) + if (match) { + return `Atom ${match[0].charAt(0).toUpperCase() + match[0].slice(1)} Helper` + } + + return 'Atom Helper' +} + export function getAtomHelperPath() { if (process.platform === 'darwin') { - const beta = atom.appVersion.match(/-beta/); - const appName = beta ? 'Atom Beta Helper' : 'Atom Helper'; + const appName = getAtomAppName() return path.resolve(process.resourcesPath, '..', 'Frameworks', `${appName}.app`, 'Contents', 'MacOS', appName); } else { From 1112a4542daf8ff1a2f2add64739999ba94875d8 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 3 Jul 2018 07:01:04 -0700 Subject: [PATCH 0445/4847] :shirt: --- lib/helpers.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/helpers.js b/lib/helpers.js index b346d6bd83..edfed59365 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -73,17 +73,17 @@ export function getPackageRoot() { } function getAtomAppName() { - const match = atom.getVersion().match(/beta|nightly/) + const match = atom.getVersion().match(/beta|nightly/); if (match) { - return `Atom ${match[0].charAt(0).toUpperCase() + match[0].slice(1)} Helper` + return `Atom ${match[0].charAt(0).toUpperCase() + match[0].slice(1)} Helper`; } - return 'Atom Helper' + return 'Atom Helper'; } export function getAtomHelperPath() { if (process.platform === 'darwin') { - const appName = getAtomAppName() + const appName = getAtomAppName(); return path.resolve(process.resourcesPath, '..', 'Frameworks', `${appName}.app`, 'Contents', 'MacOS', appName); } else { From 4f60b4b9d274f174a2320c8a6c55aa07c7d5a714 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 14:32:50 -0400 Subject: [PATCH 0446/4847] Okay actually that fixture is pointless --- test/fixtures/repo-dotcom-remote/aaa.txt | 1 - test/fixtures/repo-dotcom-remote/bbb.txt | 1 - test/fixtures/repo-dotcom-remote/ccc.txt | 1 - .../repo-dotcom-remote/dot-git/COMMIT_EDITMSG | 1 - test/fixtures/repo-dotcom-remote/dot-git/HEAD | 1 - test/fixtures/repo-dotcom-remote/dot-git/config | 10 ---------- .../repo-dotcom-remote/dot-git/description | 1 - test/fixtures/repo-dotcom-remote/dot-git/index | Bin 281 -> 0 bytes .../repo-dotcom-remote/dot-git/info/exclude | 6 ------ .../fixtures/repo-dotcom-remote/dot-git/logs/HEAD | 1 - .../dot-git/logs/refs/heads/master | 1 - .../2a/81e58dd15cf000600574f01fce31a3468de3d2 | Bin 789 -> 0 bytes .../72/943a16fb2c8f38f9dde202b7a70ccc19c52f34 | Bin 19 -> 0 bytes .../b2/a7546679fdf79ca0eb7bfbee1e1bb342487380 | Bin 19 -> 0 bytes .../b3/81b181f9e34b91baa95e9d357ec40c56ee37fa | Bin 109 -> 0 bytes .../f7/61ec192d9f0dca3329044b96ebdb12839dbff6 | Bin 19 -> 0 bytes .../repo-dotcom-remote/dot-git/refs/heads/master | 1 - 17 files changed, 25 deletions(-) delete mode 100644 test/fixtures/repo-dotcom-remote/aaa.txt delete mode 100644 test/fixtures/repo-dotcom-remote/bbb.txt delete mode 100644 test/fixtures/repo-dotcom-remote/ccc.txt delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/COMMIT_EDITMSG delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/HEAD delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/config delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/description delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/index delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/info/exclude delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/logs/HEAD delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/logs/refs/heads/master delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/objects/2a/81e58dd15cf000600574f01fce31a3468de3d2 delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34 delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/objects/b2/a7546679fdf79ca0eb7bfbee1e1bb342487380 delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/objects/b3/81b181f9e34b91baa95e9d357ec40c56ee37fa delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/objects/f7/61ec192d9f0dca3329044b96ebdb12839dbff6 delete mode 100644 test/fixtures/repo-dotcom-remote/dot-git/refs/heads/master diff --git a/test/fixtures/repo-dotcom-remote/aaa.txt b/test/fixtures/repo-dotcom-remote/aaa.txt deleted file mode 100644 index 72943a16fb..0000000000 --- a/test/fixtures/repo-dotcom-remote/aaa.txt +++ /dev/null @@ -1 +0,0 @@ -aaa diff --git a/test/fixtures/repo-dotcom-remote/bbb.txt b/test/fixtures/repo-dotcom-remote/bbb.txt deleted file mode 100644 index f761ec192d..0000000000 --- a/test/fixtures/repo-dotcom-remote/bbb.txt +++ /dev/null @@ -1 +0,0 @@ -bbb diff --git a/test/fixtures/repo-dotcom-remote/ccc.txt b/test/fixtures/repo-dotcom-remote/ccc.txt deleted file mode 100644 index b2a7546679..0000000000 --- a/test/fixtures/repo-dotcom-remote/ccc.txt +++ /dev/null @@ -1 +0,0 @@ -ccc diff --git a/test/fixtures/repo-dotcom-remote/dot-git/COMMIT_EDITMSG b/test/fixtures/repo-dotcom-remote/dot-git/COMMIT_EDITMSG deleted file mode 100644 index 8026076649..0000000000 --- a/test/fixtures/repo-dotcom-remote/dot-git/COMMIT_EDITMSG +++ /dev/null @@ -1 +0,0 @@ -initial commit diff --git a/test/fixtures/repo-dotcom-remote/dot-git/HEAD b/test/fixtures/repo-dotcom-remote/dot-git/HEAD deleted file mode 100644 index cb089cd89a..0000000000 --- a/test/fixtures/repo-dotcom-remote/dot-git/HEAD +++ /dev/null @@ -1 +0,0 @@ -ref: refs/heads/master diff --git a/test/fixtures/repo-dotcom-remote/dot-git/config b/test/fixtures/repo-dotcom-remote/dot-git/config deleted file mode 100644 index 562e0de5b0..0000000000 --- a/test/fixtures/repo-dotcom-remote/dot-git/config +++ /dev/null @@ -1,10 +0,0 @@ -[core] - repositoryformatversion = 0 - filemode = true - bare = false - logallrefupdates = true - ignorecase = true - precomposeunicode = true -[remote "origin"] - url = git@github.com:owner/repo.git - fetch = +refs/heads/*:refs/remotes/origin/* diff --git a/test/fixtures/repo-dotcom-remote/dot-git/description b/test/fixtures/repo-dotcom-remote/dot-git/description deleted file mode 100644 index 498b267a8c..0000000000 --- a/test/fixtures/repo-dotcom-remote/dot-git/description +++ /dev/null @@ -1 +0,0 @@ -Unnamed repository; edit this file 'description' to name the repository. diff --git a/test/fixtures/repo-dotcom-remote/dot-git/index b/test/fixtures/repo-dotcom-remote/dot-git/index deleted file mode 100644 index 6d8781392adb10b5d60f512540101dbbd9f49378..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 281 zcmZ?q402{*U|<4b=4k7JiJBK!^kFn30|N`o(qoYf42??|7#P0-)rbHwOVJc7vEMrV z7C-MkV%ol(=Zxf0eG>-u#Kc6sl8O?b0-*k>OqN$YVKmg7XmoSFC%%!?ozHv9Sd+zj z+Uwgw&2#sEV_;88NG>+0X{ 1530622117 -0400 commit (initial): initial commit diff --git a/test/fixtures/repo-dotcom-remote/dot-git/logs/refs/heads/master b/test/fixtures/repo-dotcom-remote/dot-git/logs/refs/heads/master deleted file mode 100644 index a021157a5a..0000000000 --- a/test/fixtures/repo-dotcom-remote/dot-git/logs/refs/heads/master +++ /dev/null @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 2a81e58dd15cf000600574f01fce31a3468de3d2 Ash Wilson 1530622117 -0400 commit (initial): initial commit diff --git a/test/fixtures/repo-dotcom-remote/dot-git/objects/2a/81e58dd15cf000600574f01fce31a3468de3d2 b/test/fixtures/repo-dotcom-remote/dot-git/objects/2a/81e58dd15cf000600574f01fce31a3468de3d2 deleted file mode 100644 index 338a00439c1d9de46e3b98252a3643a466003706..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 789 zcmV+w1M2*E0iBb{&ZAZkg|p@#r^qU}+59fa!1E0wc-8mjp;&r*%;^%Omk9;@)35zb9JhmIixlZt#e>nr)nly!lATDPg19 z@*Fn(%Hz)Z+3-%x#wHxqH8?eEea_S0P!MI^-94o6uDqM&QIF}6c@*k6G;Xx_@`%!S zQ&Fj+*Bt}pbYq%B780@34|b&SgGtnsJsG%pidHEqlzo46mpt+st`X1dnk!IuH0SQG z)h&IA7?7q*8P4Ie;K$c9l|v<-<1OE6nwb01N(Nbe-p^W7oyTTlIWJygU!tvb4X%p` zZ;ti3p@_C69WRBw$Ci}~4Uv-e_2JK5UsvAqT0O0O#fwSAeOvP~Qo8ypjC9_q^THs? z6azbN>FoN@_H;8(yd~wQWrTO`=r@uE-^N>56=R`7QcIi|&EkeGVgH(-OD>GjNk0x4 zXsx506+u3PRoMu1qz7pBj`QI%lPx+K&b$=woK7PK@6n>Q2fshLFo6foqq;te5e9~0 zy&AF9kqx5#oV*jy%7r$S@JIC?#jmQlKaN`vsRax+r{C1;iC diff --git a/test/fixtures/repo-dotcom-remote/dot-git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34 b/test/fixtures/repo-dotcom-remote/dot-git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34 deleted file mode 100644 index dcc78722fe99ad70a05819b5545d5242f0216e2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19 acmbx-;s%2N diff --git a/test/fixtures/repo-dotcom-remote/dot-git/objects/b2/a7546679fdf79ca0eb7bfbee1e1bb342487380 b/test/fixtures/repo-dotcom-remote/dot-git/objects/b2/a7546679fdf79ca0eb7bfbee1e1bb342487380 deleted file mode 100644 index c396a515ee487a5dd4f5cb867e883c57650f6c76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19 acmb7Fl8__FfcPQQAkWo)GMhdVJMnnCH7mV-{R-pM@-w7^PG`9 zs&4{Sl9ZGLR`NaZjil~;-c!b!EZ);z-xg|~yZ;+hNpf;BSjnd4A!(I=zt36ly88D! PIqA(#9>om+GXX6}Fg`NS diff --git a/test/fixtures/repo-dotcom-remote/dot-git/objects/f7/61ec192d9f0dca3329044b96ebdb12839dbff6 b/test/fixtures/repo-dotcom-remote/dot-git/objects/f7/61ec192d9f0dca3329044b96ebdb12839dbff6 deleted file mode 100644 index 725953ba39b33c01be52b9ae433dbf9175029578..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19 acmb Date: Tue, 3 Jul 2018 15:05:47 -0400 Subject: [PATCH 0447/4847] Inject a GithubLoginModel to the package under test --- lib/controllers/root-controller.js | 12 +++++------- lib/github-package.js | 5 ++++- test/integration/helpers.js | 12 ++++++++++-- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 70ebe14aab..c050d0e436 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -20,7 +20,6 @@ import IssueishPaneItem from '../items/issueish-pane-item'; import GitTabItem from '../items/git-tab-item'; import StatusBarTileController from './status-bar-tile-controller'; import RepositoryConflictController from './repository-conflict-controller'; -import GithubLoginModel from '../models/github-login-model'; import GitCacheView from '../views/git-cache-view'; import Conflict from '../models/conflicts/conflict'; import Switchboard from '../switchboard'; @@ -37,6 +36,7 @@ export default class RootController extends React.Component { grammars: PropTypes.object.isRequired, config: PropTypes.object.isRequired, project: PropTypes.object.isRequired, + loginModel: PropTypes.object.isRequired, confirm: PropTypes.func.isRequired, getRepositoryForWorkdir: PropTypes.func.isRequired, createRepositoryForProjectPath: PropTypes.func, @@ -68,8 +68,6 @@ export default class RootController extends React.Component { 'discardWorkDirChangesForPaths', 'discardLines', 'undoLastDiscard', 'refreshResolutionProgress', ); - this.loginModel = GithubLoginModel.get(); - this.state = { cloneDialogActive: false, cloneDialogInProgress: false, @@ -277,7 +275,7 @@ export default class RootController extends React.Component { confirm={this.props.confirm} config={this.props.config} repository={this.props.repository} - loginModel={this.loginModel} + loginModel={this.props.loginModel} initializeRepo={this.initializeRepo} resolutionProgress={this.props.resolutionProgress} ensureGitTab={this.gitTabTracker.ensureVisible} @@ -296,7 +294,7 @@ export default class RootController extends React.Component { )} @@ -334,7 +332,7 @@ export default class RootController extends React.Component { repo={params.repo} issueishNumber={parseInt(params.issueishNumber, 10)} - loginModel={this.loginModel} + loginModel={this.props.loginModel} /> )} @@ -399,7 +397,7 @@ export default class RootController extends React.Component { } clearGithubToken() { - return this.loginModel.removeToken('https://api.github.com'); + return this.props.loginModel.removeToken('https://api.github.com'); } initializeRepo(initDialogPath) { diff --git a/lib/github-package.js b/lib/github-package.js index 2937a9992d..a006004f9b 100644 --- a/lib/github-package.js +++ b/lib/github-package.js @@ -12,6 +12,7 @@ import WorkdirContext from './models/workdir-context'; import WorkdirContextPool from './models/workdir-context-pool'; import Repository from './models/repository'; import StyleCalculator from './models/style-calculator'; +import GithubLoginModel from './models/github-login-model'; import RootController from './controllers/root-controller'; import StubItem from './items/stub-item'; import Switchboard from './switchboard'; @@ -31,7 +32,7 @@ export default class GithubPackage { workspace, project, commandRegistry, notificationManager, tooltips, styles, grammars, config, deserializers, confirm, getLoadSettings, configDirPath, - renderFn, + renderFn, loginModel, }) { autobind( this, @@ -76,6 +77,7 @@ export default class GithubPackage { this.switchboard = new Switchboard(); + this.loginModel = loginModel || new GithubLoginModel(); this.renderFn = renderFn || ((component, node, callback) => { return ReactDom.render(component, node, callback); }); @@ -280,6 +282,7 @@ export default class GithubPackage { config={this.config} project={this.project} confirm={this.confirm} + loginModel={this.loginModel} repository={this.getActiveRepository()} resolutionProgress={this.getActiveResolutionProgress()} statusBar={this.statusBar} diff --git a/test/integration/helpers.js b/test/integration/helpers.js index 304b22d816..8f071685b4 100644 --- a/test/integration/helpers.js +++ b/test/integration/helpers.js @@ -3,6 +3,8 @@ import {mount} from 'enzyme'; import {getTempDir} from '../../lib/helpers'; import {cloneRepository} from '../helpers'; import GithubPackage from '../../lib/github-package'; +import GithubLoginModel from '../../lib/models/github-login-model'; +import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; import metadata from '../../package.json'; /** @@ -47,8 +49,9 @@ export async function setup(currentTest, options = {}) { suiteRoot.id = 'github-IntegrationSuite'; document.body.appendChild(suiteRoot); } - suiteRoot.appendChild(atomEnv.workspace.getElement()); - atomEnv.workspace.getElement().focus(); + const workspaceElement = atomEnv.workspace.getElement(); + suiteRoot.appendChild(workspaceElement); + workspaceElement.focus(); await opts.initAtomEnv(atomEnv); @@ -60,6 +63,8 @@ export async function setup(currentTest, options = {}) { atomEnv.project.setPaths(projectDirs, {mustExist: true, exact: true}); + const loginModel = new GithubLoginModel(InMemoryStrategy); + let configDirPath = null; if (opts.isolateConfigDir) { configDirPath = await getTempDir(); @@ -81,6 +86,7 @@ export async function setup(currentTest, options = {}) { grammars: atomEnv.grammars, config: atomEnv.config, deserializers: atomEnv.deserializers, + loginModel, confirm: atomEnv.confirm.bind(atomEnv), getLoadSettings: atomEnv.getLoadSettings.bind(atomEnv), configDirPath, @@ -115,9 +121,11 @@ export async function setup(currentTest, options = {}) { return { atomEnv, githubPackage, + loginModel, wrapper, domRoot, suiteRoot, + workspaceElement, }; } From df8ba20ee4a946d062749db5038a1198e33950c1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 15:06:01 -0400 Subject: [PATCH 0448/4847] Factory to create a sequence of pull request results --- test/fixtures/factories/pull-request-result.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/fixtures/factories/pull-request-result.js b/test/fixtures/factories/pull-request-result.js index 1a265d875c..001f3698d6 100644 --- a/test/fixtures/factories/pull-request-result.js +++ b/test/fixtures/factories/pull-request-result.js @@ -107,6 +107,15 @@ export function createPullRequestResult(attrs = {}) { } } +export function createPullRequestsResult(...attrs) { + const idGen = IDGenerator.fromOpts({}); + const embed = idGen.embed(); + + return attrs.map(attr => { + return createPullRequestResult({...attr, ...embed}); + }); +} + export function createPullRequestDetailResult(attrs = {}) { const idGen = IDGenerator.fromOpts(attrs); From 5db7c82f0faad9baf1316ca4d3a3d0c1d8038cb8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 15:06:12 -0400 Subject: [PATCH 0449/4847] Accept "good-token" while under spec --- lib/models/github-login-model.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/models/github-login-model.js b/lib/models/github-login-model.js index b9f6fe75c3..99554e64bd 100644 --- a/lib/models/github-login-model.js +++ b/lib/models/github-login-model.js @@ -92,6 +92,10 @@ export default class GithubLoginModel { async getScopes(host, token) { if (atom.inSpecMode()) { + if (token === 'good-token') { + return this.constructor.REQUIRED_SCOPES; + } + throw new Error('Attempt to check token scopes in specs'); } From 5cc74337f517cd5d9e158d56566c78e6cc77410f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 15:06:32 -0400 Subject: [PATCH 0450/4847] Integration test for navigation to a pull request item --- test/integration/view-issueish.test.js | 145 +++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 test/integration/view-issueish.test.js diff --git a/test/integration/view-issueish.test.js b/test/integration/view-issueish.test.js new file mode 100644 index 0000000000..0ac2bb3a23 --- /dev/null +++ b/test/integration/view-issueish.test.js @@ -0,0 +1,145 @@ +import {setup, teardown} from './helpers'; +import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; +import GitShellOutStrategy from '../../lib/git-shell-out-strategy'; +import {createRepositoryResult} from '../fixtures/factories/repository-result'; +import {createPullRequestsResult, createPullRequestDetailResult} from '../fixtures/factories/pull-request-result'; + +describe('viewing an issue or pull request', function() { + let context, wrapper, atomEnv, workspaceElement; + + beforeEach(async function() { + context = await setup(this.currentTest, { + initialRoots: ['three-files'], + }); + wrapper = context.wrapper; + atomEnv = context.atomEnv; + workspaceElement = context.workspaceElement; + + await context.loginModel.setToken('https://api.github.com', 'good-token'); + + const root = atomEnv.project.getPaths()[0]; + const git = new GitShellOutStrategy(root); + await git.exec(['remote', 'add', 'dotcom', 'git@github.com:owner/repo.git']); + }); + + afterEach(async function() { + await teardown(context); + }); + + function expectRepositoryQuery() { + return expectRelayQuery({ + name: 'remoteContainerQuery', + variables: { + owner: 'owner', + name: 'repo', + }, + }, { + repository: createRepositoryResult(), + }); + } + + function expectIssueishSearchQuery() { + return expectRelayQuery({ + name: 'issueishSearchContainerQuery', + variables: { + query: 'repo:owner/repo type:pr state:open', + first: 20, + }, + }, { + search: { + issueCount: 10, + nodes: createPullRequestsResult( + {number: 0}, + {number: 1}, + {number: 2}, + ), + }, + }); + } + + function expectIssueishDetailQuery() { + const result = { + repository: { + id: 'repository0', + name: 'repo', + owner: { + __typename: 'User', + id: 'user0', + login: 'owner', + }, + issueish: createPullRequestDetailResult({ + number: 1, + title: 'Pull Request 1', + }), + }, + }; + + // console.log(result); + + return expectRelayQuery({ + name: 'issueishDetailContainerQuery', + variables: { + repoOwner: 'owner', + repoName: 'repo', + issueishNumber: 1, + timelineCount: 100, + timelineCursor: null, + }, + }, result); + } + + function expectMentionableUsersQuery() { + return expectRelayQuery({ + name: 'GetMentionableUsers', + variables: { + owner: 'owner', + name: 'repo', + first: 100, + after: null, + }, + }, { + repository: { + mentionableUsers: { + nodes: [{login: 'smashwilson', email: 'smashwilson@github.com', name: 'Me'}], + pageInfo: {hasNextPage: false, endCursor: 'zzz'}, + }, + }, + }); + } + + it('opens a pane item for a pull request by clicking on an entry in the GitHub tab', async function() { + const {resolve: resolve0, promise: promise0} = expectRepositoryQuery(); + resolve0(); + await promise0; + + const {resolve: resolve1, promise: promise1} = expectIssueishSearchQuery(); + resolve1(); + await promise1; + + const {resolve: resolve2, promise: promise2} = expectIssueishDetailQuery(); + resolve2(); + await promise2; + + const {resolve: resolve3, promise: promise3} = expectMentionableUsersQuery(); + resolve3(); + await promise3; + + // Open the GitHub tab and wait for results to be rendered + await atomEnv.commands.dispatch(workspaceElement, 'github:toggle-github-tab'); + await assert.async.isTrue(wrapper.update().find('.github-IssueishList-item').exists()); + + // Click on PR #1 + const prOne = wrapper.find('.github-Accordion-listItem').filterWhere(li => { + return li.find('.github-IssueishList-item--number').text() === '#1'; + }); + prOne.simulate('click'); + + // Wait for the pane item to open and fetch + await assert.async.include( + atomEnv.workspace.getActivePaneItem().getTitle(), + 'PR: owner/repo#1 — Pull Request 1', + ); + + assert.strictEqual(wrapper.update().find('.github-IssueishDetailView-title').text(), 'Pull Request 1'); + }); +}); From 00b2dee77dec21d2c43fd7b5f6dabcd8dba25b66 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 15:07:59 -0400 Subject: [PATCH 0451/4847] Fix that damn proptype error --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 499e6996ca..545587602a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -7,7 +7,7 @@ const entry = { workspace: atom.workspace, project: atom.project, commandRegistry: atom.commands, - notificationManager: atom.notificationManager, + notificationManager: atom.notifications, tooltips: atom.tooltips, styles: atom.styles, grammars: atom.grammars, From cebb31c9247893787e5ecf07f4d2bb66fa5633d7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 15:17:27 -0400 Subject: [PATCH 0452/4847] Arguments are more useful if you pass them --- lib/containers/issueish-detail-container.js | 6 +++++- lib/controllers/issue-timeline-controller.js | 2 +- lib/controllers/issueish-detail-controller.js | 2 +- lib/controllers/pr-timeline-controller.js | 9 ++++++--- lib/views/issueish-detail-view.js | 4 ++-- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index 6f974ba96b..3ffe6a2313 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -76,7 +76,11 @@ export default class IssueishDetailContainer extends React.Component { $timelineCursor: String ) { repository(owner: $repoOwner, name: $repoName) { - ...issueishDetailController_repository @arguments(issueishNumber: $issueishNumber) + ...issueishDetailController_repository @arguments( + timelineCount: $timelineCount, + timelineCursor: $timelineCursor, + issueishNumber: $issueishNumber, + ) } } `; diff --git a/lib/controllers/issue-timeline-controller.js b/lib/controllers/issue-timeline-controller.js index df370ca8db..82f319ef36 100644 --- a/lib/controllers/issue-timeline-controller.js +++ b/lib/controllers/issue-timeline-controller.js @@ -6,7 +6,7 @@ export default createPaginationContainer(IssueishTimelineView, { issue: graphql` fragment issueTimelineController_issue on Issue @argumentDefinitions( - timelineCount: {type: "Int"}, + timelineCount: {type: "Int!"}, timelineCursor: {type: "String"} ) { url diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index a393610b1c..c7c4cb9db5 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -58,7 +58,7 @@ export default createFragmentContainer(BareIssueishDetailController, { repository: graphql` fragment issueishDetailController_repository on Repository @argumentDefinitions( - timelineCount: {type: "Int"}, + timelineCount: {type: "Int!"}, timelineCursor: {type: "String"}, issueishNumber: {type: "Int!"} ) { diff --git a/lib/controllers/pr-timeline-controller.js b/lib/controllers/pr-timeline-controller.js index acdd7e5413..31c62674ba 100644 --- a/lib/controllers/pr-timeline-controller.js +++ b/lib/controllers/pr-timeline-controller.js @@ -6,7 +6,7 @@ export default createPaginationContainer(IssueishTimelineView, { pullRequest: graphql` fragment prTimelineController_pullRequest on PullRequest @argumentDefinitions( - timelineCount: {type: "Int"}, + timelineCount: {type: "Int!"}, timelineCursor: {type: "String"} ) { url @@ -47,10 +47,13 @@ export default createPaginationContainer(IssueishTimelineView, { }; }, query: graphql` - query prTimelineControllerQuery($timelineCount: Int! $timelineCursor: String $url: URI!) { + query prTimelineControllerQuery($timelineCount: Int!, $timelineCursor: String, $url: URI!) { resource(url: $url) { ... on PullRequest { - ...prTimelineController_pullRequest + ...prTimelineController_pullRequest @arguments( + timelineCount: $timelineCount, + timelineCursor: $timelineCursor + ) } } } diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index f08fe2be26..31534e9fca 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -199,7 +199,7 @@ export default createRefetchContainer(BareIssueishDetailView, { issueish: graphql` fragment issueishDetailView_issueish on IssueOrPullRequest @argumentDefinitions( - timelineCount: {type: "Int"}, + timelineCount: {type: "Int!"}, timelineCursor: {type: "String"} ) { __typename @@ -246,7 +246,7 @@ export default createRefetchContainer(BareIssueishDetailView, { $repoId: ID!, $issueishId: ID!, $timelineCount: Int!, $timelineCursor: String ) { repository:node(id: $repoId) { - ...issueishDetailView_repository + ...issueishDetailView_repository @arguments(timelineCount: $timelineCount, timelineCursor: $timelineCursor) } issueish:node(id: $issueishId) { From 7c3c44d385b19e1a8cf4ad337f79385b0d7e40f6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 3 Jul 2018 15:17:33 -0400 Subject: [PATCH 0453/4847] Relay regeneration --- .../issueishDetailContainerQuery.graphql.js | 208 +++++++------ .../issueTimelineController_issue.graphql.js | 4 +- ...eishDetailController_repository.graphql.js | 4 +- .../prTimelineControllerQuery.graphql.js | 59 +++- ...rTimelineController_pullRequest.graphql.js | 4 +- .../issueishDetailViewRefetchQuery.graphql.js | 277 +++++++++--------- .../issueishDetailView_issueish.graphql.js | 4 +- 7 files changed, 315 insertions(+), 245 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index ea3ff136ea..aef03dc47c 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash d84672cec1e64616fc80f4bc4e135943 + * @relayHash 8cc87326d72e0672d446d157a24435d5 */ /* eslint-disable */ @@ -30,14 +30,16 @@ query issueishDetailContainerQuery( $repoOwner: String! $repoName: String! $issueishNumber: Int! + $timelineCount: Int! + $timelineCursor: String ) { repository(owner: $repoOwner, name: $repoName) { - ...issueishDetailController_repository_146t2V + ...issueishDetailController_repository_n0A9R id } } -fragment issueishDetailController_repository_146t2V on Repository { +fragment issueishDetailController_repository_n0A9R on Repository { ...issueishDetailView_repository name owner { @@ -50,12 +52,12 @@ fragment issueishDetailController_repository_146t2V on Repository { ... on Issue { title number - ...issueishDetailView_issueish_1wZIw + ...issueishDetailView_issueish_3D8CP9 } ... on PullRequest { title number - ...issueishDetailView_issueish_1wZIw + ...issueishDetailView_issueish_3D8CP9 } ... on Node { id @@ -73,7 +75,7 @@ fragment issueishDetailView_repository on Repository { } } -fragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest { +fragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest { __typename ... on Node { id @@ -97,7 +99,7 @@ fragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest { id } } - ...issueTimelineController_issue_1wZIw + ...issueTimelineController_issue_3D8CP9 } ... on PullRequest { ...prStatusesView_pullRequest @@ -119,7 +121,7 @@ fragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest { id } } - ...prTimelineController_pullRequest_1wZIw + ...prTimelineController_pullRequest_3D8CP9 } ... on UniformResourceLocatable { url @@ -134,9 +136,9 @@ fragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest { } } -fragment issueTimelineController_issue_1wZIw on Issue { +fragment issueTimelineController_issue_3D8CP9 on Issue { url - timeline { + timeline(first: $timelineCount, after: $timelineCursor) { pageInfo { endCursor hasNextPage @@ -179,10 +181,10 @@ fragment prStatusesView_pullRequest on PullRequest { } } -fragment prTimelineController_pullRequest_1wZIw on PullRequest { +fragment prTimelineController_pullRequest_3D8CP9 on PullRequest { url ...headRefForcePushedEventView_issueish - timeline { + timeline(first: $timelineCount, after: $timelineCursor) { pageInfo { endCursor hasNextPage @@ -520,7 +522,21 @@ v9 = { "args": null, "storageKey": null }, -v10 = { +v10 = [ + { + "kind": "Variable", + "name": "after", + "variableName": "timelineCursor", + "type": "String" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "timelineCount", + "type": "Int" + } +], +v11 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -545,41 +561,41 @@ v10 = { } ] }, -v11 = { +v12 = { "kind": "ScalarField", "alias": null, "name": "cursor", "args": null, "storageKey": null }, -v12 = { +v13 = { "kind": "ScalarField", "alias": null, "name": "avatarUrl", "args": null, "storageKey": null }, -v13 = [ +v14 = [ v4, v5, - v12, + v13, v2 ], -v14 = { +v15 = { "kind": "ScalarField", "alias": null, "name": "number", "args": null, "storageKey": null }, -v15 = { +v16 = { "kind": "ScalarField", "alias": null, "name": "url", "args": null, "storageKey": null }, -v16 = { +v17 = { "kind": "InlineFragment", "type": "CrossReferencedEvent", "selections": [ @@ -605,7 +621,7 @@ v16 = { "args": null, "concreteType": null, "plural": false, - "selections": v13 + "selections": v14 }, { "kind": "LinkedField", @@ -643,9 +659,9 @@ v16 = { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v14, - v9, v15, + v9, + v16, { "kind": "ScalarField", "alias": "prState", @@ -659,9 +675,9 @@ v16 = { "kind": "InlineFragment", "type": "Issue", "selections": [ - v14, - v9, v15, + v9, + v16, { "kind": "ScalarField", "alias": "issueState", @@ -675,18 +691,18 @@ v16 = { } ] }, -v17 = { +v18 = { "kind": "ScalarField", "alias": null, "name": "oid", "args": null, "storageKey": null }, -v18 = [ - v17, +v19 = [ + v18, v2 ], -v19 = { +v20 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -694,22 +710,22 @@ v19 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v18 + "selections": v19 }, -v20 = { +v21 = { "kind": "ScalarField", "alias": null, "name": "createdAt", "args": null, "storageKey": null }, -v21 = [ +v22 = [ v4, - v12, + v13, v5, v2 ], -v22 = { +v23 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -717,9 +733,9 @@ v22 = { "args": null, "concreteType": null, "plural": false, - "selections": v21 + "selections": v22 }, -v23 = { +v24 = { "kind": "InlineFragment", "type": "IssueComment", "selections": [ @@ -731,13 +747,13 @@ v23 = { "args": null, "concreteType": null, "plural": false, - "selections": v21 + "selections": v22 }, v8, - v20 + v21 ] }, -v24 = { +v25 = { "kind": "LinkedField", "alias": null, "name": "user", @@ -750,7 +766,7 @@ v24 = { v2 ] }, -v25 = { +v26 = { "kind": "InlineFragment", "type": "Commit", "selections": [ @@ -764,8 +780,8 @@ v25 = { "plural": false, "selections": [ v3, - v24, - v12 + v25, + v13 ] }, { @@ -778,8 +794,8 @@ v25 = { "plural": false, "selections": [ v3, - v12, - v24 + v13, + v25 ] }, { @@ -789,7 +805,7 @@ v25 = { "args": null, "storageKey": null }, - v17, + v18, { "kind": "ScalarField", "alias": null, @@ -806,17 +822,17 @@ v25 = { } ] }, -v26 = { +v27 = { "kind": "ScalarField", "alias": null, "name": "state", "args": null, "storageKey": null }, -v27 = [ - v15 +v28 = [ + v16 ], -v28 = { +v29 = { "kind": "LinkedField", "alias": null, "name": "author", @@ -827,21 +843,21 @@ v28 = { "selections": [ v4, v5, - v12, + v13, v2, { "kind": "InlineFragment", "type": "Bot", - "selections": v27 + "selections": v28 }, { "kind": "InlineFragment", "type": "User", - "selections": v27 + "selections": v28 } ] }, -v29 = { +v30 = { "kind": "LinkedField", "alias": null, "name": "reactionGroups", @@ -882,7 +898,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_146t2V\n id\n }\n}\n\nfragment issueishDetailController_repository_146t2V on Repository {\n ...issueishDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishDetailView_issueish_1wZIw\n }\n ... on PullRequest {\n title\n number\n ...issueishDetailView_issueish_1wZIw\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_1wZIw on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_1wZIw\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_1wZIw\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_1wZIw on Issue {\n url\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_1wZIw on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_n0A9R\n id\n }\n}\n\nfragment issueishDetailController_repository_n0A9R on Repository {\n ...issueishDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishDetailView_issueish_3D8CP9\n }\n ... on PullRequest {\n title\n number\n ...issueishDetailView_issueish_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -909,6 +925,18 @@ return { "name": "issueishNumber", "variableName": "issueishNumber", "type": null + }, + { + "kind": "Variable", + "name": "timelineCount", + "variableName": "timelineCount", + "type": null + }, + { + "kind": "Variable", + "name": "timelineCursor", + "variableName": "timelineCursor", + "type": null } ] } @@ -962,11 +990,11 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": null, + "args": v10, "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v10, + v11, { "kind": "LinkedField", "alias": null, @@ -976,7 +1004,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v11, + v12, { "kind": "LinkedField", "alias": null, @@ -988,12 +1016,12 @@ return { "selections": [ v4, v2, - v16, + v17, { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v19, + v20, { "kind": "LinkedField", "alias": null, @@ -1037,11 +1065,11 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v13 + "selections": v14 }, - v19, - v8, v20, + v8, + v21, { "kind": "ScalarField", "alias": null, @@ -1068,7 +1096,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v22, + v23, { "kind": "LinkedField", "alias": null, @@ -1077,7 +1105,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v18 + "selections": v19 }, { "kind": "LinkedField", @@ -1087,17 +1115,17 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v18 + "selections": v19 }, - v20 + v21 ] }, { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v22, - v19, + v23, + v20, { "kind": "ScalarField", "alias": null, @@ -1105,11 +1133,11 @@ return { "args": null, "storageKey": null }, - v20 + v21 ] }, - v23, - v25 + v24, + v26 ] } ] @@ -1120,7 +1148,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": null, + "args": v10, "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null @@ -1177,7 +1205,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v26, + v27, { "kind": "LinkedField", "alias": null, @@ -1188,7 +1216,7 @@ return { "plural": true, "selections": [ v2, - v26, + v27, { "kind": "ScalarField", "alias": null, @@ -1225,10 +1253,10 @@ return { } ] }, - v26, - v14, - v28, + v27, v15, + v29, + v16, { "kind": "ScalarField", "alias": null, @@ -1259,7 +1287,7 @@ return { v2 ] }, - v29 + v30 ] }, { @@ -1268,20 +1296,20 @@ return { "selections": [ v8, v9, - v26, - v14, - v28, + v27, v15, + v29, + v16, { "kind": "LinkedField", "alias": null, "name": "timeline", "storageKey": null, - "args": null, + "args": v10, "concreteType": "IssueTimelineConnection", "plural": false, "selections": [ - v10, + v11, { "kind": "LinkedField", "alias": null, @@ -1291,7 +1319,7 @@ return { "concreteType": "IssueTimelineItemEdge", "plural": true, "selections": [ - v11, + v12, { "kind": "LinkedField", "alias": null, @@ -1303,9 +1331,9 @@ return { "selections": [ v4, v2, - v16, - v23, - v25 + v17, + v24, + v26 ] } ] @@ -1316,12 +1344,12 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": null, + "args": v10, "handle": "connection", "key": "IssueTimelineController_timeline", "filters": null }, - v29 + v30 ] } ] @@ -1333,5 +1361,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'd62715328b9954af775f83a45e8b6feb'; +(node/*: any*/).hash = '5559fe0b5c062ee9f888aefc5f0dfd15'; module.exports = node; diff --git a/lib/controllers/__generated__/issueTimelineController_issue.graphql.js b/lib/controllers/__generated__/issueTimelineController_issue.graphql.js index ce083d4b85..d5f348a00f 100644 --- a/lib/controllers/__generated__/issueTimelineController_issue.graphql.js +++ b/lib/controllers/__generated__/issueTimelineController_issue.graphql.js @@ -53,7 +53,7 @@ const node/*: ConcreteFragment*/ = { { "kind": "LocalArgument", "name": "timelineCount", - "type": "Int", + "type": "Int!", "defaultValue": null }, { @@ -161,5 +161,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = '91a0aa63cb74691005a4ed6dc3f7aa16'; +(node/*: any*/).hash = 'c494d20d52edd33af0a0265df766c13e'; module.exports = node; diff --git a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js index 237c15b3f6..b34fdf55c1 100644 --- a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js +++ b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js @@ -77,7 +77,7 @@ return { { "kind": "LocalArgument", "name": "timelineCount", - "type": "Int", + "type": "Int!", "defaultValue": null }, { @@ -163,5 +163,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'a4817f0fee232866758b7c80c77e71a9'; +(node/*: any*/).hash = 'd039efc2fd081d0c138415f4bc1ff190'; module.exports = node; diff --git a/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js b/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js index 705d4efe52..e80fc01147 100644 --- a/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js +++ b/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 3fb91f9b6850bc8de8a7c65508590a21 + * @relayHash e400921f4377d1ed040cee69d4ba9c6c */ /* eslint-disable */ @@ -25,12 +25,14 @@ export type prTimelineControllerQueryResponse = {| /* query prTimelineControllerQuery( + $timelineCount: Int! + $timelineCursor: String $url: URI! ) { resource(url: $url) { __typename ... on PullRequest { - ...prTimelineController_pullRequest + ...prTimelineController_pullRequest_3D8CP9 } ... on Node { id @@ -38,10 +40,10 @@ query prTimelineControllerQuery( } } -fragment prTimelineController_pullRequest on PullRequest { +fragment prTimelineController_pullRequest_3D8CP9 on PullRequest { url ...headRefForcePushedEventView_issueish - timeline { + timeline(first: $timelineCount, after: $timelineCursor) { pageInfo { endCursor hasNextPage @@ -443,7 +445,7 @@ return { "operationKind": "query", "name": "prTimelineControllerQuery", "id": null, - "text": "query prTimelineControllerQuery(\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineController_pullRequest\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineController_pullRequest on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", + "text": "query prTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -468,7 +470,20 @@ return { { "kind": "FragmentSpread", "name": "prTimelineController_pullRequest", - "args": null + "args": [ + { + "kind": "Variable", + "name": "timelineCount", + "variableName": "timelineCount", + "type": null + }, + { + "kind": "Variable", + "name": "timelineCursor", + "variableName": "timelineCursor", + "type": null + } + ] } ] } @@ -532,7 +547,20 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": null, + "args": [ + { + "kind": "Variable", + "name": "after", + "variableName": "timelineCursor", + "type": "String" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "timelineCount", + "type": "Int" + } + ], "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ @@ -887,7 +915,20 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": null, + "args": [ + { + "kind": "Variable", + "name": "after", + "variableName": "timelineCursor", + "type": "String" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "timelineCount", + "type": "Int" + } + ], "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null @@ -901,5 +942,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '70b5c2eb56b15708ffbd13c2d97b80a6'; +(node/*: any*/).hash = '9666ee294586973cd7b27193e460c2e1'; module.exports = node; diff --git a/lib/controllers/__generated__/prTimelineController_pullRequest.graphql.js b/lib/controllers/__generated__/prTimelineController_pullRequest.graphql.js index 097342a016..b30a37083b 100644 --- a/lib/controllers/__generated__/prTimelineController_pullRequest.graphql.js +++ b/lib/controllers/__generated__/prTimelineController_pullRequest.graphql.js @@ -58,7 +58,7 @@ const node/*: ConcreteFragment*/ = { { "kind": "LocalArgument", "name": "timelineCount", - "type": "Int", + "type": "Int!", "defaultValue": null }, { @@ -186,5 +186,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = 'e2137d027447cba05e42f3d8bae6643d'; +(node/*: any*/).hash = '237e6c0f8794b6f7065f0bbd7a417f99'; module.exports = node; diff --git a/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js index ae5d7909bf..5204b29995 100644 --- a/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 84069f78e531f794e9f37c33bd9522ca + * @relayHash 1713fc0aab49681909c757e7fb0f9d04 */ /* eslint-disable */ @@ -37,7 +37,7 @@ query issueishDetailViewRefetchQuery( ) { repository: node(id: $repoId) { __typename - ...issueishDetailView_repository + ...issueishDetailView_repository_3D8CP9 id } issueish: node(id: $issueishId) { @@ -47,7 +47,7 @@ query issueishDetailViewRefetchQuery( } } -fragment issueishDetailView_repository on Repository { +fragment issueishDetailView_repository_3D8CP9 on Repository { id name owner { @@ -436,6 +436,20 @@ v1 = [ } ], v2 = [ + { + "kind": "Variable", + "name": "timelineCount", + "variableName": "timelineCount", + "type": null + }, + { + "kind": "Variable", + "name": "timelineCursor", + "variableName": "timelineCursor", + "type": null + } +], +v3 = [ { "kind": "Variable", "name": "id", @@ -443,40 +457,40 @@ v2 = [ "type": "ID!" } ], -v3 = { +v4 = { "kind": "ScalarField", "alias": null, "name": "__typename", "args": null, "storageKey": null }, -v4 = { +v5 = { "kind": "ScalarField", "alias": null, "name": "id", "args": null, "storageKey": null }, -v5 = { +v6 = { "kind": "ScalarField", "alias": null, "name": "name", "args": null, "storageKey": null }, -v6 = { +v7 = { "kind": "ScalarField", "alias": null, "name": "login", "args": null, "storageKey": null }, -v7 = [ - v3, - v6, - v4 +v8 = [ + v4, + v7, + v5 ], -v8 = { +v9 = { "kind": "LinkedField", "alias": null, "name": "owner", @@ -484,26 +498,26 @@ v8 = { "args": null, "concreteType": null, "plural": false, - "selections": v7 + "selections": v8 }, -v9 = { +v10 = { "kind": "ScalarField", "alias": null, "name": "url", "args": null, "storageKey": null }, -v10 = { +v11 = { "kind": "ScalarField", "alias": null, "name": "avatarUrl", "args": null, "storageKey": null }, -v11 = [ - v9 +v12 = [ + v10 ], -v12 = { +v13 = { "kind": "LinkedField", "alias": null, "name": "author", @@ -512,51 +526,51 @@ v12 = { "concreteType": null, "plural": false, "selections": [ - v3, - v6, - v10, v4, + v7, + v11, + v5, { "kind": "InlineFragment", "type": "Bot", - "selections": v11 + "selections": v12 }, { "kind": "InlineFragment", "type": "User", - "selections": v11 + "selections": v12 } ] }, -v13 = { +v14 = { "kind": "ScalarField", "alias": null, "name": "state", "args": null, "storageKey": null }, -v14 = { +v15 = { "kind": "ScalarField", "alias": null, "name": "number", "args": null, "storageKey": null }, -v15 = { +v16 = { "kind": "ScalarField", "alias": null, "name": "title", "args": null, "storageKey": null }, -v16 = { +v17 = { "kind": "ScalarField", "alias": null, "name": "bodyHTML", "args": null, "storageKey": null }, -v17 = [ +v18 = [ { "kind": "Variable", "name": "after", @@ -570,7 +584,7 @@ v17 = [ "type": "Int" } ], -v18 = { +v19 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -595,20 +609,20 @@ v18 = { } ] }, -v19 = { +v20 = { "kind": "ScalarField", "alias": null, "name": "cursor", "args": null, "storageKey": null }, -v20 = [ - v3, - v6, - v10, - v4 +v21 = [ + v4, + v7, + v11, + v5 ], -v21 = { +v22 = { "kind": "InlineFragment", "type": "CrossReferencedEvent", "selections": [ @@ -634,7 +648,7 @@ v21 = { "args": null, "concreteType": null, "plural": false, - "selections": v20 + "selections": v21 }, { "kind": "LinkedField", @@ -645,7 +659,7 @@ v21 = { "concreteType": null, "plural": false, "selections": [ - v3, + v4, { "kind": "LinkedField", "alias": null, @@ -655,9 +669,9 @@ v21 = { "concreteType": "Repository", "plural": false, "selections": [ + v6, + v9, v5, - v8, - v4, { "kind": "ScalarField", "alias": null, @@ -667,14 +681,14 @@ v21 = { } ] }, - v4, + v5, { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v14, v15, - v9, + v16, + v10, { "kind": "ScalarField", "alias": "prState", @@ -688,9 +702,9 @@ v21 = { "kind": "InlineFragment", "type": "Issue", "selections": [ - v14, v15, - v9, + v16, + v10, { "kind": "ScalarField", "alias": "issueState", @@ -704,18 +718,18 @@ v21 = { } ] }, -v22 = { +v23 = { "kind": "ScalarField", "alias": null, "name": "oid", "args": null, "storageKey": null }, -v23 = [ - v22, - v4 +v24 = [ + v23, + v5 ], -v24 = { +v25 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -723,22 +737,22 @@ v24 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v23 + "selections": v24 }, -v25 = { +v26 = { "kind": "ScalarField", "alias": null, "name": "createdAt", "args": null, "storageKey": null }, -v26 = [ - v3, - v10, - v6, - v4 +v27 = [ + v4, + v11, + v7, + v5 ], -v27 = { +v28 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -746,9 +760,9 @@ v27 = { "args": null, "concreteType": null, "plural": false, - "selections": v26 + "selections": v27 }, -v28 = { +v29 = { "kind": "InlineFragment", "type": "IssueComment", "selections": [ @@ -760,13 +774,13 @@ v28 = { "args": null, "concreteType": null, "plural": false, - "selections": v26 + "selections": v27 }, - v16, - v25 + v17, + v26 ] }, -v29 = { +v30 = { "kind": "LinkedField", "alias": null, "name": "user", @@ -775,11 +789,11 @@ v29 = { "concreteType": "User", "plural": false, "selections": [ - v6, - v4 + v7, + v5 ] }, -v30 = { +v31 = { "kind": "InlineFragment", "type": "Commit", "selections": [ @@ -792,9 +806,9 @@ v30 = { "concreteType": "GitActor", "plural": false, "selections": [ - v5, - v29, - v10 + v6, + v30, + v11 ] }, { @@ -806,9 +820,9 @@ v30 = { "concreteType": "GitActor", "plural": false, "selections": [ - v5, - v10, - v29 + v6, + v11, + v30 ] }, { @@ -818,7 +832,7 @@ v30 = { "args": null, "storageKey": null }, - v22, + v23, { "kind": "ScalarField", "alias": null, @@ -840,7 +854,7 @@ return { "operationKind": "query", "name": "issueishDetailViewRefetchQuery", "id": null, - "text": "query issueishDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishDetailView_repository\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishDetailView_issueish_3D8CP9\n id\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishDetailView_repository_3D8CP9\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishDetailView_issueish_3D8CP9\n id\n }\n}\n\nfragment issueishDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -861,7 +875,7 @@ return { { "kind": "FragmentSpread", "name": "issueishDetailView_repository", - "args": null + "args": v2 } ] }, @@ -870,27 +884,14 @@ return { "alias": "issueish", "name": "node", "storageKey": null, - "args": v2, + "args": v3, "concreteType": null, "plural": false, "selections": [ { "kind": "FragmentSpread", "name": "issueishDetailView_issueish", - "args": [ - { - "kind": "Variable", - "name": "timelineCount", - "variableName": "timelineCount", - "type": null - }, - { - "kind": "Variable", - "name": "timelineCursor", - "variableName": "timelineCursor", - "type": null - } - ] + "args": v2 } ] } @@ -910,14 +911,14 @@ return { "concreteType": null, "plural": false, "selections": [ - v3, v4, + v5, { "kind": "InlineFragment", "type": "Repository", "selections": [ - v5, - v8 + v6, + v9 ] } ] @@ -927,13 +928,13 @@ return { "alias": "issueish", "name": "node", "storageKey": null, - "args": v2, + "args": v3, "concreteType": null, "plural": false, "selections": [ - v3, v4, - v9, + v5, + v10, { "kind": "LinkedField", "alias": null, @@ -974,11 +975,11 @@ return { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v12, v13, v14, v15, v16, + v17, { "kind": "LinkedField", "alias": null, @@ -1031,7 +1032,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v13, + v14, { "kind": "LinkedField", "alias": null, @@ -1041,8 +1042,8 @@ return { "concreteType": "StatusContext", "plural": true, "selections": [ - v4, - v13, + v5, + v14, { "kind": "ScalarField", "alias": null, @@ -1066,13 +1067,13 @@ return { } ] }, - v4 + v5 ] }, - v4 + v5 ] }, - v4 + v5 ] } ] @@ -1094,7 +1095,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v7 + "selections": v8 }, { "kind": "LinkedField", @@ -1105,8 +1106,8 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v8, - v4 + v9, + v5 ] }, { @@ -1114,11 +1115,11 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": v17, + "args": v18, "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v18, + v19, { "kind": "LinkedField", "alias": null, @@ -1128,7 +1129,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v19, + v20, { "kind": "LinkedField", "alias": null, @@ -1138,14 +1139,14 @@ return { "concreteType": null, "plural": false, "selections": [ - v3, v4, - v21, + v5, + v22, { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v24, + v25, { "kind": "LinkedField", "alias": null, @@ -1180,7 +1181,7 @@ return { "concreteType": "CommitComment", "plural": false, "selections": [ - v4, + v5, { "kind": "LinkedField", "alias": null, @@ -1189,11 +1190,11 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v20 + "selections": v21 }, - v24, - v16, v25, + v17, + v26, { "kind": "ScalarField", "alias": null, @@ -1220,7 +1221,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v27, + v28, { "kind": "LinkedField", "alias": null, @@ -1229,7 +1230,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v23 + "selections": v24 }, { "kind": "LinkedField", @@ -1239,17 +1240,17 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v23 + "selections": v24 }, - v25 + v26 ] }, { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v27, - v24, + v28, + v25, { "kind": "ScalarField", "alias": null, @@ -1257,11 +1258,11 @@ return { "args": null, "storageKey": null }, - v25 + v26 ] }, - v28, - v30 + v29, + v31 ] } ] @@ -1272,7 +1273,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v17, + "args": v18, "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null @@ -1283,21 +1284,21 @@ return { "kind": "InlineFragment", "type": "Issue", "selections": [ - v13, v14, v15, v16, - v12, + v17, + v13, { "kind": "LinkedField", "alias": null, "name": "timeline", "storageKey": null, - "args": v17, + "args": v18, "concreteType": "IssueTimelineConnection", "plural": false, "selections": [ - v18, + v19, { "kind": "LinkedField", "alias": null, @@ -1307,7 +1308,7 @@ return { "concreteType": "IssueTimelineItemEdge", "plural": true, "selections": [ - v19, + v20, { "kind": "LinkedField", "alias": null, @@ -1317,11 +1318,11 @@ return { "concreteType": null, "plural": false, "selections": [ - v3, v4, - v21, - v28, - v30 + v5, + v22, + v29, + v31 ] } ] @@ -1332,7 +1333,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v17, + "args": v18, "handle": "connection", "key": "IssueTimelineController_timeline", "filters": null @@ -1346,5 +1347,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '7607224ca8842b4949c0e98e1a37c3bf'; +(node/*: any*/).hash = '6c291092a43f298d622deae79a6a31cb'; module.exports = node; diff --git a/lib/views/__generated__/issueishDetailView_issueish.graphql.js b/lib/views/__generated__/issueishDetailView_issueish.graphql.js index 981cd78045..6872a99a9e 100644 --- a/lib/views/__generated__/issueishDetailView_issueish.graphql.js +++ b/lib/views/__generated__/issueishDetailView_issueish.graphql.js @@ -138,7 +138,7 @@ return { { "kind": "LocalArgument", "name": "timelineCount", - "type": "Int", + "type": "Int!", "defaultValue": null }, { @@ -241,5 +241,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'cc2a04ddfc3249b138025f067ba42363'; +(node/*: any*/).hash = '5b78b0edbca6e2259feed1ebbed3bfcf'; module.exports = node; From fcec3c776ef78ae4a3a336c893b33b871ebc087c Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 3 Jul 2018 13:39:09 -0700 Subject: [PATCH 0454/4847] add instructions on how to run tests on the command line --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 109edab83e..bf0a801ccd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,8 @@ To run tests, open the command palette and select "Run Package Specs". This will To re-run tests, you can refresh that window by pressing `Cmd + R` in DevTools. +You can also run them on the command line with `npm run test`. + ### Async Tests Sometimes it's necessary to test async operations. For example, imagine the following test: From a0a9aaf7a0ee1f8a6a93a529586b8a34cc01cf8a Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 3 Jul 2018 14:33:10 -0700 Subject: [PATCH 0455/4847] increment counters on login/logout --- lib/containers/remote-container.js | 3 +++ test/containers/remote-container.test.js | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/lib/containers/remote-container.js b/lib/containers/remote-container.js index 74dc9d4619..a811a20e1f 100644 --- a/lib/containers/remote-container.js +++ b/lib/containers/remote-container.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {QueryRenderer, graphql} from 'react-relay'; +import {incrementCounter} from '../reporter-proxy'; import {autobind} from '../helpers'; import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; @@ -132,10 +133,12 @@ export default class RemoteContainer extends React.Component { } handleLogin(token) { + incrementCounter('github-login'); this.props.loginModel.setToken(this.props.host, token); } handleLogout() { + incrementCounter('github-logout'); this.props.loginModel.removeToken(this.props.host); } } diff --git a/test/containers/remote-container.test.js b/test/containers/remote-container.test.js index 4996fc47fc..bbe780acb3 100644 --- a/test/containers/remote-container.test.js +++ b/test/containers/remote-container.test.js @@ -1,6 +1,7 @@ import React from 'react'; import {mount} from 'enzyme'; +import * as reporterProxy from '../../lib/reporter-proxy'; import {createRepositoryResult} from '../fixtures/factories/repository-result'; import Remote from '../../lib/models/remote'; import Branch, {nullBranch} from '../../lib/models/branch'; @@ -131,6 +132,28 @@ describe('RemoteContainer', function() { assert.strictEqual(qev.prop('error'), e); }); + it('increments a counter on login', async function() { + const token = '1234'; + sinon.stub(model, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); + const incrementCounterStub = sinon.stub(reporterProxy, 'incrementCounter'); + + const wrapper = mount(buildApp()); + wrapper.instance().handleLogin(token); + assert.isTrue(incrementCounterStub.calledOnceWith('github-login')); + }); + + it('increments a counter on logout', async function() { + const token = '1234'; + sinon.stub(model, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES); + + const wrapper = mount(buildApp()); + wrapper.instance().handleLogin(token); + + const incrementCounterStub = sinon.stub(reporterProxy, 'incrementCounter'); + wrapper.instance().handleLogout(); + assert.isTrue(incrementCounterStub.calledOnceWith('github-logout')); + }); + it('renders the controller once results have arrived', async function() { const {resolve} = expectRepositoryQuery(); expectEmptyIssueishQuery(); From eef8a7aa122fc063e25a0d2f58f1cf9b287975dc Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 3 Jul 2018 17:41:01 -0700 Subject: [PATCH 0456/4847] add some tests for `reporterProxy` --- lib/reporter-proxy.js | 5 +++++ test/reporter-proxy.test.js | 44 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 test/reporter-proxy.test.js diff --git a/lib/reporter-proxy.js b/lib/reporter-proxy.js index e08c8c7266..a6e2e2fd70 100644 --- a/lib/reporter-proxy.js +++ b/lib/reporter-proxy.js @@ -1,3 +1,5 @@ +const pjson = require('../package.json'); + // this class allows us to call reporter methods // before the reporter is actually loaded, since we don't want to // assume that the metrics package will load before the GitHub package. @@ -10,6 +12,7 @@ class ReporterProxy { this.events = []; this.timings = []; this.counters = []; + this.gitHubPackageVersion = pjson.version; } // function that is called after the reporter is actually loaded, to @@ -43,6 +46,7 @@ export const incrementCounter = function(counterName) { } export const addTiming = function(eventType, durationInMilliseconds, metadata = {}) { + metadata.gitHubPackageVersion = reporterProxy.gitHubPackageVersion; if (reporterProxy.reporter) { reporterProxy.reporter.addTiming(eventType, durationInMilliseconds, metadata); } else { @@ -51,6 +55,7 @@ export const addTiming = function(eventType, durationInMilliseconds, metadata = } export const addEvent = function(eventType, event) { + event.gitHubPackageVersion = reporterProxy.gitHubPackageVersion; if (reporterProxy.reporter) { reporterProxy.reporter.addCustomEvent(eventType, event); } else { diff --git a/test/reporter-proxy.test.js b/test/reporter-proxy.test.js new file mode 100644 index 0000000000..eb8ca9b53f --- /dev/null +++ b/test/reporter-proxy.test.js @@ -0,0 +1,44 @@ +import {addEvent, addTiming, incrementCounter, reporterProxy} from '../lib/reporter-proxy'; +const pjson = require('../package.json'); + +const version = pjson.version; + +describe('reporterProxy', function() { + describe('before reporter has been set', function() { + it('adds event to queue when addEvent is called', function() { + const event = {coAuthorCount: 2}; + const eventType = 'commits'; + const expectedEvent = { eventType, event }; + addEvent(eventType, event); + + const events = reporterProxy.events; + assert.deepEqual(events.length, 1); + const actualEvent = events[0] + assert.deepEqual(actualEvent.eventType, eventType); + assert.deepEqual(actualEvent.event, { coAuthorCount: 2, gitHubPackageVersion: version}); + }); + + it('adds timing to queue when addTiming is called', function() { + const eventType = 'load'; + const durationInMilliseconds = 42; + addTiming(eventType, durationInMilliseconds); + + const timings = reporterProxy.timings; + assert.deepEqual(timings.length, 1); + const timing = timings[0]; + assert.deepEqual(timing.eventType, eventType); + assert.deepEqual(timing.durationInMilliseconds, durationInMilliseconds); + console.log(timing.metadata); + assert.deepEqual(timing.metadata, { gitHubPackageVersion: version }); + }) + + it('adds counter to queue when incrementCounter is called', function() { + const counterName = "commits"; + incrementCounter(counterName); + + const counters = reporterProxy.counters; + assert.deepEqual(counters.length, 1); + assert.deepEqual(counters[0], counterName); + }); + }); +}); From 3d8d723804eb0587e93d9beee20a454cb0b0c02a Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 3 Jul 2018 18:30:33 -0700 Subject: [PATCH 0457/4847] improve reporterProxy tests --- lib/reporter-proxy.js | 4 +- test/reporter-proxy.test.js | 102 ++++++++++++++++++++++++++++++++---- 2 files changed, 95 insertions(+), 11 deletions(-) diff --git a/lib/reporter-proxy.js b/lib/reporter-proxy.js index a6e2e2fd70..b8e1c1fd45 100644 --- a/lib/reporter-proxy.js +++ b/lib/reporter-proxy.js @@ -21,11 +21,11 @@ class ReporterProxy { this.reporter = reporter; this.events.forEach((customEvent) => { - this.reporter.addCustomEvent(...customEvent); + this.reporter.addCustomEvent(customEvent.eventType, customEvent.event); }); this.timings.forEach((timing) => { - this.reporter.addTiming(...timing); + this.reporter.addTiming(timing.eventType, timing.durationInMilliseconds, timing.metadata); }); this.counters.forEach((counterName) => { diff --git a/test/reporter-proxy.test.js b/test/reporter-proxy.test.js index eb8ca9b53f..9803149e7a 100644 --- a/test/reporter-proxy.test.js +++ b/test/reporter-proxy.test.js @@ -3,12 +3,33 @@ const pjson = require('../package.json'); const version = pjson.version; +class FakeReporter { + addCustomEvent() {} + + addTiming() {} + + incrementCounter() {} +} + +const fakeReporter = new FakeReporter(); + describe('reporterProxy', function() { + const event = {coAuthorCount: 2}; + const eventType = 'commits'; + + const timingEventType = 'load'; + const durationInMilliseconds = 42; + + const counterName = 'push'; + afterEach(function() { + // let's not leak state between tests, dawg. + reporterProxy.events = []; + reporterProxy.timings = []; + reporterProxy.counters = []; + }) + describe('before reporter has been set', function() { it('adds event to queue when addEvent is called', function() { - const event = {coAuthorCount: 2}; - const eventType = 'commits'; - const expectedEvent = { eventType, event }; addEvent(eventType, event); const events = reporterProxy.events; @@ -19,21 +40,18 @@ describe('reporterProxy', function() { }); it('adds timing to queue when addTiming is called', function() { - const eventType = 'load'; - const durationInMilliseconds = 42; - addTiming(eventType, durationInMilliseconds); + addTiming(timingEventType, durationInMilliseconds); const timings = reporterProxy.timings; assert.deepEqual(timings.length, 1); const timing = timings[0]; - assert.deepEqual(timing.eventType, eventType); + + assert.deepEqual(timing.eventType, timingEventType); assert.deepEqual(timing.durationInMilliseconds, durationInMilliseconds); - console.log(timing.metadata); assert.deepEqual(timing.metadata, { gitHubPackageVersion: version }); }) it('adds counter to queue when incrementCounter is called', function() { - const counterName = "commits"; incrementCounter(counterName); const counters = reporterProxy.counters; @@ -41,4 +59,70 @@ describe('reporterProxy', function() { assert.deepEqual(counters[0], counterName); }); }); + describe('after reporter has been set', function() { + let addCustomEventStub, addTimingStub, incrementCounterStub; + beforeEach(function() { + addCustomEventStub = sinon.stub(fakeReporter, 'addCustomEvent'); + addTimingStub = sinon.stub(fakeReporter, 'addTiming'); + incrementCounterStub = sinon.stub(fakeReporter, 'incrementCounter'); + }) + it('empties all queues', function() { + addEvent(eventType, event); + addTiming(timingEventType, durationInMilliseconds); + incrementCounter(counterName); + + assert.isFalse(addCustomEventStub.called); + assert.isFalse(addTimingStub.called); + assert.isFalse(incrementCounterStub.called); + + assert.deepEqual(reporterProxy.events.length, 1); + assert.deepEqual(reporterProxy.timings.length, 1); + assert.deepEqual(reporterProxy.counters.length, 1); + + reporterProxy.setReporter(fakeReporter); + + const addCustomEventArgs = addCustomEventStub.lastCall.args; + assert.deepEqual(addCustomEventArgs[0], eventType); + assert.deepEqual(addCustomEventArgs[1], {coAuthorCount: 2, gitHubPackageVersion: version}); + + const addTimingArgs = addTimingStub.lastCall.args; + assert.deepEqual(addTimingArgs[0], timingEventType); + assert.deepEqual(addTimingArgs[1], durationInMilliseconds); + assert.deepEqual(addTimingArgs[2], { gitHubPackageVersion: version }); + + assert.deepEqual(incrementCounterStub.lastCall.args, [counterName]); + }); + it('calls addCustomEvent directly, bypassing queue', function() { + assert.isFalse(addCustomEventStub.called); + reporterProxy.setReporter(fakeReporter); + + addEvent(eventType, event); + assert.deepEqual(reporterProxy.events.length, 0); + + const addCustomEventArgs = addCustomEventStub.lastCall.args; + assert.deepEqual(addCustomEventArgs[0], eventType); + assert.deepEqual(addCustomEventArgs[1], {coAuthorCount: 2, gitHubPackageVersion: version}); + }); + it('calls addTiming directly, bypassing queue', function() { + assert.isFalse(addTimingStub.called); + reporterProxy.setReporter(fakeReporter); + + addTiming(timingEventType, durationInMilliseconds); + assert.deepEqual(reporterProxy.timings.length, 0); + + const addTimingArgs = addTimingStub.lastCall.args; + assert.deepEqual(addTimingArgs[0], timingEventType); + assert.deepEqual(addTimingArgs[1], durationInMilliseconds); + assert.deepEqual(addTimingArgs[2], { gitHubPackageVersion: version }); + }); + it('calls incrementCounter directly, bypassing queue', function() { + assert.isFalse(incrementCounterStub.called); + reporterProxy.setReporter(fakeReporter); + + incrementCounter(counterName); + assert.deepEqual(reporterProxy.counters.length, 0); + + assert.deepEqual(incrementCounterStub.lastCall.args, [counterName]); + }); + }); }); From 0beb26c0746b29b7b8489879dc91f696a633f51b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 5 Jul 2018 08:54:03 -0400 Subject: [PATCH 0458/4847] Inherit the WorkdirContextPool proptype from my other branch --- lib/prop-types.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/prop-types.js b/lib/prop-types.js index 46c279bdfb..73184029e4 100644 --- a/lib/prop-types.js +++ b/lib/prop-types.js @@ -10,6 +10,10 @@ export const DOMNodePropType = (props, propName, componentName) => { } }; +export const WorkdirContextPoolPropType = PropTypes.shape({ + getContext: PropTypes.func.isRequired, +}); + export const GithubLoginModelPropType = PropTypes.shape({ getToken: PropTypes.func.isRequired, setToken: PropTypes.func.isRequired, From 8a211d84d0bf6082dc7103b9cd693c04b4fb97ca Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 5 Jul 2018 08:58:08 -0400 Subject: [PATCH 0459/4847] Associate a working directory with each IssueishPaneItem --- lib/items/issueish-pane-item.js | 13 +++++++++---- test/fixtures/props/issueish-pane-props.js | 3 +++ test/items/issueish-pane-item.test.js | 10 +++++----- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/items/issueish-pane-item.js b/lib/items/issueish-pane-item.js index e25b69743e..6189f257ca 100644 --- a/lib/items/issueish-pane-item.js +++ b/lib/items/issueish-pane-item.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {Emitter} from 'event-kit'; import {autobind} from '../helpers'; -import {GithubLoginModelPropType} from '../prop-types'; +import {GithubLoginModelPropType, WorkdirContextPoolPropType} from '../prop-types'; import IssueishDetailContainer from '../containers/issueish-detail-container'; export default class IssueishPaneItem extends Component { @@ -13,17 +13,19 @@ export default class IssueishPaneItem extends Component { repo: PropTypes.string.isRequired, issueishNumber: PropTypes.number.isRequired, + workingDirectory: PropTypes.string.isRequired, + workdirContextPool: WorkdirContextPoolPropType.isRequired, loginModel: GithubLoginModelPropType.isRequired, } - static uriPattern = 'atom-github://issueish/{host}/{owner}/{repo}/{issueishNumber}' + static uriPattern = 'atom-github://issueish/{host}/{owner}/{repo}/{issueishNumber}?workdir={workingDirectory}' - static buildURI(host, owner, repo, number) { + static buildURI(host, owner, repo, number, workdir) { return 'atom-github://issueish/' + encodeURIComponent(host) + '/' + encodeURIComponent(owner) + '/' + encodeURIComponent(repo) + '/' + - encodeURIComponent(number); + encodeURIComponent(number) + '?workdir=' + encodeURIComponent(workdir); } constructor(props) { @@ -43,6 +45,8 @@ export default class IssueishPaneItem extends Component { } render() { + const repository = this.props.workdirContextPool.getContext(this.props.workingDirectory).getRepository(); + return ( Date: Thu, 5 Jul 2018 08:59:10 -0400 Subject: [PATCH 0460/4847] Observe a Repository model in an IssueishDetailContainer --- lib/containers/issueish-detail-container.js | 51 +++++++++++++++---- .../issueish-detail-container.test.js | 10 ++-- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index 3ffe6a2313..8449e2161e 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -21,6 +21,7 @@ export default class IssueishDetailContainer extends React.Component { repo: PropTypes.string.isRequired, issueishNumber: PropTypes.number.isRequired, + repository: PropTypes.object.isRequired, loginModel: GithubLoginModelPropType.isRequired, switchToIssueish: PropTypes.func.isRequired, @@ -29,10 +30,15 @@ export default class IssueishDetailContainer extends React.Component { constructor(props) { super(props); - autobind(this, 'fetchData', 'renderWithToken', 'renderWithResult', 'handleLogin', 'handleLogout'); + autobind(this, + 'fetchToken', 'renderWithToken', + 'fetchRepositoryData', 'renderWithRepositoryData', + 'renderWithResult', + 'handleLogin', 'handleLogout', + ); } - fetchData(loginModel) { + fetchToken(loginModel) { return yubikiri({ token: loginModel.getToken(this.props.host), }); @@ -40,22 +46,34 @@ export default class IssueishDetailContainer extends React.Component { render() { return ( - + {this.renderWithToken} ); } - renderWithToken(data) { - if (!data) { + fetchRepositoryData(repository) { + return yubikiri({ + branches: repository.getBranches(), + remotes: repository.getRemotes(), + isMerging: repository.isMerging(), + isRebasing: repository.isRebasing(), + unstagedChanges: repository.getUnstagedChanges(), + stagedChanges: repository.getStagedChanges(), + mergeConflicts: repository.getMergeConflicts(), + }); + } + + renderWithToken(tokenData) { + if (!tokenData) { return ; } - if (data.token === UNAUTHENTICATED) { + if (tokenData.token === UNAUTHENTICATED) { return ; } - if (data.token === INSUFFICIENT) { + if (tokenData.token === INSUFFICIENT) { return (

    @@ -65,7 +83,19 @@ export default class IssueishDetailContainer extends React.Component { ); } - const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, data.token); + return ( + + {repoData => this.renderWithRepositoryData(repoData, tokenData.token)} + + ); + } + + renderWithRepositoryData(repoData, token) { + if (!repoData) { + return ; + } + + const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.host, token); const query = graphql` query issueishDetailContainerQuery ( @@ -98,13 +128,13 @@ export default class IssueishDetailContainer extends React.Component { environment={environment} query={query} variables={variables} - render={this.renderWithResult} + render={queryResult => this.renderWithResult(queryResult, repoData)} /> ); } - renderWithResult({error, props, retry}) { + renderWithResult({error, props, retry}, repoData) { if (error) { return ( ; + return ; } it('renders a spinner while the token is being fetched', function() { From 1247977a42e0e9b5f640706bca2c06e6c910663f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 5 Jul 2018 09:50:07 -0400 Subject: [PATCH 0461/4847] Pass the WorkdirContextPool to opened IssueishPaneItems --- lib/controllers/root-controller.js | 4 ++++ test/controllers/root-controller.test.js | 21 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index c050d0e436..5a70621f14 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -23,6 +23,7 @@ import RepositoryConflictController from './repository-conflict-controller'; import GitCacheView from '../views/git-cache-view'; import Conflict from '../models/conflicts/conflict'; import Switchboard from '../switchboard'; +import {WorkdirContextPoolPropType} from '../prop-types'; import {destroyFilePatchPaneItems, destroyEmptyFilePatchPaneItems, autobind} from '../helpers'; import {GitError} from '../git-shell-out-strategy'; @@ -38,6 +39,7 @@ export default class RootController extends React.Component { project: PropTypes.object.isRequired, loginModel: PropTypes.object.isRequired, confirm: PropTypes.func.isRequired, + workdirContextPool: WorkdirContextPoolPropType.isRequired, getRepositoryForWorkdir: PropTypes.func.isRequired, createRepositoryForProjectPath: PropTypes.func, cloneRepositoryForProjectPath: PropTypes.func, @@ -332,6 +334,8 @@ export default class RootController extends React.Component { repo={params.repo} issueishNumber={parseInt(params.issueishNumber, 10)} + workingDirectory={params.workingDirectory} + workdirContextPool={this.props.workdirContextPool} loginModel={this.props.loginModel} /> )} diff --git a/test/controllers/root-controller.test.js b/test/controllers/root-controller.test.js index 8036b83584..7f10e04c41 100644 --- a/test/controllers/root-controller.test.js +++ b/test/controllers/root-controller.test.js @@ -8,16 +8,20 @@ import dedent from 'dedent-js'; import {cloneRepository, buildRepository} from '../helpers'; import {GitError} from '../../lib/git-shell-out-strategy'; import Repository from '../../lib/models/repository'; +import WorkdirContextPool from '../../lib/models/workdir-context-pool'; +import GithubLoginModel from '../../lib/models/github-login-model'; +import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; import GitTabItem from '../../lib/items/git-tab-item'; import GithubTabController from '../../lib/controllers/github-tab-controller'; import ResolutionProgress from '../../lib/models/conflicts/resolution-progress'; +import IssueishPaneItem from '../../lib/items/issueish-pane-item'; import RootController from '../../lib/controllers/root-controller'; describe('RootController', function() { let atomEnv, app; let workspace, commandRegistry, notificationManager, tooltips, config, confirm, deserializers, grammars, project; - let getRepositoryForWorkdir; + let workdirContextPool, getRepositoryForWorkdir; beforeEach(function() { atomEnv = global.buildAtomEnvironment(); @@ -30,8 +34,10 @@ describe('RootController', function() { config = atomEnv.config; project = atomEnv.project; + workdirContextPool = new WorkdirContextPool(); getRepositoryForWorkdir = sinon.stub(); + const loginModel = new GithubLoginModel(InMemoryStrategy); const absentRepository = Repository.absent(); const emptyResolutionProgress = new ResolutionProgress(); @@ -47,10 +53,12 @@ describe('RootController', function() { config={config} confirm={confirm} project={project} + loginModel={loginModel} repository={absentRepository} resolutionProgress={emptyResolutionProgress} startOpen={false} startRevealed={false} + workdirContextPool={workdirContextPool} getRepositoryForWorkdir={getRepositoryForWorkdir} /> ); @@ -1037,4 +1045,15 @@ describe('RootController', function() { }); }); }); + + describe('opening an IssueishPaneItem', function() { + it('registers an opener for IssueishPaneItems', async function() { + const uri = IssueishPaneItem.buildURI('https://api.github.com', 'owner', 'repo', 123, __dirname); + const wrapper = mount(app); + + const item = await atomEnv.workspace.open(uri); + assert.strictEqual(item.getTitle(), 'owner/repo#123'); + assert.lengthOf(wrapper.update().find('IssueishPaneItem'), 1); + }); + }); }); From a804145018de37df2b45cf0cba965cf5399949b4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 5 Jul 2018 09:52:33 -0400 Subject: [PATCH 0462/4847] Pass the WorkdirContextPool to the RootController --- lib/github-package.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/github-package.js b/lib/github-package.js index a006004f9b..ea7ea57cb0 100644 --- a/lib/github-package.js +++ b/lib/github-package.js @@ -282,6 +282,7 @@ export default class GithubPackage { config={this.config} project={this.project} confirm={this.confirm} + workdirContextPool={this.contextPool} loginModel={this.loginModel} repository={this.getActiveRepository()} resolutionProgress={this.getActiveResolutionProgress()} From 881fe02190fd758d55f03bb5378e2d82059995a7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 5 Jul 2018 11:17:32 -0400 Subject: [PATCH 0463/4847] MaybeOperation allows you to enable/disable an operation for children --- lib/models/maybe-operation.js | 78 ++++++++++++++++ test/models/maybe-operation.test.js | 137 ++++++++++++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 lib/models/maybe-operation.js create mode 100644 test/models/maybe-operation.test.js diff --git a/lib/models/maybe-operation.js b/lib/models/maybe-operation.js new file mode 100644 index 0000000000..8e0bb085ed --- /dev/null +++ b/lib/models/maybe-operation.js @@ -0,0 +1,78 @@ +const DISABLEMENT = Symbol('disablement'); +const ENABLED = Symbol('enabled'); +const NO_REASON = Symbol('no-reason'); + +// Track an operation that may be either enabled or disabled with a message and a reason. MaybeOperation instances are +// immutable to aid passing them as React comopnent props; call `.enable()` or `.disable()` to derive a new operation +// instance with the same callback. +export default class MaybeOperation { + constructor(op, options = {}) { + this.beforeOp = null; + this.op = op; + this.afterOp = null; + this.disablement = options[DISABLEMENT] || ENABLED; + } + + toggleState(component, stateKey) { + this.beforeOp = () => { + component.setState(prevState => { + return !prevState[stateKey] ? {[stateKey]: true} : {}; + }); + }; + + this.afterOp = () => { + return new Promise(resolve => { + component.setState(prevState => { + return prevState[stateKey] ? {[stateKey]: false} : {}; + }, resolve); + }); + }; + } + + isEnabled() { + return this.disablement === ENABLED; + } + + async run() { + if (!this.isEnabled()) { + throw new Error(this.disablement.message); + } + + if (this.beforeOp) { + this.beforeOp(); + } + let result = undefined; + try { + result = await this.op(); + } finally { + if (this.afterOp) { + await this.afterOp(); + } + } + return result; + } + + getMessage() { + return this.disablement.message; + } + + why() { + return this.disablement.reason; + } + + disable(reason = NO_REASON, message = 'disabled') { + if (!this.isEnabled() && this.disablement.reason === reason && this.disablement.message === message) { + return this; + } + + return new this.constructor(this.op, {[DISABLEMENT]: {reason, message}}); + } + + enable() { + if (this.isEnabled()) { + return this; + } + + return new this.constructor(this.op, {[DISABLEMENT]: ENABLED}); + } +} diff --git a/test/models/maybe-operation.test.js b/test/models/maybe-operation.test.js new file mode 100644 index 0000000000..b98423b120 --- /dev/null +++ b/test/models/maybe-operation.test.js @@ -0,0 +1,137 @@ +import MaybeOperation from '../../lib/models/maybe-operation'; + +class ComponentLike { + constructor() { + this.state = {inProgress: false}; + this.beforeRenderPromise = null; + } + + simulateAsyncRender() { + this.beforeRenderPromise = new Promise(resolve => { + this.resolveBeforeRenderPromise = resolve; + }); + } + + async setState(changeCb, afterCb) { + // Simulate an asynchronous render. + if (this.beforeRenderPromise) { + await this.beforeRenderPromise; + } + const after = changeCb(this.state); + this.state.inProgress = after.inProgress !== undefined ? after.inProgress : this.state.inProgress; + if (afterCb) { afterCb(); } + } +} + +describe('MaybeOperation', function() { + let callback, op; + const REASON = Symbol('reason'); + + beforeEach(function() { + callback = sinon.stub(); + op = new MaybeOperation(callback); + }); + + it('defaults to being enabled', async function() { + callback.resolves(123); + + assert.isTrue(op.isEnabled()); + assert.strictEqual(await op.run(), 123); + }); + + it('may be disabled with a message', async function() { + const disabled = op.disable(REASON, "I don't want to"); + assert.notStrictEqual(disabled, op); + assert.isFalse(disabled.isEnabled()); + assert.strictEqual(disabled.why(), REASON); + assert.strictEqual(disabled.getMessage(), "I don't want to"); + await assert.isRejected(disabled.run(), /I don't want to/); + }); + + it('may be disabled with a different message', function() { + const disabled0 = op.disable(REASON, 'one'); + assert.notStrictEqual(disabled0, op); + assert.strictEqual(disabled0.why(), REASON); + assert.strictEqual(disabled0.getMessage(), 'one'); + + const disabled1 = disabled0.disable(REASON, 'two'); + assert.notStrictEqual(disabled1, disabled0); + assert.strictEqual(disabled1.why(), REASON); + assert.strictEqual(disabled1.getMessage(), 'two'); + }); + + it('provides a default disablement message if omitted', async function() { + const disabled = op.disable(); + assert.notStrictEqual(disabled, op); + assert.isFalse(disabled.isEnabled()); + assert.strictEqual(disabled.getMessage(), 'disabled'); + await assert.isRejected(disabled.run(), /disabled/); + }); + + it('may be re-enabled', async function() { + callback.resolves(123); + + const reenabled = op.disable().enable(); + assert.notStrictEqual(reenabled, op); + assert.isTrue(op.isEnabled()); + assert.strictEqual(await op.run(), 123); + }); + + it('returns itself when transitioning to the same state', function() { + assert.strictEqual(op, op.enable()); + const disabled = op.disable(); + assert.strictEqual(disabled, disabled.disable()); + }); + + it('can be wired to toggle component state before and after its action', async function() { + const component = new ComponentLike(); + op.toggleState(component, 'inProgress'); + + assert.isFalse(component.state.inProgress); + const promise = op.run(); + assert.isTrue(component.state.inProgress); + await promise; + assert.isFalse(component.state.inProgress); + }); + + it('restores the progress tracking state even if the operation fails', async function() { + const component = new ComponentLike(); + op.toggleState(component, 'inProgress'); + callback.rejects(new Error('boom')); + + assert.isFalse(component.state.inProgress); + const promise = op.run(); + assert.isTrue(component.state.inProgress); + await assert.isRejected(promise, /boom/); + assert.isFalse(component.state.inProgress); + }); + + it('does not toggle state if the state has been redundantly toggled', async function() { + let resolveCbPromise = () => {}; + const cbPromise = new Promise(resolve => { + resolveCbPromise = resolve; + }); + callback.returns(resolveCbPromise); + + const component = new ComponentLike(); + component.simulateAsyncRender(); + op.toggleState(component, 'inProgress'); + + assert.isFalse(component.state.inProgress); + const opPromise = op.run(); + + assert.isFalse(component.state.inProgress); + component.state.inProgress = true; + + component.resolveBeforeRenderPromise(); + await component.beforeRenderPromise; + + assert.isTrue(component.state.inProgress); + + component.state.inProgress = false; + + resolveCbPromise(); + await Promise.all([cbPromise, opPromise]); + assert.isFalse(component.state.inProgress); + }); +}); From 6d15c4e7813f4bc823f659248b7c4ce9d3f0a984 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 5 Jul 2018 11:51:42 -0400 Subject: [PATCH 0464/4847] Use RemoteSet to store... sets of Remotes --- lib/models/remote-set.js | 30 +++++++++++++++++++++++++++ test/models/remote-set.test.js | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 lib/models/remote-set.js create mode 100644 test/models/remote-set.test.js diff --git a/lib/models/remote-set.js b/lib/models/remote-set.js new file mode 100644 index 0000000000..ade2116ce7 --- /dev/null +++ b/lib/models/remote-set.js @@ -0,0 +1,30 @@ +import {nullRemote} from './remote'; + +export default class RemoteSet { + constructor(iterable = []) { + this.byName = new Map(); + for (const remote of iterable) { + this.add(remote); + } + } + + add(remote) { + this.byName.set(remote.getName(), remote); + } + + isEmpty() { + return this.byName.size === 0; + } + + size() { + return this.byName.size; + } + + withName(name) { + return this.byName.get(name) || nullRemote; + } + + [Symbol.iterator]() { + return this.byName.values(); + } +} diff --git a/test/models/remote-set.test.js b/test/models/remote-set.test.js new file mode 100644 index 0000000000..162488141f --- /dev/null +++ b/test/models/remote-set.test.js @@ -0,0 +1,38 @@ +import RemoteSet from '../../lib/models/remote-set'; +import Remote from '../../lib/models/remote'; + +describe('RemoteSet', function() { + const remotes = [ + new Remote('origin', 'git@github.com:origin/repo.git'), + new Remote('upstream', 'git@github.com:upstream/repo.git'), + ]; + + it('creates an empty set', function() { + const set = new RemoteSet(); + assert.isTrue(set.isEmpty()); + assert.strictEqual(set.size(), 0); + }); + + it('creates a set containing one or more Remotes', function() { + const set = new RemoteSet(remotes); + assert.isFalse(set.isEmpty()); + assert.strictEqual(set.size(), 2); + }); + + it('retrieves a Remote from the set by name', function() { + const set = new RemoteSet(remotes); + const remote = set.withName('upstream'); + assert.strictEqual(remote, remotes[1]); + }); + + it('returns a nullRemote for unknown remote names', function() { + const set = new RemoteSet(remotes); + const remote = set.withName('unknown'); + assert.isFalse(remote.isPresent()); + }); + + it('iterates over the Remotes', function() { + const set = new RemoteSet(remotes); + assert.deepEqual(Array.from(set), remotes); + }); +}); From 944b9bebb186f4474ba72c367cb7013b63553a32 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 5 Jul 2018 11:54:48 -0400 Subject: [PATCH 0465/4847] Return indexed RemoteSets from .getRemotes() --- lib/models/repository-states/present.js | 5 ++++- lib/models/repository-states/state.js | 3 ++- test/models/repository.test.js | 30 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index 2acf5a28bc..96c77c9e06 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -14,6 +14,7 @@ import Branch, {nullBranch} from '../branch'; import Author from '../author'; import BranchSet from '../branch-set'; import Remote from '../remote'; +import RemoteSet from '../remote-set'; import Commit from '../commit'; import OperationStates from '../operation-states'; @@ -689,7 +690,9 @@ export default class Present extends State { getRemotes() { return this.cache.getOrSet(Keys.remotes, async () => { const remotesInfo = await this.git().getRemotes(); - return remotesInfo.map(({name, url}) => new Remote(name, url)); + return new RemoteSet( + remotesInfo.map(({name, url}) => new Remote(name, url)), + ); }); } diff --git a/lib/models/repository-states/state.js b/lib/models/repository-states/state.js index c24f9080a1..b9e6fddbbb 100644 --- a/lib/models/repository-states/state.js +++ b/lib/models/repository-states/state.js @@ -1,5 +1,6 @@ import {nullCommit} from '../commit'; import BranchSet from '../branch-set'; +import RemoteSet from '../remote-set'; import {nullOperationStates} from '../operation-states'; /** @@ -319,7 +320,7 @@ export default class State { // Remotes getRemotes() { - return Promise.resolve([]); + return Promise.resolve(new RemoteSet([])); } getAheadCount(branchName) { diff --git a/test/models/repository.test.js b/test/models/repository.test.js index ca28ee4131..6a3504c8cb 100644 --- a/test/models/repository.test.js +++ b/test/models/repository.test.js @@ -570,6 +570,36 @@ describe('Repository', function() { }); }); + describe('getRemotes()', function() { + it('returns an empty RemoteSet before the repository has loaded', async function() { + const workdir = await cloneRepository('three-files'); + const repository = new Repository(workdir); + assert.isTrue(repository.isLoading()); + + const remotes = await repository.getRemotes(); + assert.isTrue(remotes.isEmpty()); + }); + + it('returns a RemoteSet that indexes remotes by name', async function() { + const workdir = await cloneRepository('three-files'); + const repository = new Repository(workdir); + await repository.getLoadPromise(); + + await repository.setConfig('remote.origin.url', 'git@github.com:smashwilson/atom.git'); + await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); + + await repository.setConfig('remote.upstream.url', 'git@github.com:atom/atom.git'); + await repository.setConfig('remote.upstream.fetch', '+refs/heads/*:refs/remotes/upstream/*'); + + const remotes = await repository.getRemotes(); + assert.isFalse(remotes.isEmpty()); + + const origin = remotes.withName('origin'); + assert.strictEqual(origin.getName(), 'origin'); + assert.strictEqual(origin.getUrl(), 'git@github.com:smashwilson/atom.git'); + }); + }); + describe('pull()', function() { it('updates the remote branch and merges into local branch', async function() { const {localRepoPath} = await setUpLocalAndRemoteRepositories({remoteAhead: true}); From 7d829f0caa26132673f8536159851f978622c2e9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 5 Jul 2018 13:01:06 -0400 Subject: [PATCH 0466/4847] Filter a RemoteSet by a predicate function --- lib/models/remote-set.js | 6 ++++++ test/models/remote-set.test.js | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/models/remote-set.js b/lib/models/remote-set.js index ade2116ce7..ae43150a85 100644 --- a/lib/models/remote-set.js +++ b/lib/models/remote-set.js @@ -27,4 +27,10 @@ export default class RemoteSet { [Symbol.iterator]() { return this.byName.values(); } + + filter(predicate) { + return new this.constructor( + Array.from(this).filter(predicate), + ); + } } diff --git a/test/models/remote-set.test.js b/test/models/remote-set.test.js index 162488141f..604c6397ae 100644 --- a/test/models/remote-set.test.js +++ b/test/models/remote-set.test.js @@ -35,4 +35,13 @@ describe('RemoteSet', function() { const set = new RemoteSet(remotes); assert.deepEqual(Array.from(set), remotes); }); + + it('filters remotes by a predicate', function() { + const set0 = new RemoteSet(remotes); + const set1 = set0.filter(remote => remote.getName() === 'upstream'); + + assert.notStrictEqual(set0, set1); + assert.isTrue(set1.withName('upstream').isPresent()); + assert.isFalse(set1.withName('origin1').isPresent()); + }); }); From d19ca91e54f4fea954a7486a3bff28b535e354a3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 5 Jul 2018 13:12:26 -0400 Subject: [PATCH 0467/4847] Update callers of getRemotes() to expect a RemoteSet --- .../current-pull-request-container.js | 8 +++--- lib/containers/remote-container.js | 6 ++--- lib/controllers/github-tab-controller.js | 27 +++++++++---------- .../issueish-searches-controller.js | 6 ++--- lib/controllers/remote-controller.js | 6 ++--- lib/controllers/status-bar-tile-controller.js | 5 +--- lib/models/user-store.js | 4 +-- lib/prop-types.js | 7 +++++ lib/views/remote-selector-view.js | 6 ++--- .../current-pull-request-container.test.js | 5 ++-- .../issueish-searches-controller.test.js | 5 ++-- 11 files changed, 44 insertions(+), 41 deletions(-) diff --git a/lib/containers/current-pull-request-container.js b/lib/containers/current-pull-request-container.js index f761b44d1a..92479afcdf 100644 --- a/lib/containers/current-pull-request-container.js +++ b/lib/containers/current-pull-request-container.js @@ -4,7 +4,7 @@ import {QueryRenderer, graphql} from 'react-relay'; import {Disposable} from 'event-kit'; import {autobind} from '../helpers'; -import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; +import {RemotePropType, RemoteSetPropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; import IssueishListController, {BareIssueishListController} from '../controllers/issueish-list-controller'; import CreatePullRequestTile from '../views/create-pull-request-tile'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; @@ -24,7 +24,7 @@ export default class CurrentPullRequestContainer extends React.Component { limit: PropTypes.number, remoteOperationObserver: OperationStateObserverPropType.isRequired, remote: RemotePropType.isRequired, - remotesByName: PropTypes.shape({get: PropTypes.func}).isRequired, + remotes: RemoteSetPropType.isRequired, branches: BranchSetPropType.isRequired, aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, @@ -55,8 +55,8 @@ export default class CurrentPullRequestContainer extends React.Component { if (!push.isPresent() || !push.isRemoteTracking()) { return this.renderEmptyResult(); } - const pushRemote = this.props.remotesByName.get(push.getRemoteName()); - if (!pushRemote || !pushRemote.isPresent() || !pushRemote.isGithubRepo()) { + const pushRemote = this.props.remotes.withName(push.getRemoteName()); + if (!pushRemote.isPresent() || !pushRemote.isGithubRepo()) { return this.renderEmptyResult(); } diff --git a/lib/containers/remote-container.js b/lib/containers/remote-container.js index 74dc9d4619..7a6635c81b 100644 --- a/lib/containers/remote-container.js +++ b/lib/containers/remote-container.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {QueryRenderer, graphql} from 'react-relay'; import {autobind} from '../helpers'; -import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; +import {RemotePropType, RemoteSetPropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; import RemoteController from '../controllers/remote-controller'; @@ -21,7 +21,7 @@ export default class RemoteContainer extends React.Component { remoteOperationObserver: OperationStateObserverPropType.isRequired, workspace: PropTypes.object.isRequired, remote: RemotePropType.isRequired, - remotesByName: PropTypes.shape({get: PropTypes.func}).isRequired, + remotes: RemoteSetPropType.isRequired, branches: BranchSetPropType.isRequired, aheadCount: PropTypes.number, @@ -120,7 +120,7 @@ export default class RemoteContainer extends React.Component { remoteOperationObserver={this.props.remoteOperationObserver} workspace={this.props.workspace} remote={this.props.remote} - remotesByName={this.props.remotesByName} + remotes={this.props.remotes} branches={this.props.branches} aheadCount={this.props.aheadCount} diff --git a/lib/controllers/github-tab-controller.js b/lib/controllers/github-tab-controller.js index 6ad6689ffe..dc680bdfe9 100644 --- a/lib/controllers/github-tab-controller.js +++ b/lib/controllers/github-tab-controller.js @@ -42,7 +42,7 @@ export default class GithubTabController extends React.Component { fetchModelData(repo) { return yubikiri({ - remotes: repo.getRemotes().then(remotes => remotes.filter(remote => remote.isGithubRepo())), + allRemotes: repo.getRemotes(), branches: repo.getBranches(), selectedRemoteName: repo.getConfig('atomGithub.currentRemote'), selectedPrUrl: async query => { @@ -76,33 +76,30 @@ export default class GithubTabController extends React.Component { renderWithData(data) { const { - remotes, branches, selectedRemoteName, aheadCount, + allRemotes, branches, selectedRemoteName, aheadCount, } = data; - if (!this.props.repository.isPresent() || !remotes) { + if (!this.props.repository.isPresent()) { return null; } + const remotes = allRemotes.filter(remote => remote.isGithubRepo()); const currentBranch = branches.getHeadBranch(); - let remote = remotes.find(r => r.getName() === selectedRemoteName); + let remote = remotes.withName(selectedRemoteName); let manyRemotesAvailable = false; - if (!remote && remotes.length === 1) { - remote = remotes[0]; - } else if (!remote && remotes.length > 1) { + if (!remote.isPresent() && remotes.size() === 1) { + remote = Array.from(remotes)[0]; + } else if (!remote.isPresent() && remotes.size() > 1) { manyRemotesAvailable = true; } - const remotesByName = new Map( - remotes.map(r => [r.getName(), remote]), - ); - const pushInProgress = this.props.repository.getOperationStates().isPushInProgress(); return (

    { this.root = c; }} className="github-GithubTabController">
    {/* only supporting GH.com for now, hardcoded values */} - {remote && + {remote.isPresent() && this.handlePushBranch(currentBranch, remote)} remote={remote} - remotesByName={remotesByName} + remotes={remotes} branches={branches} aheadCount={aheadCount} pushInProgress={pushInProgress} /> } - {!remote && manyRemotesAvailable && + {!remote.isPresent() && manyRemotesAvailable && } - {!remote && !manyRemotesAvailable && this.renderNoRemotes()} + {!remote.isPresent() && !manyRemotesAvailable && this.renderNoRemotes()}
    ); diff --git a/lib/controllers/issueish-searches-controller.js b/lib/controllers/issueish-searches-controller.js index 83b8f0f491..277fc5003a 100644 --- a/lib/controllers/issueish-searches-controller.js +++ b/lib/controllers/issueish-searches-controller.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {shell} from 'electron'; import {autobind} from '../helpers'; -import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; +import {RemotePropType, RemoteSetPropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; import Search from '../models/search'; import IssueishSearchContainer from '../containers/issueish-search-container'; import CurrentPullRequestContainer from '../containers/current-pull-request-container'; @@ -25,7 +25,7 @@ export default class IssueishSearchesController extends React.Component { remoteOperationObserver: OperationStateObserverPropType.isRequired, remote: RemotePropType.isRequired, - remotesByName: PropTypes.shape({get: PropTypes.func}).isRequired, + remotes: RemoteSetPropType.isRequired, branches: BranchSetPropType.isRequired, aheadCount: PropTypes.number, pushInProgress: PropTypes.bool.isRequired, @@ -57,7 +57,7 @@ export default class IssueishSearchesController extends React.Component { host={this.props.host} remoteOperationObserver={this.props.remoteOperationObserver} remote={this.props.remote} - remotesByName={this.props.remotesByName} + remotes={this.props.remotes} branches={this.props.branches} aheadCount={this.props.aheadCount} pushInProgress={this.props.pushInProgress} diff --git a/lib/controllers/remote-controller.js b/lib/controllers/remote-controller.js index da75e4e329..a5f343ee62 100644 --- a/lib/controllers/remote-controller.js +++ b/lib/controllers/remote-controller.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {shell} from 'electron'; import {autobind} from '../helpers'; -import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; +import {RemotePropType, RemoteSetPropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; import IssueishSearchesController from './issueish-searches-controller'; export default class RemoteController extends React.Component { @@ -22,7 +22,7 @@ export default class RemoteController extends React.Component { remoteOperationObserver: OperationStateObserverPropType.isRequired, workspace: PropTypes.object.isRequired, remote: RemotePropType.isRequired, - remotesByName: PropTypes.shape({get: PropTypes.func}).isRequired, + remotes: RemoteSetPropType.isRequired, branches: BranchSetPropType.isRequired, aheadCount: PropTypes.number, @@ -47,7 +47,7 @@ export default class RemoteController extends React.Component { workspace={this.props.workspace} remote={this.props.remote} - remotesByName={this.props.remotesByName} + remotes={this.props.remotes} branches={this.props.branches} aheadCount={this.props.aheadCount} pushInProgress={this.props.pushInProgress} diff --git a/lib/controllers/status-bar-tile-controller.js b/lib/controllers/status-bar-tile-controller.js index a38bc7a537..95cf29b31a 100644 --- a/lib/controllers/status-bar-tile-controller.js +++ b/lib/controllers/status-bar-tile-controller.js @@ -54,10 +54,7 @@ export default class StatusBarTileController extends React.Component { currentRemote: async query => repository.getRemoteForBranch((await query.currentBranch).getName()), aheadCount: async query => repository.getAheadCount((await query.currentBranch).getName()), behindCount: async query => repository.getBehindCount((await query.currentBranch).getName()), - originExists: async () => { - const remotes = await repository.getRemotes(); - return remotes.filter(remote => remote.getName() === 'origin').length > 0; - }, + originExists: async () => (await repository.getRemotes()).withName('origin').isPresent(), }); } diff --git a/lib/models/user-store.js b/lib/models/user-store.js index 2894c8c53d..90ffd5acb6 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -98,7 +98,7 @@ export default class UserStore { } this.setCommitter(data.committer); - const githubRemotes = data.remotes.filter(remote => remote.isGithubRepo()); + const githubRemotes = Array.from(data.remotes).filter(remote => remote.isGithubRepo()); if (githubRemotes.length === 0) { this.addUsers(data.authors, source.GITLOG); @@ -109,7 +109,7 @@ export default class UserStore { loadUsersFromGraphQL(remotes) { return Promise.all( - remotes.map(remote => this.loadMentionableUsers(remote)), + Array.from(remotes, remote => this.loadMentionableUsers(remote)), ); } diff --git a/lib/prop-types.js b/lib/prop-types.js index 73184029e4..b56fcaa538 100644 --- a/lib/prop-types.js +++ b/lib/prop-types.js @@ -41,6 +41,13 @@ export const SearchPropType = PropTypes.shape({ createQuery: PropTypes.func.isRequired, }); +export const RemoteSetPropType = PropTypes.shape({ + withName: PropTypes.func.isRequired, + isEmpty: PropTypes.func.isRequired, + size: PropTypes.func.isRequired, + [Symbol.iterator]: PropTypes.func.isRequired, +}); + export const BranchSetPropType = PropTypes.shape({ getNames: PropTypes.func.isRequired, getPullTargets: PropTypes.func.isRequired, diff --git a/lib/views/remote-selector-view.js b/lib/views/remote-selector-view.js index 8b28df727f..1aa66b5335 100644 --- a/lib/views/remote-selector-view.js +++ b/lib/views/remote-selector-view.js @@ -1,11 +1,11 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {RemotePropType, BranchPropType} from '../prop-types'; +import {RemoteSetPropType, BranchPropType} from '../prop-types'; export default class RemoteSelector extends React.Component { static propTypes = { - remotes: PropTypes.arrayOf(RemotePropType).isRequired, + remotes: RemoteSetPropType.isRequired, currentBranch: BranchPropType.isRequired, selectRemote: PropTypes.func.isRequired, } @@ -20,7 +20,7 @@ export default class RemoteSelector extends React.Component { with the {currentBranch.getName()} branch.

    + {isPr &&
    + +
    } + No description provided.'} switchToIssueish={this.props.switchToIssueish} @@ -154,10 +158,6 @@ export class BareIssueishDetailView extends React.Component { /> } - {isPr &&
    - -
    } -
    ); diff --git a/styles/issueish-detail-view.less b/styles/issueish-detail-view.less index 1e96464034..a4c906b85a 100644 --- a/styles/issueish-detail-view.less +++ b/styles/issueish-detail-view.less @@ -119,7 +119,7 @@ // Build Status ------------------------ &-buildStatus { - margin-top: @component-padding * 4; + margin: @component-padding*3 0; padding: @component-padding; border: 1px solid @base-border-color; border-radius: @component-border-radius; From 00a9274308bb2ba2bad580b40b295e5ee9577034 Mon Sep 17 00:00:00 2001 From: simurai Date: Mon, 16 Jul 2018 13:15:11 +0900 Subject: [PATCH 0555/4847] Make buildStatus more compact --- lib/views/pr-status-context-view.js | 2 +- styles/issueish-detail-view.less | 33 +++++++++++++++++-- styles/pr-statuses.less | 50 +++++++++++++++++++++++------ 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/lib/views/pr-status-context-view.js b/lib/views/pr-status-context-view.js index 9198ddfd68..c790f2344d 100644 --- a/lib/views/pr-status-context-view.js +++ b/lib/views/pr-status-context-view.js @@ -28,7 +28,7 @@ export class BarePrStatusContextView extends React.Component { - {context}
    {description} + {context} {description}
    Details diff --git a/styles/issueish-detail-view.less b/styles/issueish-detail-view.less index a4c906b85a..a764e87411 100644 --- a/styles/issueish-detail-view.less +++ b/styles/issueish-detail-view.less @@ -120,15 +120,19 @@ &-buildStatus { margin: @component-padding*3 0; - padding: @component-padding; - border: 1px solid @base-border-color; - border-radius: @component-border-radius; &:empty { display: none; } } + + // PR body ------------------------ + + &-container > .github-DotComMarkdownHtml { + margin: @component-padding*3 0; + } + } @@ -163,6 +167,14 @@ atom-dock .github-IssueishDetailView { line-height: 1.3; } + &-buildStatus { + margin: @component-padding 0; + + &:empty { + display: none; + } + } + .timeline-item { margin: 0; padding: @component-padding*1.5 0; @@ -176,4 +188,19 @@ atom-dock .github-IssueishDetailView { } } + &-container > .github-DotComMarkdownHtml { + margin: @component-padding 0; + } + +} + +atom-dock .github-PrStatuses { + &-header, + &-list-item { + border-radius: 0; + padding-left: 0; + padding-right: 0; + border-left: none; + border-right: none; + } } diff --git a/styles/pr-statuses.less b/styles/pr-statuses.less index 7b8838a193..36fcab7e2b 100644 --- a/styles/pr-statuses.less +++ b/styles/pr-statuses.less @@ -1,22 +1,37 @@ @import 'variables'; +@donut-size: 26px; +@donut-stroke: 4px; + .github-PrStatuses { + &-header { display: flex; + align-items: center; + border: 1px solid @base-border-color; + padding: @component-padding; + border-radius: @component-border-radius @component-border-radius 0 0; + } + + &-donut-chart { + margin-right: @component-padding; svg { - width: 50px; - height: 50px; + display: block; + width: @donut-size; + height: @donut-size; circle { - stroke-width: 5; + cx: @donut-size/2; + cy: @donut-size/2; + r: @donut-size/2 - @donut-stroke/2; + stroke-width: @donut-stroke; } } } &-summary { font-weight: bold; - padding: @component-padding 0; flex: 1; } @@ -31,21 +46,36 @@ &-list-item { display: flex; flex-direction: row; - border-top: 1px solid @base-border-color; - padding: @component-padding / 2; + font-size: .9em; + padding: @component-padding/2 @component-padding; + border: 1px solid @base-border-color; + border-top: none; + + &:last-child { + border-radius: 0 0 @component-border-radius @component-border-radius; + } &-icon { - padding-right: @component-padding; - display: flex; - align-items: center; // hmm, does it look better centered vertically or not + width: @donut-size; + margin-right: @component-padding; + text-align: center; + .icon::before { margin-right: 0; } } &-context { flex: 1; + color: @text-color-subtle; + strong { + margin-right: .5em; + color: @text-color-highlight; + } } &-details-link { - margin-left: 5px; + margin-left: .5em; + a { + color: @text-color-info; + } } } From 8db59eccacba9f7d27b392e89a6a656501bafe1a Mon Sep 17 00:00:00 2001 From: simurai Date: Mon, 16 Jul 2018 15:03:06 +0900 Subject: [PATCH 0556/4847] Make reactions look less like buttons --- styles/issueish-detail-view.less | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/styles/issueish-detail-view.less b/styles/issueish-detail-view.less index a764e87411..251e6040f9 100644 --- a/styles/issueish-detail-view.less +++ b/styles/issueish-detail-view.less @@ -100,18 +100,15 @@ // Reactions ------------------------ &-reactions { - margin-top: @component-padding; + padding-top: @component-padding*3; + border-top: 1px solid @base-border-color; &:empty { display: none; } &Group { - display: inline-block; - margin-right: @component-padding; - padding: @component-padding/2 @component-padding; - border: 1px solid @base-border-color; - border-radius: @component-border-radius; + margin-right: @component-padding*2; } } @@ -167,6 +164,10 @@ atom-dock .github-IssueishDetailView { line-height: 1.3; } + &-reactions { + padding-top: @component-padding; + } + &-buildStatus { margin: @component-padding 0; @@ -175,6 +176,10 @@ atom-dock .github-IssueishDetailView { } } + .github-PrTimeline { + margin-top: @component-padding; + } + .timeline-item { margin: 0; padding: @component-padding*1.5 0; From 72bfa6f8e4cd0f04f7677bc0bd64c2e2c675c6a1 Mon Sep 17 00:00:00 2001 From: simurai Date: Mon, 16 Jul 2018 16:03:03 +0900 Subject: [PATCH 0557/4847] Show co-authors stacked --- styles/pr-timeline.less | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/styles/pr-timeline.less b/styles/pr-timeline.less index 357f114916..7db789f812 100644 --- a/styles/pr-timeline.less +++ b/styles/pr-timeline.less @@ -59,19 +59,45 @@ } .commit-author { - display: table-cell; - white-space: nowrap; - text-align: right; + position: absolute; + display: flex; } .author-avatar { - flex-basis: @avatar-size; + @size: 20px; + position: relative; + margin-right: -@size + 4px; + width: @size; + height: @size; + border-radius: @component-border-radius; + background-color: mix(@text-color, @base-background-color, 15%); + box-shadow: 1px 0 @base-background-color; + transition: margin .12s cubic-bezier(.5,.1,0,1); + + &:nth-child(1) { z-index: 3; } + &:nth-child(2) { z-index: 2; opacity: .7; } + &:nth-child(3) { z-index: 1; opacity: .4; } + &:nth-child(n+4) { + display: none; + } + &:only-child, + &:last-child { + box-shadow: none; + } + } + + .commit-author:hover .author-avatar { + display: inline-block; + margin-right: 1px; + opacity: 1; } .commit-message-headline { display: table-cell; font-size: .9em; + line-height: @avatar-size + 4px; padding: 0 @component-padding/3; + padding-left: @avatar-size + @component-padding; max-height: @avatar-size; text-overflow: ellipsis; white-space: nowrap; From 0a9295ab09db4c1d666df8a0791e21729ae41f69 Mon Sep 17 00:00:00 2001 From: simurai Date: Mon, 16 Jul 2018 16:11:23 +0900 Subject: [PATCH 0558/4847] De-emphasize headers --- styles/pr-timeline.less | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/styles/pr-timeline.less b/styles/pr-timeline.less index 7db789f812..a4d476e1c1 100644 --- a/styles/pr-timeline.less +++ b/styles/pr-timeline.less @@ -116,6 +116,11 @@ } } + .comment-message-header { + font-size: .9em; + color: @text-color-subtle; + } + .cross-referenced-events { // provides spacing between cross-referenced-event rows border-spacing: 0 @component-padding / 2; @@ -132,6 +137,11 @@ margin-bottom: 0; } + &-header { + font-size: .9em; + color: @text-color-subtle; + } + &-label { display: table-cell; width: 100%; @@ -199,10 +209,6 @@ .info-row { margin-bottom: @component-padding/1.5; } - .comment-message-header { - font-size: .9em; - color: @text-color-subtle; - } .github-DotComMarkdownHtml { pre > code { From 60680d1be3174d02798264ecd13a91cffbad05fe Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 16 Jul 2018 08:59:12 -0400 Subject: [PATCH 0559/4847] Use the new Context API for RelayEnvironment --- lib/containers/issueish-detail-container.js | 4 ++-- lib/views/github-dotcom-markdown.js | 14 +++++++++++--- lib/views/relay-environment.js | 20 +------------------- test/views/github-dotcom-markdown.test.js | 12 ++++++++++-- 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index e3cd283eb0..8213caceef 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -123,14 +123,14 @@ export default class IssueishDetailContainer extends React.Component { }; return ( - + this.renderWithResult(queryResult, repoData)} /> - + ); } diff --git a/lib/views/github-dotcom-markdown.js b/lib/views/github-dotcom-markdown.js index 6d5e3d136e..c4b6bd78c2 100644 --- a/lib/views/github-dotcom-markdown.js +++ b/lib/views/github-dotcom-markdown.js @@ -7,10 +7,12 @@ import PropTypes from 'prop-types'; import {handleClickEvent, openIssueishLinkInNewTab, openLinkInBrowser, getDataFromGithubUrl} from './issueish-link'; import UserMentionTooltipItem from '../items/user-mention-tooltip-item'; import IssueishTooltipItem from '../items/issueish-tooltip-item'; +import RelayEnvironment from './relay-environment'; import {autobind} from '../helpers'; -export default class GithubDotcomMarkdown extends React.Component { +export class BareGithubDotcomMarkdown extends React.Component { static propTypes = { + relayEnvironment: PropTypes.object.isRequired, html: PropTypes.string.isRequired, switchToIssueish: PropTypes.func.isRequired, handleClickEvent: PropTypes.func, @@ -57,7 +59,7 @@ export default class GithubDotcomMarkdown extends React.Component { this.tooltipSubscriptions = new CompositeDisposable(); this.component.querySelectorAll('.user-mention').forEach(node => { - const item = new UserMentionTooltipItem(node.textContent, this.context.relayEnvironment); + const item = new UserMentionTooltipItem(node.textContent, this.props.relayEnvironment); this.tooltipSubscriptions.add(atom.tooltips.add(node, { trigger: 'hover', delay: 0, @@ -66,7 +68,7 @@ export default class GithubDotcomMarkdown extends React.Component { this.tooltipSubscriptions.add(new Disposable(() => item.destroy())); }); this.component.querySelectorAll('.issue-link').forEach(node => { - const item = new IssueishTooltipItem(node.getAttribute('href'), this.context.relayEnvironment); + const item = new IssueishTooltipItem(node.getAttribute('href'), this.props.relayEnvironment); this.tooltipSubscriptions.add(atom.tooltips.add(node, { trigger: 'hover', delay: 0, @@ -111,3 +113,9 @@ export default class GithubDotcomMarkdown extends React.Component { return this.props.openLinkInBrowser(event.target.getAttribute('href')); } } + +export default props => ( + + {relayEnvironment => } + +); diff --git a/lib/views/relay-environment.js b/lib/views/relay-environment.js index 8b8e370605..51b82c7da7 100644 --- a/lib/views/relay-environment.js +++ b/lib/views/relay-environment.js @@ -1,21 +1,3 @@ import React from 'react'; -import PropTypes from 'prop-types'; -export default class RelayEnvironment extends React.Component { - static propTypes = { - environment: PropTypes.object.isRequired, - children: PropTypes.node, - } - - static childContextTypes = { - relayEnvironment: PropTypes.object.isRequired, - } - - getChildContext() { - return {relayEnvironment: this.props.environment}; - } - - render() { - return this.props.children; - } -} +export default React.createContext(null); diff --git a/test/views/github-dotcom-markdown.test.js b/test/views/github-dotcom-markdown.test.js index 7b99cc7854..7cd01fde1a 100644 --- a/test/views/github-dotcom-markdown.test.js +++ b/test/views/github-dotcom-markdown.test.js @@ -1,12 +1,20 @@ import React from 'react'; import {mount} from 'enzyme'; -import GithubDotcomMarkdown from '../../lib/views/github-dotcom-markdown'; +import {BareGithubDotcomMarkdown} from '../../lib/views/github-dotcom-markdown'; +import RelayNetworkLayerManager from '../../lib/relay-network-layer-manager'; describe('GithubDotcomMarkdown', function() { + let relayEnvironment; + + beforeEach(function() { + relayEnvironment = RelayNetworkLayerManager.getEnvironmentForHost('https://api.somehost.com', '1234'); + }); + function buildApp(overloadProps = {}) { return ( - content

    '} switchToIssueish={() => {}} handleClickEvent={() => {}} From 615fda8c003c2d074544905aef47830aff9d932e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 16 Jul 2018 08:59:35 -0400 Subject: [PATCH 0560/4847] Dedupe dependencies because eslint couldn't find its plugins? --- package-lock.json | 3605 +++++++++++++-------------------------------- 1 file changed, 1043 insertions(+), 2562 deletions(-) diff --git a/package-lock.json b/package-lock.json index 00512103a1..1fa46bc42c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,111 @@ "integrity": "sha1-nK+xca+CMpSQNTtIFvAzR6oVCjA=", "dev": true }, + "@babel/code-frame": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.49.tgz", + "integrity": "sha1-vs2AVIJzREDJ0TfkbXc0DmTX9Rs=", + "dev": true, + "requires": { + "@babel/highlight": "7.0.0-beta.49" + } + }, + "@babel/generator": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.49.tgz", + "integrity": "sha1-6c/9qROZaszseTu8JauRvBnQv3o=", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.49", + "lodash": "^4.17.5", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-function-name": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.49.tgz", + "integrity": "sha1-olwRGbnwNSeGcBJuAiXAMEHI3jI=", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "7.0.0-beta.49", + "@babel/template": "7.0.0-beta.49", + "@babel/types": "7.0.0-beta.49" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.49.tgz", + "integrity": "sha1-z1Aj8y0q2S0Ic3STnOwJUby1FEE=", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.49" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.49.tgz", + "integrity": "sha1-QNeO2glo0BGxxShm5XRs+yPldUg=", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.49" + } + }, + "@babel/highlight": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.49.tgz", + "integrity": "sha1-lr3GtD4TSCASumaRsQGEktOWIsw=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, "@babel/parser": { "version": "7.0.0-beta.49", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.0.0-beta.49.tgz", "integrity": "sha1-lE0MW6KBK7FZ7b0iZ0Ov0mUXm9w=", "dev": true }, + "@babel/template": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.49.tgz", + "integrity": "sha1-44q+ghfLl5P0YaUwbXrXRdg+HSc=", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.49", + "@babel/parser": "7.0.0-beta.49", + "@babel/types": "7.0.0-beta.49", + "lodash": "^4.17.5" + } + }, + "@babel/traverse": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.49.tgz", + "integrity": "sha1-TypzaCoYM07WYl0QCo0nMZ98LWg=", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.49", + "@babel/generator": "7.0.0-beta.49", + "@babel/helper-function-name": "7.0.0-beta.49", + "@babel/helper-split-export-declaration": "7.0.0-beta.49", + "@babel/parser": "7.0.0-beta.49", + "@babel/types": "7.0.0-beta.49", + "invariant": "^2.2.0", + "lodash": "^4.17.5" + } + }, + "@babel/types": { + "version": "7.0.0-beta.49", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.49.tgz", + "integrity": "sha1-t+Oxw/TUz+Eb34yJ8e/V4WF7h6Y=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.5", + "to-fast-properties": "^2.0.0" + } + }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -99,6 +198,12 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", "dev": true }, + "amdefine": { + "version": "1.0.1", + "resolved": false, + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, "ansi-escapes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", @@ -108,27 +213,40 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "append-transform": { + "version": "1.0.0", + "resolved": false, + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=" }, + "archy": { + "version": "1.0.0", + "resolved": false, + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, "are-we-there-yet": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.3" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "argparse": { @@ -222,6 +340,12 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, + "async": { + "version": "1.5.2", + "resolved": false, + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -254,168 +378,39 @@ "tmp": "0.0.31" }, "dependencies": { - "browser-stdout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", - "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", - "dev": true - }, - "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true, - "requires": { - "graceful-readlink": "1.0.1" - } - }, "debug": { "version": "2.6.8", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "dev": true, "requires": { "ms": "2.0.0" } }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "etch": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/etch/-/etch-0.8.0.tgz", - "integrity": "sha1-VPYZV0NG+KPueXP1T7vQG1YnItY=", - "dev": true, - "requires": { - "virtual-dom": "2.1.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, "glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "grim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz", - "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==", - "dev": true, "requires": { - "event-kit": "2.5.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, - "growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", - "dev": true - }, "has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "1.1.8" - } - }, - "mocha": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", - "integrity": "sha1-HgSA/jbS2lhY0etqzDhBiybqog0=", - "dev": true, - "requires": { - "browser-stdout": "1.3.0", - "commander": "2.9.0", - "debug": "2.6.8", - "diff": "3.2.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.1", - "growl": "1.9.2", - "he": "1.1.1", - "json3": "3.3.2", - "lodash.create": "3.1.1", - "mkdirp": "0.5.1", - "supports-color": "3.1.2" - }, - "dependencies": { - "diff": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", - "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", - "dev": true - } - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" }, "supports-color": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", - "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true } } }, @@ -437,61 +432,6 @@ "chalk": "^1.1.3", "esutils": "^2.0.2", "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } } }, "babel-core": { @@ -525,8 +465,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-template": { @@ -534,11 +474,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.5" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" } }, "babel-traverse": { @@ -546,15 +486,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" } }, "babel-types": { @@ -562,10 +502,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "babylon": { @@ -585,6 +525,18 @@ } } }, + "babel-eslint": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-7.2.3.tgz", + "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "babel-traverse": "^6.23.1", + "babel-types": "^6.23.0", + "babylon": "^6.17.0" + } + }, "babel-generator": { "version": "6.26.1", "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", @@ -600,21 +552,13 @@ "trim-right": "^1.0.1" }, "dependencies": { - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "requires": { - "babel-runtime": "6.26.0" - } - }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-types": { @@ -622,36 +566,21 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, "to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" } } }, @@ -670,8 +599,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-types": { @@ -679,17 +608,12 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", @@ -732,8 +656,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-types": { @@ -742,10 +666,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "regenerator-runtime": { @@ -766,7 +690,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "dev": true, "requires": { "babel-helper-get-function-arity": "^6.24.1", "babel-runtime": "^6.22.0", @@ -779,7 +702,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "dev": true, "requires": { "babel-runtime": "^6.22.0", "babel-types": "^6.24.1" @@ -880,13 +802,13 @@ "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", "dev": true, "requires": { - "babel-generator": "6.26.1", - "babel-template": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.18.0", - "istanbul-lib-coverage": "1.2.0", - "semver": "5.4.1" + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.0", + "semver": "^5.3.0" } } } @@ -935,29 +857,6 @@ "babel-plugin-syntax-class-properties": "^6.8.0", "babel-runtime": "^6.22.0", "babel-template": "^6.24.1" - }, - "dependencies": { - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "requires": { - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.25.0", - "babel-template": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0" - } - }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "requires": { - "babel-runtime": "6.25.0", - "babel-types": "6.25.0" - } - } } }, "babel-plugin-transform-es2015-arrow-functions": { @@ -997,8 +896,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-template": { @@ -1007,11 +906,11 @@ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.5" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" } }, "babel-traverse": { @@ -1020,15 +919,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" } }, "babel-types": { @@ -1037,10 +936,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "babylon": { @@ -1139,41 +1038,13 @@ "babel-types": "^6.26.0" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "requires": { - "babel-runtime": "6.26.0" - } - }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-template": { @@ -1181,11 +1052,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.5" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" } }, "babel-traverse": { @@ -1193,15 +1064,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" } }, "babel-types": { @@ -1209,10 +1080,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "babylon": { @@ -1220,54 +1091,11 @@ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "2.1.1" - } - }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - }, "to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", @@ -1368,8 +1196,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "regenerator-runtime": { @@ -1441,8 +1269,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" }, "dependencies": { "regenerator-runtime": { @@ -1531,8 +1359,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "regenerator-runtime": { @@ -1547,8 +1375,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.25.0.tgz", "integrity": "sha1-M7mOql1IK7AajRqmtDetKwGuxBw=", "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.10.5" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.10.0" } }, "babel-template": { @@ -1556,11 +1384,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", "requires": { - "babel-runtime": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "lodash": "4.17.5" + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.25.0", + "babel-types": "^6.25.0", + "babylon": "^6.17.2", + "lodash": "^4.2.0" } }, "babel-traverse": { @@ -1568,25 +1396,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" - }, - "dependencies": { - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "requires": { - "babel-runtime": "6.25.0" - } - } + "babel-code-frame": "^6.22.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-types": "^6.25.0", + "babylon": "^6.17.2", + "debug": "^2.2.0", + "globals": "^9.0.0", + "invariant": "^2.2.0", + "lodash": "^4.2.0" } }, "babel-types": { @@ -1594,17 +1412,12 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", "requires": { - "babel-runtime": "6.25.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.22.0", + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^1.0.1" }, "dependencies": { - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, "to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", @@ -1695,38 +1508,23 @@ "safe-buffer": "^5.1.1" }, "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -1734,13 +1532,8 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" } } }, @@ -1750,21 +1543,12 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "dev": true, - "requires": { - "hoek": "4.2.1" - } - }, "brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -1803,6 +1587,12 @@ "integrity": "sha1-ewl1dPjj6tYG+0Zk5krf3aKYGpM=", "dev": true }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, "bser": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", @@ -1817,8 +1607,8 @@ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.1.0.tgz", "integrity": "sha1-BVFNM78WVtNUDGhPZbEgLpDsowM=", "requires": { - "buffer-alloc-unsafe": "0.1.1", - "buffer-fill": "0.1.1" + "buffer-alloc-unsafe": "^0.1.0", + "buffer-fill": "^0.1.0" } }, "buffer-alloc-unsafe": { @@ -1859,9 +1649,20 @@ "unset-value": "^1.0.0" } }, - "call-me-maybe": { + "caching-transform": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "resolved": false, + "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", + "dev": true, + "requires": { + "md5-hex": "^1.2.0", + "mkdirp": "^0.5.1", + "write-file-atomic": "^1.1.4" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", "dev": true }, @@ -1924,7 +1725,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -2038,9 +1838,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -2069,16 +1869,14 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=", - "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "^1.1.1" } }, "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "colors": { "version": "0.5.1", @@ -2094,6 +1892,21 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, + "commondir": { + "version": "1.0.1", + "resolved": false, + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, "compare-sets": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/compare-sets/-/compare-sets-1.0.1.tgz", @@ -2131,6 +1944,11 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.0.tgz", "integrity": "sha1-VpwFCRi+ZIazg3VSAorgRmtxcIY=" }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, "coveralls": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.1.tgz", @@ -2161,8 +1979,8 @@ "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "yallist": { @@ -2179,26 +1997,6 @@ "integrity": "sha1-UYO8R6CVWb78+YzEZXlkmZNZNy8=", "dev": true }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "dev": true, - "requires": { - "boom": "5.2.0" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha1-XdnabuOl8wIHdDYpDLcX0/SlTgI=", - "dev": true, - "requires": { - "hoek": "4.2.1" - } - } - } - }, "css-select": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", @@ -2233,6 +2031,12 @@ "ms": "2.0.0" } }, + "debug-log": { + "version": "1.0.1", + "resolved": false, + "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", + "dev": true + }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -2268,6 +2072,12 @@ "type-detect": "^4.0.0" } }, + "deep-equal": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.1.tgz", + "integrity": "sha1-+tenkyJMvww8d4b5LveA5PyMyHg=", + "dev": true + }, "deep-extend": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", @@ -2279,6 +2089,15 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": false, + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, "define-properties": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", @@ -2355,6 +2174,12 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, "detect-indent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", @@ -2386,16 +2211,10 @@ "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" }, "dependencies": { - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -2440,7 +2259,7 @@ "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", "dev": true, "requires": { - "domelementtype": "1.3.0" + "domelementtype": "1" } }, "domutils": { @@ -2458,12 +2277,12 @@ "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.66.0.tgz", "integrity": "sha1-X9q2aDwLU4p5vb7Emenz0+pyEPk=", "requires": { - "checksum": "0.1.1", - "mkdirp": "0.5.1", - "progress": "2.0.0", - "request": "2.87.0", - "rimraf": "2.6.2", - "tar": "4.4.4" + "checksum": "^0.1.1", + "mkdirp": "^0.5.1", + "progress": "^2.0.0", + "request": "^2.86.0", + "rimraf": "^2.5.4", + "tar": "^4.0.2" } }, "ecc-jsbn": { @@ -2487,35 +2306,12 @@ "semver": "^5.3.0" } }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "requires": { - "iconv-lite": "~0.4.13" - } - }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", "requires": { "once": "^1.4.0" - }, - "dependencies": { - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - } } }, "entities": { @@ -2555,7 +2351,7 @@ "dev": true, "optional": true, "requires": { - "prr": "0.0.0" + "prr": "~0.0.0" } }, "error": { @@ -2575,7 +2371,7 @@ "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, "es-abstract": { @@ -2584,19 +2380,11 @@ "integrity": "sha1-zOh9UY8Elok7GjDNhGGDVTVIBoE=", "dev": true, "requires": { - "es-to-primitive": "1.1.1", - "function-bind": "1.1.1", - "has": "1.0.1", - "is-callable": "1.1.3", - "is-regex": "1.0.4" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", - "dev": true - } + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" } }, "es-to-primitive": { @@ -2613,8 +2401,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { "version": "5.0.1", @@ -2731,16 +2518,6 @@ "esutils": "^2.0.2" } }, - "eslint-scope": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -2798,126 +2575,21 @@ "eslint-plugin-prefer-object-spread": "^1.1.0", "eslint-plugin-react": "^6.9.0", "fbjs-eslint-utils": "^1.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - } - }, - "babel-eslint": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-7.2.3.tgz", - "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=", - "dev": true, - "requires": { - "babel-code-frame": "^6.22.0", - "babel-traverse": "^6.23.1", - "babel-types": "^6.23.0", - "babylon": "^6.17.0" - } - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint-plugin-babel": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-4.1.2.tgz", - "integrity": "sha1-eSAqDjV1fdkngJGbIzbx+i/lPB4=", - "dev": true - }, - "eslint-plugin-react": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz", - "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", - "dev": true, - "requires": { - "array.prototype.find": "2.0.4", - "doctrine": "1.5.0", - "has": "1.0.1", - "jsx-ast-utils": "1.4.1", - "object.assign": "4.1.0" - } - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "jsx-ast-utils": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", - "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } } }, + "eslint-plugin-babel": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-4.1.2.tgz", + "integrity": "sha1-eSAqDjV1fdkngJGbIzbx+i/lPB4=", + "dev": true + }, "eslint-plugin-flowtype": { "version": "2.46.3", "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.46.3.tgz", "integrity": "sha1-foQTHYfvGLSWsYEESFkzdIYLTo4=", "dev": true, "requires": { - "lodash": "4.17.5" + "lodash": "^4.15.0" } }, "eslint-plugin-jasmine": { @@ -2932,6 +2604,29 @@ "integrity": "sha1-J/uRhTaQzOs65hAdnIrsxqZ6QCw=", "dev": true }, + "eslint-plugin-react": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz", + "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", + "dev": true, + "requires": { + "array.prototype.find": "^2.0.1", + "doctrine": "^1.2.2", + "has": "^1.0.1", + "jsx-ast-utils": "^1.3.4", + "object.assign": "^4.0.4" + } + }, + "eslint-scope": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -2983,6 +2678,15 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "etch": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/etch/-/etch-0.8.0.tgz", + "integrity": "sha1-VPYZV0NG+KPueXP1T7vQG1YnItY=", + "dev": true, + "requires": { + "virtual-dom": "^2.0.1" + } + }, "ev-store": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/ev-store/-/ev-store-7.0.0.tgz", @@ -3175,6 +2879,19 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" }, + "fast-glob": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.1.tgz", + "integrity": "sha512-wSyW1TBK3ia5V+te0rGPXudeMHoUQW6O5Y9oATiaGhpENmEifPDlOdhpsnlj5HoG6ttIvGiY1DdCmI9X2xGMhg==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.1", + "micromatch": "^3.1.10" + } + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -3200,13 +2917,13 @@ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", "requires": { - "core-js": "1.2.7", - "isomorphic-fetch": "2.2.1", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "promise": "7.3.1", - "setimmediate": "1.0.5", - "ua-parser-js": "0.7.14" + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.9" }, "dependencies": { "core-js": { @@ -3214,46 +2931,14 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "requires": { - "node-fetch": "1.7.3", - "whatwg-fetch": "2.0.4" - } - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "3.0.2" - } - }, "node-fetch": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" + "encoding": "^0.1.11", + "is-stream": "^1.0.1" } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" } } }, @@ -3305,6 +2990,17 @@ } } }, + "find-cache-dir": { + "version": "1.0.0", + "resolved": false, + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" + } + }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -3338,6 +3034,15 @@ "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", "dev": true }, + "foreground-child": { + "version": "1.5.6", + "resolved": false, + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "dev": true, + "requires": { + "signal-exit": "^3.0.0" + } + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -3385,6 +3090,11 @@ "minipass": "^2.2.1" } }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -3400,14 +3110,6 @@ "define-properties": "^1.1.2", "function-bind": "^1.1.1", "is-callable": "^1.1.3" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", - "dev": true - } } }, "functional-red-black-tree": { @@ -3431,32 +3133,14 @@ "wide-align": "^1.1.0" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "2.1.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -3509,53 +3193,6 @@ "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" - }, - "dependencies": { - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "1.1.8" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - } } }, "glob-parent": { @@ -3644,6 +3281,43 @@ "immutable": "~3.7.6" } }, + "grim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz", + "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==", + "dev": true, + "requires": { + "event-kit": "^2.0.0" + } + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "handlebars": { + "version": "4.0.11", + "resolved": false, + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "dev": true, + "requires": { + "async": "^1.4.0", + "source-map": "^0.4.4", + "uglify-js": "^2.6" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": false, + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -3664,22 +3338,13 @@ "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", "dev": true, "requires": { - "function-bind": "1.1.1" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - } + "function-bind": "^1.0.2" } }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3687,8 +3352,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { "version": "1.0.0", @@ -3733,18 +3397,6 @@ } } }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha1-r02RTrBl+bXOTZ0RwcshJu7MMDg=", - "dev": true, - "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.1", - "sntp": "2.1.0" - } - }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", @@ -3758,22 +3410,8 @@ "dev": true, "requires": { "deep-equal": "0.2.1" - }, - "dependencies": { - "deep-equal": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.1.tgz", - "integrity": "sha1-+tenkyJMvww8d4b5LveA5PyMyHg=", - "dev": true - } } }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha1-ljRQKqEsRF3Vp8VzS1cruHOKrLs=", - "dev": true - }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -3801,14 +3439,6 @@ "entities": "^1.1.1", "inherits": "^2.0.1", "readable-stream": "^2.0.2" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } } }, "http-signature": { @@ -3824,7 +3454,8 @@ "iconv-lite": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" + "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==", + "dev": true }, "ignore": { "version": "3.3.10", @@ -3857,9 +3488,23 @@ "integrity": "sha1-58pPhfiVewGHNPKFdQ3CLsL5hi0=", "dev": true }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=" }, "inquirer": { @@ -3935,16 +3580,6 @@ "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", "requires": { "loose-envify": "^1.0.0" - }, - "dependencies": { - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "3.0.2" - } - } } }, "invert-kv": { @@ -3988,8 +3623,7 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", - "dev": true + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=" }, "is-builtin-module": { "version": "1.0.0", @@ -4069,13 +3703,6 @@ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "requires": { "number-is-nan": "^1.0.0" - }, - "dependencies": { - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - } } }, "is-fullwidth-code-point": { @@ -4084,13 +3711,6 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "^1.0.0" - }, - "dependencies": { - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - } } }, "is-glob": { @@ -4179,7 +3799,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", - "dev": true, "requires": { "isobject": "^3.0.1" } @@ -4208,8 +3827,7 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-string": { "version": "1.0.4", @@ -4255,14 +3873,20 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "whatwg-fetch": ">=0.10.0" + } }, "isstream": { "version": "0.1.2", @@ -4275,6 +3899,15 @@ "integrity": "sha512-yMSw5xLIbdaxiVXHk3amfNM2WeBxLrwH/BCyZ9HvA/fylwziAIJOG2rKqWyLqEJqwKT725vxxqidv+SyynnGAA==", "dev": true }, + "istanbul-lib-hook": { + "version": "2.0.0", + "resolved": false, + "integrity": "sha512-qm3dt628HKpCVtIjbdZLuQyXn0+LO8qz+YHQDfkeXuSk5D+p299SEV5DrnUUnPi2SXvdMmWapMYWiuE75o2rUQ==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, "istanbul-lib-instrument": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-2.2.0.tgz", @@ -4286,138 +3919,32 @@ "@babel/template": "7.0.0-beta.49", "@babel/traverse": "7.0.0-beta.49", "@babel/types": "7.0.0-beta.49", - "istanbul-lib-coverage": "2.0.0", - "semver": "5.5.0" + "istanbul-lib-coverage": "^2.0.0", + "semver": "^5.5.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.49.tgz", - "integrity": "sha1-vs2AVIJzREDJ0TfkbXc0DmTX9Rs=", - "dev": true, - "requires": { - "@babel/highlight": "7.0.0-beta.49" - } - }, - "@babel/generator": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.49.tgz", - "integrity": "sha1-6c/9qROZaszseTu8JauRvBnQv3o=", - "dev": true, - "requires": { - "@babel/types": "7.0.0-beta.49", - "jsesc": "2.5.1", - "lodash": "4.17.5", - "source-map": "0.5.7", - "trim-right": "1.0.1" - } - }, - "@babel/helper-function-name": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.49.tgz", - "integrity": "sha1-olwRGbnwNSeGcBJuAiXAMEHI3jI=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "7.0.0-beta.49", - "@babel/template": "7.0.0-beta.49", - "@babel/types": "7.0.0-beta.49" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.49.tgz", - "integrity": "sha1-z1Aj8y0q2S0Ic3STnOwJUby1FEE=", - "dev": true, - "requires": { - "@babel/types": "7.0.0-beta.49" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.49.tgz", - "integrity": "sha1-QNeO2glo0BGxxShm5XRs+yPldUg=", - "dev": true, - "requires": { - "@babel/types": "7.0.0-beta.49" - } - }, - "@babel/highlight": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.49.tgz", - "integrity": "sha1-lr3GtD4TSCASumaRsQGEktOWIsw=", - "dev": true, - "requires": { - "chalk": "2.4.1", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - } - }, - "@babel/template": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.49.tgz", - "integrity": "sha1-44q+ghfLl5P0YaUwbXrXRdg+HSc=", - "dev": true, - "requires": { - "@babel/code-frame": "7.0.0-beta.49", - "@babel/parser": "7.0.0-beta.49", - "@babel/types": "7.0.0-beta.49", - "lodash": "4.17.5" - } - }, - "@babel/traverse": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.49.tgz", - "integrity": "sha1-TypzaCoYM07WYl0QCo0nMZ98LWg=", - "dev": true, - "requires": { - "@babel/code-frame": "7.0.0-beta.49", - "@babel/generator": "7.0.0-beta.49", - "@babel/helper-function-name": "7.0.0-beta.49", - "@babel/helper-split-export-declaration": "7.0.0-beta.49", - "@babel/parser": "7.0.0-beta.49", - "@babel/types": "7.0.0-beta.49", - "debug": "3.1.0", - "globals": "11.7.0", - "invariant": "2.2.4", - "lodash": "4.17.5" - } - }, - "@babel/types": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.49.tgz", - "integrity": "sha1-t+Oxw/TUz+Eb34yJ8e/V4WF7h6Y=", - "dev": true, - "requires": { - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "2.0.0" - } - }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -4425,14 +3952,12 @@ "globals": { "version": "11.7.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", - "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", - "dev": true + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==" }, "jsesc": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", - "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", - "dev": true + "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=" }, "semver": { "version": "5.5.0", @@ -4444,13 +3969,51 @@ "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } }, + "istanbul-lib-report": { + "version": "2.0.0", + "resolved": false, + "integrity": "sha512-RiELmy9oIRYUv36ITOAhVum9PUvuj6bjyXVEKEHNiD1me6qXtxfx7vSEJWnjOGk2QmYw/GRFjLXWJv3qHpLceQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.0", + "make-dir": "^1.3.0" + } + }, + "istanbul-lib-source-maps": { + "version": "2.0.0", + "resolved": false, + "integrity": "sha512-jenUeC0gMSSMGkvqD9xuNfs3nD7XWeXLhqaIkqHsNZ3DJBWPdlKEydE7Ya5aTgdWjrEQhrCYTv+J606cGC2vuQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.0", + "make-dir": "^1.3.0", + "rimraf": "^2.6.2", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": false, + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "1.5.0", + "resolved": false, + "integrity": "sha512-HeZG0WHretI9FXBni5wZ9DOgNziqDCEwetxnme5k1Vv5e81uTqcsy3fMH99gXGDGKr1ea87TyGseDMa2h4HEUA==", + "dev": true, + "requires": { + "handlebars": "^4.0.11" + } + }, "iterall": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", @@ -4491,8 +4054,8 @@ "integrity": "sha1-WXwai9VxUvJtYizkEXhRpR9euu8=", "dev": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "jsbn": { @@ -4506,6 +4069,12 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": false, + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -4516,6 +4085,16 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "optional": true, + "requires": { + "jsonify": "~0.0.0" + } + }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -4546,6 +4125,13 @@ "graceful-fs": "^4.1.6" } }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true, + "optional": true + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -4555,15 +4141,14 @@ "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } } }, + "jsx-ast-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", + "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", + "dev": true + }, "just-extend": { "version": "1.1.27", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", @@ -4641,21 +4226,13 @@ "dev": true, "optional": true }, - "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", - "dev": true, - "optional": true - }, "boom": { "version": "2.10.1", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, - "optional": true, "requires": { - "hoek": "2.16.3" + "hoek": "2.x.x" } }, "combined-stream": { @@ -4672,23 +4249,9 @@ "dev": true, "optional": true, "requires": { - "boom": "2.10.1" + "boom": "2.x.x" } }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true, - "optional": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "optional": true - }, "form-data": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", @@ -4708,18 +4271,11 @@ "dev": true, "optional": true, "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } } } }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true, - "optional": true - }, "har-schema": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", @@ -4745,18 +4301,17 @@ "dev": true, "optional": true, "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" } }, "hoek": { "version": "2.16.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true, - "optional": true + "dev": true }, "http-signature": { "version": "1.1.1", @@ -4770,58 +4325,6 @@ "sshpk": "^1.7.0" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true, - "optional": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true, - "optional": true - }, - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true, - "optional": true - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true, - "optional": true - }, "performance-now": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", @@ -4874,7 +4377,7 @@ "dev": true, "optional": true, "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "tough-cookie": { @@ -4884,7 +4387,7 @@ "dev": true, "optional": true, "requires": { - "punycode": "1.4.1" + "punycode": "^1.4.1" } } } @@ -4896,16 +4399,9 @@ "dev": true, "optional": true, "requires": { - "hoek": "2.16.3" + "hoek": "2.x.x" } }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "optional": true - }, "tough-cookie": { "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", "integrity": "sha512-42UXjmzk88F7URyg9wDV/dlQ7hXtl/SDV6xIMVdDq82cnDGQDyg8mI8xGBPOwpEfbhvrja6cJ8H1wr0xxykBKA==", @@ -4931,10 +4427,10 @@ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" } }, "locate-path": { @@ -5074,6 +4570,23 @@ "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", "dev": true }, + "make-dir": { + "version": "1.3.0", + "resolved": false, + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": false, + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -5089,6 +4602,21 @@ "object-visit": "^1.0.0" } }, + "md5-hex": { + "version": "1.3.0", + "resolved": false, + "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", + "dev": true, + "requires": { + "md5-o-matic": "^0.1.1" + } + }, + "md5-o-matic": { + "version": "0.1.1", + "resolved": false, + "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", + "dev": true + }, "mem": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", @@ -5098,6 +4626,23 @@ "mimic-fn": "^1.0.0" } }, + "merge-source-map": { + "version": "1.1.0", + "resolved": false, + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": false, + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "merge2": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.1.tgz", @@ -5125,6 +4670,13 @@ "to-regex": "^3.0.2" } }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true, + "optional": true + }, "mime-db": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz", @@ -5135,7 +4687,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=", "requires": { - "mime-db": "1.29.0" + "mime-db": "~1.29.0" } }, "mimic-fn": { @@ -5231,6 +4783,31 @@ } } }, + "mocha": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", + "integrity": "sha1-HgSA/jbS2lhY0etqzDhBiybqog0=", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "growl": "1.9.2", + "he": "1.1.1", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1" + }, + "dependencies": { + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + } + } + }, "mocha-appveyor-reporter": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/mocha-appveyor-reporter/-/mocha-appveyor-reporter-0.4.0.tgz", @@ -5240,108 +4817,47 @@ "request-json": "^0.6.1" }, "dependencies": { - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", - "dev": true + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" }, "mime-types": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "dev": true, "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.33.0" } }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true - }, "request": { "version": "2.83.0", "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", - "dev": true, "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.7.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.18", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" - } - }, - "request-json": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/request-json/-/request-json-0.6.3.tgz", - "integrity": "sha512-5TVnMD3LaeK0GRCyFlsNgJf5Fjg8J8j7VEfsoJESSWZlWRgPIf7IojsBLbTHcg2798JrrRkJ6L3k1+wj4sglgw==", - "dev": true, - "requires": { - "depd": "1.1.2", - "request": "2.83.0" + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "hawk": "~6.0.2", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "stringstream": "~0.0.5", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" } - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", - "dev": true } } }, @@ -5363,15 +4879,6 @@ "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", "dev": true }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, "diff": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", @@ -5394,18 +4901,6 @@ "minimatch": "0.3" } }, - "growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", - "dev": true - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, "minimatch": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", @@ -5506,23 +5001,12 @@ "to-regex": "^3.0.1" }, "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" - } - }, "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -5575,7 +5059,7 @@ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.0.tgz", "integrity": "sha1-PCdRXLhC9bvBMqMSVPnx4cVce4M=", "requires": { - "semver": "5.4.1" + "semver": "^5.4.1" } }, "node-emoji": { @@ -5654,6 +5138,11 @@ "boolbase": "~1.0.0" } }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, "nyc": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-13.0.0.tgz", @@ -5687,109 +5176,21 @@ "yargs-parser": "^9.0.2" }, "dependencies": { - "align-text": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - } - }, - "amdefine": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, "ansi-regex": { "version": "3.0.0", - "bundled": true, - "dev": true - }, - "append-transform": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "default-require-extensions": "^2.0.0" - } - }, - "archy": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "arrify": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "async": { - "version": "1.5.2", - "bundled": true, - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "builtin-modules": { - "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, - "caching-transform": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "md5-hex": "^1.2.0", - "mkdirp": "^0.5.1", - "write-file-atomic": "^1.1.4" - }, - "dependencies": { - "md5-hex": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "md5-o-matic": "^0.1.1" - } - } - } - }, "camelcase": { "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true - }, - "center-align": { - "version": "0.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } + "resolved": false, + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" }, "cliui": { "version": "2.1.0", - "bundled": true, - "dev": true, - "optional": true, + "resolved": false, + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "requires": { "center-align": "^0.1.1", "right-align": "^0.1.1", @@ -5798,36 +5199,15 @@ "dependencies": { "wordwrap": { "version": "0.0.2", - "bundled": true, - "dev": true, - "optional": true + "resolved": false, + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" } } }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "commondir": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "convert-source-map": { - "version": "1.5.1", - "bundled": true, - "dev": true - }, "cross-spawn": { "version": "4.0.2", - "bundled": true, - "dev": true, + "resolved": false, + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", "requires": { "lru-cache": "^4.0.1", "which": "^1.2.9" @@ -5835,663 +5215,89 @@ }, "debug": { "version": "3.1.0", - "bundled": true, - "dev": true, + "resolved": false, + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { "ms": "2.0.0" } }, - "debug-log": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "decamelize": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "default-require-extensions": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "strip-bom": "^3.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "bundled": true, - "dev": true - } - } - }, - "error-ex": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "execa": { - "version": "0.7.0", - "bundled": true, - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - } - } - }, - "find-cache-dir": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "foreground-child": { - "version": "1.5.6", - "bundled": true, - "dev": true, - "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "get-caller-file": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "handlebars": { - "version": "4.0.11", - "bundled": true, - "dev": true, - "requires": { - "async": "^1.4.0", - "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" - }, - "dependencies": { - "source-map": { - "version": "0.4.4", - "bundled": true, - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "hosted-git-info": { - "version": "2.6.0", - "bundled": true, - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true, - "dev": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "invert-kv": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "bundled": true, - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, "is-fullwidth-code-point": { "version": "2.0.0", - "bundled": true, - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "istanbul-lib-coverage": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "istanbul-lib-hook": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "append-transform": "^1.0.0" - } - }, - "istanbul-lib-report": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.0", - "make-dir": "^1.3.0", - "supports-color": "^5.4.0" - } - }, - "istanbul-lib-source-maps": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^2.0.0", - "make-dir": "^1.3.0", - "rimraf": "^2.6.2", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "bundled": true, - "dev": true - } - } - }, - "istanbul-reports": { - "version": "1.5.0", - "bundled": true, - "dev": true, - "requires": { - "handlebars": "^4.0.11" - } - }, - "json-parse-better-errors": { - "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "kind-of": { "version": "3.2.2", - "bundled": true, - "dev": true, + "resolved": false, + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { "is-buffer": "^1.1.5" } }, - "lazy-cache": { - "version": "1.0.4", - "bundled": true, - "dev": true, - "optional": true - }, - "lcid": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "bundled": true, - "dev": true - } - } - }, - "longest": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, "lru-cache": { "version": "4.1.3", - "bundled": true, - "dev": true, + "resolved": false, + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" } }, - "make-dir": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "bundled": true, - "dev": true - } - } - }, "md5-hex": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM=", "dev": true, "requires": { "md5-o-matic": "^0.1.1" } }, - "md5-o-matic": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "mem": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "merge-source-map": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "bundled": true, - "dev": true - } - } - }, - "mimic-fn": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, "minimist": { "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "normalize-package-data": { - "version": "2.4.0", - "bundled": true, - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } + "resolved": false, + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "optimist": { "version": "0.6.1", - "bundled": true, - "dev": true, + "resolved": false, + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" } }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "os-locale": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "p-finally": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "p-limit": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "path-key": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "bundled": true, - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, "resolve-from": { "version": "4.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, - "right-align": { - "version": "0.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.1" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "dev": true, - "requires": { - "glob": "^7.0.5" - } - }, "semver": { "version": "5.5.0", - "bundled": true, - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "slide": { - "version": "1.1.6", - "bundled": true, - "dev": true - }, - "source-map": { - "version": "0.5.7", - "bundled": true, - "dev": true, - "optional": true - }, - "spawn-wrap": { - "version": "1.4.2", - "bundled": true, - "dev": true, - "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - } - }, - "spdx-correct": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "bundled": true, - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } + "resolved": false, + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" }, "strip-ansi": { "version": "4.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { "ansi-regex": "^3.0.0" } }, - "strip-eof": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, "supports-color": { "version": "5.4.0", - "bundled": true, - "dev": true, + "resolved": false, + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "requires": { "has-flag": "^3.0.0" } }, "test-exclude": { "version": "4.2.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-2kTGf+3tykCfrWVREgyTR0bmVO0afE6i7zVXi/m+bZZ8ujV89Aulxdcdv32yH+unVFg3Y5o6GA8IzsHnGQuFgQ==", "dev": true, "requires": { "arrify": "^1.0.1", @@ -6502,7 +5308,8 @@ "dependencies": { "load-json-file": { "version": "4.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -6513,186 +5320,67 @@ }, "parse-json": { "version": "4.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" } }, - "path-type": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "bundled": true, - "dev": true - } - } - }, - "uglify-js": { - "version": "2.8.29", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "yargs": { - "version": "3.10.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "validate-npm-package-license": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "which": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "window-size": { - "version": "0.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "wordwrap": { - "version": "0.0.3", - "bundled": true, - "dev": true - }, - "wrap-ansi": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, + "path-type": { + "version": "3.0.0", + "resolved": false, + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "pify": "^3.0.0" } }, - "string-width": { - "version": "1.0.2", - "bundled": true, + "pify": { + "version": "3.0.0", + "resolved": false, + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": false, + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" } }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, + "read-pkg-up": { + "version": "3.0.0", + "resolved": false, + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": false, + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true } } }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "write-file-atomic": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } - }, - "y18n": { - "version": "3.2.1", - "bundled": true, - "dev": true - }, "yallist": { "version": "2.1.2", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, "yargs": { "version": "11.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "dev": true, "requires": { "cliui": "^4.0.0", @@ -6711,12 +5399,14 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true }, "cliui": { "version": "4.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { "string-width": "^2.1.1", @@ -6726,7 +5416,8 @@ }, "yargs-parser": { "version": "9.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { "camelcase": "^4.1.0" @@ -6736,7 +5427,8 @@ }, "yargs-parser": { "version": "9.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { "camelcase": "^4.1.0" @@ -6744,7 +5436,8 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true } } @@ -6829,14 +5522,6 @@ "function-bind": "^1.1.1", "has-symbols": "^1.0.0", "object-keys": "^1.0.11" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", - "dev": true - } } }, "object.entries": { @@ -6849,14 +5534,6 @@ "es-abstract": "^1.6.1", "function-bind": "^1.1.0", "has": "^1.0.1" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - } } }, "object.pick": { @@ -6878,14 +5555,14 @@ "es-abstract": "^1.6.1", "function-bind": "^1.1.0", "has": "^1.0.1" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - } + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" } }, "onetime": { @@ -6960,7 +5637,7 @@ "integrity": "sha1-DpK2vty1nwIsE9DxlJ3ILRWQnxw=", "dev": true, "requires": { - "p-try": "1.0.0" + "p-try": "^1.0.0" } }, "p-locate": { @@ -7046,7 +5723,7 @@ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { - "pify": "2.3.0" + "pify": "^2.0.0" } }, "pathval": { @@ -7081,6 +5758,15 @@ "pinkie": "^2.0.0" } }, + "pkg-dir": { + "version": "2.0.0", + "resolved": false, + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", @@ -7113,13 +5799,6 @@ "tar-fs": "^1.13.0", "tunnel-agent": "^0.6.0", "which-pm-runs": "^1.0.0" - }, - "dependencies": { - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - } } }, "prelude-ls": { @@ -7139,6 +5818,11 @@ "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=", "dev": true }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, "progress": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", @@ -7171,8 +5855,7 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "pump": { "version": "2.0.1", @@ -7181,21 +5864,6 @@ "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" - }, - "dependencies": { - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - } } }, "punycode": { @@ -7238,10 +5906,10 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz", "integrity": "sha1-ihDKMNWI0ARkNgNyuJDQbazQIpc=", "requires": { - "deep-extend": "0.5.1", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" } }, "react": { @@ -7279,70 +5947,14 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" }, - "fbjs": { - "version": "0.8.16", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", - "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", - "requires": { - "core-js": "1.2.7", - "isomorphic-fetch": "2.2.1", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "promise": "7.3.1", - "setimmediate": "1.0.5", - "ua-parser-js": "0.7.14" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "requires": { - "node-fetch": "1.7.3", - "whatwg-fetch": "2.0.4" - } - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "3.0.2" - } - }, "node-fetch": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "prop-types": { - "version": "15.6.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", - "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", - "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1" + "encoding": "^0.1.11", + "is-stream": "^1.0.1" } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" } } }, @@ -7390,70 +6002,14 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" }, - "fbjs": { - "version": "0.8.16", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", - "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", - "requires": { - "core-js": "1.2.7", - "isomorphic-fetch": "2.2.1", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "promise": "7.3.1", - "setimmediate": "1.0.5", - "ua-parser-js": "0.7.14" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "requires": { - "node-fetch": "1.7.3", - "whatwg-fetch": "2.0.4" - } - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "3.0.2" - } - }, "node-fetch": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "prop-types": { - "version": "15.6.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", - "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", - "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1" + "encoding": "^0.1.11", + "is-stream": "^1.0.1" } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" } } }, @@ -7467,19 +6023,6 @@ "object-assign": "^4.1.1", "prop-types": "^15.6.0", "react-is": "^16.4.1" - }, - "dependencies": { - "prop-types": { - "version": "15.6.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", - "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", - "dev": true, - "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1" - } - } } }, "read-pkg": { @@ -7488,9 +6031,9 @@ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" } }, "read-pkg-up": { @@ -7499,8 +6042,8 @@ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" } }, "readable-stream": { @@ -7508,25 +6051,15 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" }, "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -7536,11 +6069,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" } } }, @@ -7559,23 +6087,12 @@ "safe-regex": "^1.1.0" }, "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" - } - }, "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -7649,15 +6166,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" }, "dependencies": { "babel-runtime": { @@ -7666,8 +6183,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babylon": { @@ -7684,10 +6201,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" }, "dependencies": { "babel-runtime": { @@ -7696,8 +6213,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.0", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "to-fast-properties": { @@ -7714,19 +6231,6 @@ "integrity": "sha1-kfyM1W1euYso5v3kEEXylXd5lAo=", "dev": true }, - "fast-glob": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.1.tgz", - "integrity": "sha512-wSyW1TBK3ia5V+te0rGPXudeMHoUQW6O5Y9oATiaGhpENmEifPDlOdhpsnlj5HoG6ttIvGiY1DdCmI9X2xGMhg==", - "dev": true, - "requires": { - "@mrmlnc/readdir-enhanced": "2.2.1", - "glob-parent": "3.1.0", - "is-glob": "4.0.0", - "merge2": "1.2.1", - "micromatch": "3.1.10" - } - }, "jsesc": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", @@ -7807,11 +6311,20 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha1-bzI/YKg9ERRvgx/xH9ZuL+VQO7g=", "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.33.0" } } } }, + "request-json": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/request-json/-/request-json-0.6.3.tgz", + "integrity": "sha512-5TVnMD3LaeK0GRCyFlsNgJf5Fjg8J8j7VEfsoJESSWZlWRgPIf7IojsBLbTHcg2798JrrRkJ6L3k1+wj4sglgw==", + "dev": true, + "requires": { + "depd": "1.1.2" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7951,6 +6464,11 @@ } } }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -7996,21 +6514,6 @@ "decompress-response": "^3.3.0", "once": "^1.3.1", "simple-concat": "^1.0.0" - }, - "dependencies": { - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - } } }, "sinon": { @@ -8061,6 +6564,12 @@ } } }, + "slide": { + "version": "1.1.6", + "resolved": false, + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "dev": true + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -8168,15 +6677,6 @@ } } }, - "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha1-LGzsFP7cIiJznK+bXD2F0cxaLMg=", - "dev": true, - "requires": { - "hoek": "4.2.1" - } - }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -8188,11 +6688,11 @@ "integrity": "sha1-etD1k/IoFZjoVN+A8ZquS5LXoRo=", "dev": true, "requires": { - "atob": "2.1.1", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.0", - "urix": "0.1.0" + "atob": "^2.0.0", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-support": { @@ -8209,6 +6709,20 @@ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, + "spawn-wrap": { + "version": "1.4.2", + "resolved": false, + "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", + "dev": true, + "requires": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } + }, "spdx-correct": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", @@ -8247,13 +6761,6 @@ "integrity": "sha1-YFvZvjA6pZ+zX5Ip++oN3snqB9k=", "requires": { "through": "2" - }, - "dependencies": { - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - } } }, "split-string": { @@ -8265,23 +6772,12 @@ "extend-shallow": "^3.0.0" }, "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" - } - }, "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -8297,14 +6793,14 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" } }, "static-extend": { @@ -8340,35 +6836,29 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" }, "dependencies": { "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - } + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -8391,21 +6881,18 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "stringstream": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", - "integrity": "sha1-eIAiWw1K0Q4wkn0Weh1vL9OzOnI=", - "dev": true, - "optional": true + "integrity": "sha1-eIAiWw1K0Q4wkn0Weh1vL9OzOnI=" }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -8430,8 +6917,7 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, "symbol-observable": { "version": "1.0.1", @@ -8534,33 +7020,20 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.2.tgz", "integrity": "sha1-F+Ujl0fjmffnc0T19TNl8Er1NXc=", "requires": { - "chownr": "1.0.1", - "mkdirp": "0.5.1", - "pump": "1.0.3", - "tar-stream": "1.6.0" + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" }, "dependencies": { - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - } - }, "pump": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", "integrity": "sha1-Xf6DEcM7v2/BgmH580cCxHwIqVQ=", "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" } } }, @@ -8569,13 +7042,13 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.0.tgz", "integrity": "sha1-pQ76p7F3YLgsJ7PK5KMBqCVKVxU=", "requires": { - "bl": "1.2.2", - "buffer-alloc": "1.1.0", - "end-of-stream": "1.4.1", - "fs-constants": "1.0.0", - "readable-stream": "2.3.3", - "to-buffer": "1.1.1", - "xtend": "4.0.1" + "bl": "^1.0.0", + "buffer-alloc": "^1.1.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.0.0", + "to-buffer": "^1.1.0", + "xtend": "^4.0.0" } }, "temp": { @@ -8587,11 +7060,6 @@ "rimraf": "~2.2.6" }, "dependencies": { - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, "rimraf": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", @@ -8618,8 +7086,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "load-json-file": { @@ -8628,11 +7096,11 @@ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" } }, "path-exists": { @@ -8641,7 +7109,7 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } }, "path-type": { @@ -8650,9 +7118,9 @@ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "read-pkg": { @@ -8661,9 +7129,9 @@ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" } }, "read-pkg-up": { @@ -8672,8 +7140,8 @@ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" } }, "strip-bom": { @@ -8682,7 +7150,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } } } @@ -8708,8 +7176,7 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "tinycolor2": { "version": "1.4.1", @@ -8723,14 +7190,6 @@ "dev": true, "requires": { "os-tmpdir": "~1.0.1" - }, - "dependencies": { - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - } } }, "to-buffer": { @@ -8782,23 +7241,12 @@ "safe-regex": "^1.1.0" }, "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" - } - }, "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -8829,8 +7277,7 @@ "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" }, "tunnel-agent": { "version": "0.6.0", @@ -8866,6 +7313,38 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.14.tgz", "integrity": "sha1-EQ1T+kw/MmwSEpK76skE0uAzh8o=" }, + "uglify-js": { + "version": "2.8.29", + "resolved": false, + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "optional": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "resolved": false, + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": false, + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, "underscore": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", @@ -8990,6 +7469,11 @@ "kind-of": "^6.0.2" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, "uuid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", @@ -9013,18 +7497,6 @@ "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - } } }, "virtual-dom": { @@ -9065,9 +7537,8 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", - "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "which-module": { @@ -9086,34 +7557,28 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", "integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=", "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "2.1.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } }, + "window-size": { + "version": "0.1.0", + "resolved": false, + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true, + "optional": true + }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", @@ -9135,13 +7600,18 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, "write": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", @@ -9151,6 +7621,17 @@ "mkdirp": "^0.5.1" } }, + "write-file-atomic": { + "version": "1.3.4", + "resolved": false, + "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + }, "x-is-array": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/x-is-array/-/x-is-array-0.1.0.tgz", From d4e281d051d0771a2a21a05455cd0590c7fcf97b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 16 Jul 2018 09:04:23 -0400 Subject: [PATCH 0561/4847] Use the buildURI method in issueish-link --- lib/views/issueish-link.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/views/issueish-link.js b/lib/views/issueish-link.js index 8b6eeaab83..149e95f19a 100644 --- a/lib/views/issueish-link.js +++ b/lib/views/issueish-link.js @@ -59,12 +59,7 @@ function getUriForData({hostname, repoOwner, repoName, type, issueishNumber}) { if (hostname !== 'github.com' || !['pull', 'issues'].includes(type) || !issueishNumber || isNaN(issueishNumber)) { return null; } else { - return url.format({ - slashes: true, - protocol: 'atom-github:', - hostname: 'issueish', - pathname: `/https://api.github.com/${repoOwner}/${repoName}/${issueishNumber}`, - }); + return IssueishPaneItem.buildURI('https://api.github.com', repoOwner, repoName, issueishNumber); } } From 7e76b6b425e6c33b6bfdf77c6911fdbfbb98046d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 16 Jul 2018 09:24:59 -0400 Subject: [PATCH 0562/4847] Preserve GithubDotcomMarkdown's display name --- lib/views/github-dotcom-markdown.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/views/github-dotcom-markdown.js b/lib/views/github-dotcom-markdown.js index c4b6bd78c2..3bed9b6a67 100644 --- a/lib/views/github-dotcom-markdown.js +++ b/lib/views/github-dotcom-markdown.js @@ -114,8 +114,12 @@ export class BareGithubDotcomMarkdown extends React.Component { } } -export default props => ( - - {relayEnvironment => } - -); +export default class GithubDotcomMarkdown { + render() { + return ( + + {relayEnvironment => } + + ); + } +} From 6fe9069e09354141e9acf4b68d1f4b4fbac7a77f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 16 Jul 2018 09:26:00 -0400 Subject: [PATCH 0563/4847] Oops --- lib/views/github-dotcom-markdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/github-dotcom-markdown.js b/lib/views/github-dotcom-markdown.js index 3bed9b6a67..07a32ac7a5 100644 --- a/lib/views/github-dotcom-markdown.js +++ b/lib/views/github-dotcom-markdown.js @@ -114,7 +114,7 @@ export class BareGithubDotcomMarkdown extends React.Component { } } -export default class GithubDotcomMarkdown { +export default class GithubDotcomMarkdown extends React.Component { render() { return ( From fb3001ef0bcf8599c73e9d92ef5230061f17efad Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 16 Jul 2018 15:29:53 -0400 Subject: [PATCH 0564/4847] Prepare 0.18.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1fa46bc42c..351ca57f38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "github", - "version": "0.17.0", + "version": "0.18.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 048ed40ff1..e02c818c0e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "github", "main": "./lib/index", - "version": "0.17.0", + "version": "0.18.0", "description": "GitHub integration", "repository": "https://github.com/atom/github", "license": "MIT", From d9f1e618b4422c7b10efa2e45407f96b2b7719b6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 16 Jul 2018 15:59:40 -0400 Subject: [PATCH 0565/4847] :arrow_down: react and react-dom --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e02c818c0e..4eaa403029 100644 --- a/package.json +++ b/package.json @@ -55,8 +55,8 @@ "moment": "2.22.2", "node-emoji": "^1.8.1", "prop-types": "15.6.2", - "react": "16.4.1", - "react-dom": "16.4.1", + "react": "16.4.0", + "react-dom": "16.4.0", "react-relay": "1.6.0", "react-select": "1.2.1", "relay-runtime": "1.6.0", From bcc3069f3f3b785623f5ca14a05dd9389489ddb8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 17 Jul 2018 08:12:03 -0400 Subject: [PATCH 0566/4847] Make `setTimeout` call in ReporterProxy lazier --- lib/reporter-proxy.js | 68 +++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/lib/reporter-proxy.js b/lib/reporter-proxy.js index b3bda68286..b9912e475c 100644 --- a/lib/reporter-proxy.js +++ b/lib/reporter-proxy.js @@ -13,6 +13,8 @@ class ReporterProxy { this.counters = []; this.gitHubPackageVersion = pjson.version; + this.timeout = null; + // if for some reason a user disables the metrics package, we don't want to // just keep accumulating events in memory until the heat death of the universe. // Use a no-op class, clear all queues, move on with our lives. @@ -43,6 +45,54 @@ class ReporterProxy { this.reporter.incrementCounter(counterName); }); } + + incrementCounter(counterName) { + if (this.reporter === null) { + this.startTimer(); + this.counters.push(counterName); + return; + } + + this.reporter.incrementCounter(counterName); + } + + addTiming(eventType, durationInMilliseconds, metadata = {}) { + if (this.reporter === null) { + this.startTimer(); + this.timings.push({eventType, durationInMilliseconds, metadata}); + return; + } + + this.reporter.addTiming(eventType, durationInMilliseconds, metadata); + } + + addEvent(eventType, event) { + if (this.reporter === null) { + this.startTimer(); + this.events.push({eventType, event}); + return; + } + + this.reporter.addCustomEvent(eventType, event); + } + + startTimer() { + if (this.timeout !== null) { + return; + } + + // if for some reason a user disables the metrics package, we don't want to + // just keep accumulating events in memory until the heat death of the universe. + // Use a no-op class, clear all queues, move on with our lives. + this.timeout = setTimeout(FIVE_MINUTES_IN_MILLISECONDS, () => { + if (this.reporter === null) { + this.setReporter(new FakeReporter()); + this.events = []; + this.timings = []; + this.counters = []; + } + }); + } } export const reporterProxy = new ReporterProxy(); @@ -56,27 +106,15 @@ export class FakeReporter { } export function incrementCounter(counterName) { - if (reporterProxy.reporter) { - reporterProxy.reporter.incrementCounter(counterName); - } else { - reporterProxy.counters.push(counterName); - } + reporterProxy.incrementCounter(counterName); } export function addTiming(eventType, durationInMilliseconds, metadata = {}) { metadata.gitHubPackageVersion = reporterProxy.gitHubPackageVersion; - if (reporterProxy.reporter) { - reporterProxy.reporter.addTiming(eventType, durationInMilliseconds, metadata); - } else { - reporterProxy.timings.push({eventType, durationInMilliseconds, metadata}); - } + reporterProxy.addTiming(eventType, durationInMilliseconds, metadata); } export function addEvent(eventType, event) { event.gitHubPackageVersion = reporterProxy.gitHubPackageVersion; - if (reporterProxy.reporter) { - reporterProxy.reporter.addCustomEvent(eventType, event); - } else { - reporterProxy.events.push({eventType, event}); - } + reporterProxy.addEvent(eventType, event); } From f65254110fd504204bd78ff64d3ace8d703ce4d5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 17 Jul 2018 08:13:27 -0400 Subject: [PATCH 0567/4847] Prepare 0.18.0-0 release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4eaa403029..4646d90c36 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "github", "main": "./lib/index", - "version": "0.18.0", + "version": "0.18.0-0", "description": "GitHub integration", "repository": "https://github.com/atom/github", "license": "MIT", From 7cf76eed09425f3a716671fcd6d6da8edcda139b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 17 Jul 2018 08:18:15 -0400 Subject: [PATCH 0568/4847] I... forgot to delete the original setTimeout call --- lib/reporter-proxy.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/reporter-proxy.js b/lib/reporter-proxy.js index b9912e475c..9cb62431e1 100644 --- a/lib/reporter-proxy.js +++ b/lib/reporter-proxy.js @@ -14,18 +14,6 @@ class ReporterProxy { this.gitHubPackageVersion = pjson.version; this.timeout = null; - - // if for some reason a user disables the metrics package, we don't want to - // just keep accumulating events in memory until the heat death of the universe. - // Use a no-op class, clear all queues, move on with our lives. - setTimeout(FIVE_MINUTES_IN_MILLISECONDS, () => { - if (this.reporter === null) { - this.setReporter(new FakeReporter()); - this.events = []; - this.timings = []; - this.counters = []; - } - }); } // function that is called after the reporter is actually loaded, to From f53576d17d8c4374ad522a2a164ab6cd1d9b9af9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 17 Jul 2018 08:18:25 -0400 Subject: [PATCH 0569/4847] Prepare 0.18.0-1 release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4646d90c36..08fafe3b35 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "github", "main": "./lib/index", - "version": "0.18.0-0", + "version": "0.18.0-1", "description": "GitHub integration", "repository": "https://github.com/atom/github", "license": "MIT", From ac4d3a14ef46397f2c23c16bfbc918aa8c00c66e Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 18 Jul 2018 14:24:04 +0900 Subject: [PATCH 0570/4847] Move refresh button to top row --- lib/views/issueish-detail-view.js | 58 +++++++++++++++++-------------- styles/issueish-detail-view.less | 21 +++++------ 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index c205591b8f..e085ae7a7c 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -112,34 +112,40 @@ export class BareIssueishDetailView extends React.Component {
    -
    - - +
    + + + +

    {issueish.title}

    +
    +
    + - -

    {issueish.title}

    +
    - -
    - {this.renderCheckoutButton()} - +
    + +
    + {this.renderCheckoutButton()} +
    diff --git a/styles/issueish-detail-view.less b/styles/issueish-detail-view.less index 6f0f8ce8be..bf54121ef2 100644 --- a/styles/issueish-detail-view.less +++ b/styles/issueish-detail-view.less @@ -21,26 +21,25 @@ // Header ------------------------ &-header { - display: flex; // TODO: Use grid - justify-content: space-between; - flex-wrap: wrap; - padding: @component-padding/2; border: 1px solid @base-border-color; border-radius: @component-border-radius; } + &-headerRow { + display: flex; // TODO: Use grid + justify-content: space-between; + margin: @component-padding; + } + &-headerGroup { display: flex; align-items: center; - margin: @component-padding/2; - - &.is-fullWidth { - flex: 1 1 100%; - } } &-headerBadge { margin-right: @component-padding; + padding: 0 0.75em; + line-height: 2em; } &-headerLink { @@ -54,12 +53,13 @@ // Checkout button ----------------------- &-checkoutButton { - margin-right: @component-padding; + margin-left: @component-padding; } // Refresh Button ------------------------ &-headerRefreshButton { + align-self: flex-start; color: @text-color-subtle; cursor: pointer; @@ -83,6 +83,7 @@ // Avatar and title ------------------------ &-avatar { + align-self: flex-start; margin-right: @component-padding; } From 6ca171f05df378a50fe850bded8d2303d9d404fd Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 18 Jul 2018 15:15:22 +0900 Subject: [PATCH 0571/4847] Turn PR title into a link --- lib/views/issueish-detail-view.js | 2 +- styles/issueish-detail-view.less | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index e085ae7a7c..9cdd1e22a7 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -120,7 +120,7 @@ export class BareIssueishDetailView extends React.Component { title={issueish.author.login} /> -

    {issueish.title}

    + {issueish.title}
    Date: Wed, 18 Jul 2018 16:54:23 +0900 Subject: [PATCH 0572/4847] Add link to footer --- lib/views/issueish-detail-view.js | 6 ++++++ styles/issueish-detail-view.less | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index 9cdd1e22a7..b76f373d9c 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -180,6 +180,12 @@ export class BareIssueishDetailView extends React.Component { /> } + +
    ); diff --git a/styles/issueish-detail-view.less b/styles/issueish-detail-view.less index 299ffcf77d..7e57da13f4 100644 --- a/styles/issueish-detail-view.less +++ b/styles/issueish-detail-view.less @@ -140,6 +140,20 @@ margin: @component-padding*3 0; } + + // Build Status ------------------------ + + &-footer { + margin-top: @component-padding * 3; + text-align: center; + &Link.icon { + color: @text-color-subtle; + &:before { + vertical-align: -2px; + } + } + } + } From 0c57c05524c79584476309518ad9f9b4dd59846b Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 19 Jul 2018 15:47:02 +0900 Subject: [PATCH 0573/4847] Add link to SHAs --- .../issueishDetailContainerQuery.graphql.js | 12 ++++++++++-- .../issueTimelineControllerQuery.graphql.js | 12 ++++++++++-- .../prTimelineControllerQuery.graphql.js | 12 ++++++++++-- .../issueishDetailViewRefetchQuery.graphql.js | 12 ++++++++++-- .../__generated__/commitView_item.graphql.js | 10 +++++++++- lib/views/timeline-items/commit-view.js | 4 ++-- 6 files changed, 51 insertions(+), 11 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index b30c31ada1..1e90010952 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash d3befebde26c7c8d241df823e4703c5e + * @relayHash 5f230f88c13c1743cdc15069f0ac3827 */ /* eslint-disable */ @@ -420,6 +420,7 @@ fragment commitView_item on Commit { oid message messageHeadlineHTML + commitUrl } fragment prStatusContextView_context on StatusContext { @@ -838,6 +839,13 @@ v27 = { "name": "messageHeadlineHTML", "args": null, "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "commitUrl", + "args": null, + "storageKey": null } ] }, @@ -910,7 +918,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_n0A9R\n id\n }\n}\n\nfragment issueishDetailController_repository_n0A9R on Repository {\n ...issueishDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishDetailView_issueish_3D8CP9\n }\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...issueishDetailView_issueish_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_n0A9R\n id\n }\n}\n\nfragment issueishDetailController_repository_n0A9R on Repository {\n ...issueishDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishDetailView_issueish_3D8CP9\n }\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...issueishDetailView_issueish_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", diff --git a/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js b/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js index 0a6b3ee49e..30fd448e35 100644 --- a/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js +++ b/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 19c3a66679dcd6a6d56adf3a29f8b2ef + * @relayHash 7e36f9cce1be4f5f0865b37a13480256 */ /* eslint-disable */ @@ -175,6 +175,7 @@ fragment commitView_item on Commit { oid message messageHeadlineHTML + commitUrl } */ @@ -281,7 +282,7 @@ return { "operationKind": "query", "name": "issueTimelineControllerQuery", "id": null, - "text": "query issueTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on Issue {\n ...issueTimelineController_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", + "text": "query issueTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on Issue {\n ...issueTimelineController_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -630,6 +631,13 @@ return { "name": "messageHeadlineHTML", "args": null, "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "commitUrl", + "args": null, + "storageKey": null } ] } diff --git a/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js b/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js index e80fc01147..2f6965ee83 100644 --- a/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js +++ b/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash e400921f4377d1ed040cee69d4ba9c6c + * @relayHash 9a9f31709987ca59f66772943b366a1a */ /* eslint-disable */ @@ -267,6 +267,7 @@ fragment commitView_item on Commit { oid message messageHeadlineHTML + commitUrl } */ @@ -445,7 +446,7 @@ return { "operationKind": "query", "name": "prTimelineControllerQuery", "id": null, - "text": "query prTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n", + "text": "query prTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -902,6 +903,13 @@ return { "name": "messageHeadlineHTML", "args": null, "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "commitUrl", + "args": null, + "storageKey": null } ] } diff --git a/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js index 5204b29995..619fd07ecc 100644 --- a/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 1713fc0aab49681909c757e7fb0f9d04 + * @relayHash c14c073267984ecfa8c452806d869df1 */ /* eslint-disable */ @@ -390,6 +390,7 @@ fragment commitView_item on Commit { oid message messageHeadlineHTML + commitUrl } fragment prStatusContextView_context on StatusContext { @@ -846,6 +847,13 @@ v31 = { "name": "messageHeadlineHTML", "args": null, "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "commitUrl", + "args": null, + "storageKey": null } ] }; @@ -854,7 +862,7 @@ return { "operationKind": "query", "name": "issueishDetailViewRefetchQuery", "id": null, - "text": "query issueishDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishDetailView_repository_3D8CP9\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishDetailView_issueish_3D8CP9\n id\n }\n}\n\nfragment issueishDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishDetailView_repository_3D8CP9\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishDetailView_issueish_3D8CP9\n id\n }\n}\n\nfragment issueishDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", diff --git a/lib/views/timeline-items/__generated__/commitView_item.graphql.js b/lib/views/timeline-items/__generated__/commitView_item.graphql.js index 345dbbcaf4..9dccf19f53 100644 --- a/lib/views/timeline-items/__generated__/commitView_item.graphql.js +++ b/lib/views/timeline-items/__generated__/commitView_item.graphql.js @@ -29,6 +29,7 @@ export type commitView_item = {| +oid: any, +message: string, +messageHeadlineHTML: any, + +commitUrl: any, +$refType: commitView_item$ref, |}; */ @@ -123,10 +124,17 @@ return { "name": "messageHeadlineHTML", "args": null, "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "commitUrl", + "args": null, + "storageKey": null } ] }; })(); // prettier-ignore -(node/*: any*/).hash = 'e58543afc5a89f1abb41ae37873a5e0a'; +(node/*: any*/).hash = '4030a81cc744eed1200ebf85a60082c9'; module.exports = node; diff --git a/lib/views/timeline-items/commit-view.js b/lib/views/timeline-items/commit-view.js index db96baad8f..3213a2a3bf 100644 --- a/lib/views/timeline-items/commit-view.js +++ b/lib/views/timeline-items/commit-view.js @@ -59,7 +59,7 @@ export class BareCommitView extends React.Component { title={commit.message} dangerouslySetInnerHTML={{__html: commit.messageHeadlineHTML}} /> - {commit.oid.slice(0, 8)} + {commit.oid.slice(0, 8)}
    ); } @@ -81,7 +81,7 @@ export default createFragmentContainer(BareCommitView, { } } authoredByCommitter - oid message messageHeadlineHTML + oid message messageHeadlineHTML commitUrl } `, }); From f18e99a4c80a95e2fad013e7795653af91f8b172 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 19 Jul 2018 11:14:42 +0900 Subject: [PATCH 0574/4847] Match issue links with ref-numbers --- styles/github-dotcom-markdown.less | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/styles/github-dotcom-markdown.less b/styles/github-dotcom-markdown.less index 06f42e7f25..d5783bc47e 100644 --- a/styles/github-dotcom-markdown.less +++ b/styles/github-dotcom-markdown.less @@ -166,4 +166,10 @@ background-color: @background-color-highlight; } + // Custom -------------------- + + .issue-link { + color: @text-color-subtle; // same as .cross-referenced-event-label-number + } + } From 9eff159a1e7d90d0b0c9e512f8058517c7d5e373 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 19 Jul 2018 16:24:08 +0900 Subject: [PATCH 0575/4847] Add link to comment timeago --- .../issueishDetailContainerQuery.graphql.js | 8 +++++--- .../issueTimelineControllerQuery.graphql.js | 8 +++++--- .../__generated__/prTimelineControllerQuery.graphql.js | 8 +++++--- .../issueishDetailViewRefetchQuery.graphql.js | 8 +++++--- .../__generated__/issueCommentView_item.graphql.js | 10 +++++++++- lib/views/timeline-items/issue-comment-view.js | 5 +++-- styles/pr-timeline.less | 3 +++ 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 1e90010952..1af06e1212 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 5f230f88c13c1743cdc15069f0ac3827 + * @relayHash fd2fb50c17cd6fc965d556a7247314a9 */ /* eslint-disable */ @@ -259,6 +259,7 @@ fragment issueCommentView_item on IssueComment { } bodyHTML createdAt + url } fragment mergedEventView_item on MergedEvent { @@ -770,7 +771,8 @@ v25 = { "selections": v23 }, v21, - v22 + v22, + v10 ] }, v26 = { @@ -918,7 +920,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_n0A9R\n id\n }\n}\n\nfragment issueishDetailController_repository_n0A9R on Repository {\n ...issueishDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishDetailView_issueish_3D8CP9\n }\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...issueishDetailView_issueish_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_n0A9R\n id\n }\n}\n\nfragment issueishDetailController_repository_n0A9R on Repository {\n ...issueishDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishDetailView_issueish_3D8CP9\n }\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...issueishDetailView_issueish_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", diff --git a/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js b/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js index 30fd448e35..8493f37921 100644 --- a/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js +++ b/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 7e36f9cce1be4f5f0865b37a13480256 + * @relayHash 11a080534b1e9e618daa153d559f5efc */ /* eslint-disable */ @@ -85,6 +85,7 @@ fragment issueCommentView_item on IssueComment { } bodyHTML createdAt + url } fragment crossReferencedEventsView_nodes on CrossReferencedEvent { @@ -282,7 +283,7 @@ return { "operationKind": "query", "name": "issueTimelineControllerQuery", "id": null, - "text": "query issueTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on Issue {\n ...issueTimelineController_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", + "text": "query issueTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on Issue {\n ...issueTimelineController_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -569,7 +570,8 @@ return { "name": "createdAt", "args": null, "storageKey": null - } + }, + v4 ] }, { diff --git a/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js b/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js index 2f6965ee83..12ce6837e0 100644 --- a/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js +++ b/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 9a9f31709987ca59f66772943b366a1a + * @relayHash af853f1ab5f7d7727fafd178050ec61a */ /* eslint-disable */ @@ -106,6 +106,7 @@ fragment issueCommentView_item on IssueComment { } bodyHTML createdAt + url } fragment mergedEventView_item on MergedEvent { @@ -446,7 +447,7 @@ return { "operationKind": "query", "name": "prTimelineControllerQuery", "id": null, - "text": "query prTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", + "text": "query prTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -847,7 +848,8 @@ return { "selections": v18 }, v16, - v17 + v17, + v4 ] }, { diff --git a/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js index 619fd07ecc..212b2badeb 100644 --- a/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash c14c073267984ecfa8c452806d869df1 + * @relayHash e59fe378fd0cacef7e695703a6cb0022 */ /* eslint-disable */ @@ -229,6 +229,7 @@ fragment issueCommentView_item on IssueComment { } bodyHTML createdAt + url } fragment mergedEventView_item on MergedEvent { @@ -778,7 +779,8 @@ v29 = { "selections": v27 }, v17, - v26 + v26, + v10 ] }, v30 = { @@ -862,7 +864,7 @@ return { "operationKind": "query", "name": "issueishDetailViewRefetchQuery", "id": null, - "text": "query issueishDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishDetailView_repository_3D8CP9\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishDetailView_issueish_3D8CP9\n id\n }\n}\n\nfragment issueishDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "text": "query issueishDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishDetailView_repository_3D8CP9\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishDetailView_issueish_3D8CP9\n id\n }\n}\n\nfragment issueishDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_3D8CP9 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", diff --git a/lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js b/lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js index 6f68a9f803..03c065e29b 100644 --- a/lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js +++ b/lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js @@ -17,6 +17,7 @@ export type issueCommentView_item = {| |}, +bodyHTML: any, +createdAt: any, + +url: any, +$refType: issueCommentView_item$ref, |}; */ @@ -67,9 +68,16 @@ const node/*: ConcreteFragment*/ = { "name": "createdAt", "args": null, "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null } ] }; // prettier-ignore -(node/*: any*/).hash = '802c96476c5abd33c8c2470b2424a584'; +(node/*: any*/).hash = 'adc36c52f51de14256693ab9e4eb84bb'; module.exports = node; diff --git a/lib/views/timeline-items/issue-comment-view.js b/lib/views/timeline-items/issue-comment-view.js index a65fa24cf8..2450ab5b52 100644 --- a/lib/views/timeline-items/issue-comment-view.js +++ b/lib/views/timeline-items/issue-comment-view.js @@ -29,7 +29,8 @@ export class BareIssueCommentView extends React.Component { {author && } - {author ? author.login : 'someone'} commented + {author ? author.login : 'someone'} commented + {' '}
    @@ -44,7 +45,7 @@ export default createFragmentContainer(BareIssueCommentView, { author { avatarUrl login } - bodyHTML createdAt + bodyHTML createdAt url } `, }); diff --git a/styles/pr-timeline.less b/styles/pr-timeline.less index a4d476e1c1..2115840d3e 100644 --- a/styles/pr-timeline.less +++ b/styles/pr-timeline.less @@ -119,6 +119,9 @@ .comment-message-header { font-size: .9em; color: @text-color-subtle; + a { + color: inherit; + } } .cross-referenced-events { From 929d44d770083991010f5a30cc38da7035d926b9 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 19 Jul 2018 20:59:35 +0900 Subject: [PATCH 0576/4847] Create Popover component --- lib/controllers/status-bar-tile-controller.js | 2 +- styles/popover.less | 29 +++++++++++++++++++ styles/status-bar-tile-controller.less | 25 ---------------- 3 files changed, 30 insertions(+), 26 deletions(-) create mode 100644 styles/popover.less diff --git a/lib/controllers/status-bar-tile-controller.js b/lib/controllers/status-bar-tile-controller.js index 95cf29b31a..10472c3a29 100644 --- a/lib/controllers/status-bar-tile-controller.js +++ b/lib/controllers/status-bar-tile-controller.js @@ -131,7 +131,7 @@ export default class StatusBarTileController extends React.Component { manager={this.props.tooltips} target={this.refBranchViewRoot} trigger="click" - className="github-StatusBarTileController-tooltipMenu"> + className="github-Popover"> .inline-block:hover { text-decoration: underline; cursor: default; From cf575e45765c5be0f8dcad6dda5b98a01703e1a7 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 19 Jul 2018 21:40:53 +0900 Subject: [PATCH 0577/4847] Restyle user-mention tooltips --- lib/views/github-dotcom-markdown.js | 1 + styles/user-mention-tooltip.less | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/views/github-dotcom-markdown.js b/lib/views/github-dotcom-markdown.js index 07a32ac7a5..8fa64ad6ed 100644 --- a/lib/views/github-dotcom-markdown.js +++ b/lib/views/github-dotcom-markdown.js @@ -63,6 +63,7 @@ export class BareGithubDotcomMarkdown extends React.Component { this.tooltipSubscriptions.add(atom.tooltips.add(node, { trigger: 'hover', delay: 0, + class: 'github-Popover', item, })); this.tooltipSubscriptions.add(new Disposable(() => item.destroy())); diff --git a/styles/user-mention-tooltip.less b/styles/user-mention-tooltip.less index 4b92e25713..3b7fefc6ec 100644 --- a/styles/user-mention-tooltip.less +++ b/styles/user-mention-tooltip.less @@ -4,26 +4,39 @@ display: flex; &-avatar { - flex-basis: 50px; - padding-right: @component-padding; + margin: @component-padding/2; > img { - width: 90px; - height: 90px; - border-radius: @component-border-radius / 2; + width: 60px; + height: 60px; + border-radius: @component-border-radius; } } &-info { flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + margin: @component-padding/2; + margin-left: @component-padding; + font-size: @font-size; + line-height: 20px; text-align: left; - line-height: 1.6; > div { white-space: nowrap; } .icon { + color: @text-color-subtle; vertical-align: middle; } + + &-username { + font-size: 1.2em; + strong { + font-weight: 600; + } + } } } From 328e69f678cd7dbeff558ba4765bf34917ca63ef Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 19 Jul 2018 22:04:54 +0900 Subject: [PATCH 0578/4847] Restyle issueish tooltips --- lib/views/github-dotcom-markdown.js | 1 + styles/issueish-tooltip.less | 28 +++++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/views/github-dotcom-markdown.js b/lib/views/github-dotcom-markdown.js index 8fa64ad6ed..7287f04668 100644 --- a/lib/views/github-dotcom-markdown.js +++ b/lib/views/github-dotcom-markdown.js @@ -73,6 +73,7 @@ export class BareGithubDotcomMarkdown extends React.Component { this.tooltipSubscriptions.add(atom.tooltips.add(node, { trigger: 'hover', delay: 0, + class: 'github-Popover', item, })); this.tooltipSubscriptions.add(new Disposable(() => item.destroy())); diff --git a/styles/issueish-tooltip.less b/styles/issueish-tooltip.less index 96e8dbb47b..35abc513e0 100644 --- a/styles/issueish-tooltip.less +++ b/styles/issueish-tooltip.less @@ -1,8 +1,9 @@ @import 'variables'; .github-IssueishTooltip { - max-width: 500px; text-align: left; + font-size: .9em; + padding: @component-padding/2; .issueish-badge-and-link { padding-bottom: @component-padding; @@ -36,19 +37,32 @@ } } + .issueish-link { + color: @text-color-subtle; + } + .issueish-title { + display: block; margin: 0; padding-bottom: @component-padding; - line-height: 1.2; - display: block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + font-size: 1.1em; + font-weight: 600; + line-height: 1.3; + color: @text-color-highlight; + white-space: initial; + } + + .issueish-avatar-and-title { + strong { + font-weight: normal; + color: @text-color-subtle; + } } .author-avatar { - margin-right: 10px; + margin-right: @component-padding/2; width: 20px; height: 20px; + border-radius: @component-border-radius; } } From ebc221e9e3dd8496d7f92872887653b3f0559cd3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 19 Jul 2018 13:59:30 -0400 Subject: [PATCH 0579/4847] package-lock bump --- package-lock.json | 388 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 374 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 351ca57f38..1ada9ff499 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "github", - "version": "0.18.0", + "version": "0.18.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -26,9 +26,18 @@ "dev": true, "requires": { "@babel/types": "7.0.0-beta.49", + "jsesc": "^2.5.1", "lodash": "^4.17.5", "source-map": "^0.5.0", "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", + "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", + "dev": true + } } }, "@babel/helper-function-name": { @@ -66,8 +75,40 @@ "integrity": "sha1-lr3GtD4TSCASumaRsQGEktOWIsw=", "dev": true, "requires": { + "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@babel/parser": { @@ -100,8 +141,27 @@ "@babel/helper-split-export-declaration": "7.0.0-beta.49", "@babel/parser": "7.0.0-beta.49", "@babel/types": "7.0.0-beta.49", + "debug": "^3.1.0", + "globals": "^11.1.0", "invariant": "^2.2.0", "lodash": "^4.17.5" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "dev": true + } } }, "@babel/types": { @@ -198,6 +258,26 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", "dev": true }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "amdefine": { "version": "1.0.1", "resolved": false, @@ -1543,6 +1623,14 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "requires": { + "hoek": "4.x.x" + } + }, "brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", @@ -1698,6 +1786,15 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, "chai": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", @@ -1997,6 +2094,24 @@ "integrity": "sha1-UYO8R6CVWb78+YzEZXlkmZNZNy8=", "dev": true }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.x.x" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.x.x" + } + } + } + }, "css-select": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", @@ -2306,6 +2421,14 @@ "semver": "^5.3.0" } }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -3040,7 +3163,36 @@ "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", "dev": true, "requires": { + "cross-spawn": "^4", "signal-exit": "^3.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } } }, "forever-agent": { @@ -3303,10 +3455,27 @@ "dev": true, "requires": { "async": "^1.4.0", + "optimist": "^0.6.1", "source-map": "^0.4.4", "uglify-js": "^2.6" }, "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, "source-map": { "version": "0.4.4", "resolved": false, @@ -3397,6 +3566,17 @@ } } }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "requires": { + "boom": "4.x.x", + "cryptiles": "3.x.x", + "hoek": "4.x.x", + "sntp": "2.x.x" + } + }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", @@ -3412,6 +3592,11 @@ "deep-equal": "0.2.1" } }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" + }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -3454,8 +3639,7 @@ "iconv-lite": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==", - "dev": true + "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" }, "ignore": { "version": "3.3.10", @@ -3885,7 +4069,19 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { + "node-fetch": "^1.0.1", "whatwg-fetch": ">=0.10.0" + }, + "dependencies": { + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + } } }, "isstream": { @@ -3982,7 +4178,19 @@ "dev": true, "requires": { "istanbul-lib-coverage": "^2.0.0", - "make-dir": "^1.3.0" + "make-dir": "^1.3.0", + "supports-color": "^5.4.0" + }, + "dependencies": { + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "istanbul-lib-source-maps": { @@ -3991,12 +4199,22 @@ "integrity": "sha512-jenUeC0gMSSMGkvqD9xuNfs3nD7XWeXLhqaIkqHsNZ3DJBWPdlKEydE7Ya5aTgdWjrEQhrCYTv+J606cGC2vuQ==", "dev": true, "requires": { + "debug": "^3.1.0", "istanbul-lib-coverage": "^2.0.0", "make-dir": "^1.3.0", "rimraf": "^2.6.2", "source-map": "^0.6.1" }, "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "source-map": { "version": "0.6.1", "resolved": false, @@ -4170,6 +4388,11 @@ "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", "dev": true }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -4556,6 +4779,11 @@ "integrity": "sha1-5AqMTR8UtTaqA+QqU3x6268MIL4=", "dev": true }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, "loose-envify": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", @@ -4791,20 +5019,61 @@ "requires": { "browser-stdout": "1.3.0", "commander": "2.9.0", + "debug": "2.6.8", "diff": "3.2.0", "escape-string-regexp": "1.0.5", + "glob": "7.1.1", "growl": "1.9.2", "he": "1.1.1", "json3": "3.3.2", "lodash.create": "3.1.1", - "mkdirp": "0.5.1" + "mkdirp": "0.5.1", + "supports-color": "3.1.2" }, "dependencies": { + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "diff": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", "dev": true + }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } } } }, @@ -5913,9 +6182,9 @@ } }, "react": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/react/-/react-16.4.1.tgz", - "integrity": "sha1-3lG6V2S1280fkHkDe4Yr0muC/jI=", + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.4.0.tgz", + "integrity": "sha512-K0UrkLXSAekf5nJu89obKUM7o2vc6MMN9LYoKnCa+c+8MJRAT120xzPLENcWSRc7GYKIg0LlgJRDorrufdglQQ==", "requires": { "fbjs": "^0.8.16", "loose-envify": "^1.1.0", @@ -5924,9 +6193,9 @@ } }, "react-dom": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.1.tgz", - "integrity": "sha1-f4sCI7Ol++IFEWxW3rhd4yaF2tY=", + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.0.tgz", + "integrity": "sha512-bbLd+HYpBEnYoNyxDe9XpSG2t9wypMohwQPvKw8Hov3nF7SJiJIgK56b46zHpBUpHb06a1iEuw7G3rbrsnNL6w==", "requires": { "fbjs": "^0.8.16", "loose-envify": "^1.1.0", @@ -6263,8 +6532,7 @@ "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, "repeating": { "version": "2.0.1", @@ -6322,7 +6590,55 @@ "integrity": "sha512-5TVnMD3LaeK0GRCyFlsNgJf5Fjg8J8j7VEfsoJESSWZlWRgPIf7IojsBLbTHcg2798JrrRkJ6L3k1+wj4sglgw==", "dev": true, "requires": { - "depd": "1.1.2" + "depd": "1.1.2", + "request": "2.83.0" + }, + "dependencies": { + "mime-db": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "dev": true, + "requires": { + "mime-db": "~1.35.0" + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "hawk": "~6.0.2", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "stringstream": "~0.0.5", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" + } + } } }, "require-directory": { @@ -6375,6 +6691,14 @@ "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", "dev": true }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "requires": { + "align-text": "^0.1.1" + } + }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", @@ -6677,6 +7001,14 @@ } } }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "requires": { + "hoek": "4.x.x" + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -7325,6 +7657,32 @@ "yargs": "~3.10.0" }, "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + }, "yargs": { "version": "3.10.0", "resolved": false, @@ -7332,6 +7690,8 @@ "dev": true, "optional": true, "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", "decamelize": "^1.0.0", "window-size": "0.1.0" } From 4eaac2bf718b39c70e2f0a465b7d70c8e3a8a94b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 19 Jul 2018 14:21:02 -0400 Subject: [PATCH 0580/4847] Use mocha-multi-reporters --- package-lock.json | 142 ++++------------------------------------------ package.json | 2 +- test/runner.js | 16 ++++-- 3 files changed, 23 insertions(+), 137 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1ada9ff499..f9dbc59136 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4237,30 +4237,6 @@ "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", "integrity": "sha1-ktcN64Ao4MOf8xZP2/TYsIgTDNc=" }, - "jade": { - "version": "0.26.3", - "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", - "dev": true, - "requires": { - "commander": "0.6.1", - "mkdirp": "0.3.0" - }, - "dependencies": { - "commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true - }, - "mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "dev": true - } - } - }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -4792,12 +4768,6 @@ "js-tokens": "^3.0.0" } }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, "make-dir": { "version": "1.3.0", "resolved": false, @@ -5130,96 +5100,24 @@ } } }, - "mocha-junit-and-console-reporter": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mocha-junit-and-console-reporter/-/mocha-junit-and-console-reporter-1.6.0.tgz", - "integrity": "sha1-kBmEuev51g9xXvDo4EwG5KsSJFc=", + "mocha-multi-reporters": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/mocha-multi-reporters/-/mocha-multi-reporters-1.1.7.tgz", + "integrity": "sha1-zH8/TTL0eFIJQdhSq7ZNmYhYfYI=", "dev": true, "requires": { - "debug": "^2.2.0", - "mkdirp": "~0.5.1", - "mocha": "^2.2.5", - "xml": "^1.0.0" + "debug": "^3.1.0", + "lodash": "^4.16.4" }, "dependencies": { - "commander": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", - "dev": true - }, - "diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", - "dev": true - }, - "glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", - "dev": true, - "requires": { - "inherits": "2", - "minimatch": "0.3" - } - }, - "minimatch": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - }, - "mocha": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", - "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { - "commander": "2.3.0", - "debug": "2.2.0", - "diff": "1.4.0", - "escape-string-regexp": "1.0.2", - "glob": "3.2.11", - "growl": "1.9.2", - "jade": "0.26.3", - "mkdirp": "0.5.1", - "supports-color": "1.2.0", - "to-iso-string": "0.0.2" - }, - "dependencies": { - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, - "requires": { - "ms": "0.7.1" - } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", - "dev": true - } + "ms": "2.0.0" } - }, - "supports-color": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", - "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", - "dev": true } } }, @@ -6808,12 +6706,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -7535,12 +7427,6 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, - "to-iso-string": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", - "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", - "dev": true - }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -8004,12 +7890,6 @@ "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", "dev": true }, - "xml": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", - "dev": true - }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", diff --git a/package.json b/package.json index 08fafe3b35..0a382eb006 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "lodash.isequal": "4.5.0", "mkdirp": "0.5.1", "mocha-appveyor-reporter": "0.4.0", - "mocha-junit-and-console-reporter": "1.6.0", + "mocha-multi-reporters": "^1.1.7", "mocha-stress": "1.0.0", "node-fetch": "2.1.2", "nyc": "13.0.0", diff --git a/test/runner.js b/test/runner.js index 2aaa517c70..598dd47b81 100644 --- a/test/runner.js +++ b/test/runner.js @@ -76,7 +76,7 @@ if (process.env.ATOM_GITHUB_BABEL_ENV === 'coverage' && !process.env.NYC_CONFIG) module.exports = createRunner({ htmlTitle: `GitHub Package Tests - pid ${process.pid}`, - reporter: process.env.MOCHA_REPORTER || 'spec', + reporter: process.env.MOCHA_REPORTER || 'list', overrideTestPaths: [/spec$/, /test/], }, mocha => { const Enzyme = require('enzyme'); @@ -88,14 +88,20 @@ module.exports = createRunner({ mocha.timeout(parseInt(process.env.MOCHA_TIMEOUT || '5000', 10)); if (process.env.TEST_JUNIT_XML_PATH) { - mocha.reporter(require('mocha-junit-and-console-reporter'), { - mochaFile: process.env.TEST_JUNIT_XML_PATH, + mocha.reporter(require('mocha-multi-reporters'), { + reportersEnabled: 'mocha-junit-reporter, list', + mochaJunitReporterReporterOptions: { + mochaFile: process.env.TEST_JUNIT_XML_PATH, + }, }); } else if (process.env.APPVEYOR_API_URL) { mocha.reporter(require('mocha-appveyor-reporter')); } else if (process.env.CIRCLECI === 'true') { - mocha.reporter(require('mocha-junit-and-console-reporter'), { - mochaFile: path.join('test-results', 'mocha', 'test-results.xml'), + mocha.reporter(require('mocha-multi-reporters'), { + reportersEnabled: 'mocha-junit-reporter, list', + mochaJunitReporterReporterOptions: { + mochaFile: path.join('test-results', 'mocha', 'test-results.xml'), + }, }); } }); From 45fd84e707625f64dd5c0fddd47869ca19cc450b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 19 Jul 2018 15:57:09 -0400 Subject: [PATCH 0581/4847] Split GithubTabController into twos, nay, into threes --- lib/containers/github-tab-container.js | 73 +++++++++ lib/controllers/github-tab-controller.js | 186 +++++------------------ lib/items/github-tab-item.js | 67 ++++++++ lib/views/github-tab-view.js | 81 ++++++++++ 4 files changed, 261 insertions(+), 146 deletions(-) create mode 100644 lib/containers/github-tab-container.js create mode 100644 lib/items/github-tab-item.js create mode 100644 lib/views/github-tab-view.js diff --git a/lib/containers/github-tab-container.js b/lib/containers/github-tab-container.js new file mode 100644 index 0000000000..f6bee910c2 --- /dev/null +++ b/lib/containers/github-tab-container.js @@ -0,0 +1,73 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import yubikiri from 'yubikiri'; + +import {GithubLoginModelPropType, RefHolderPropType} from '../prop-types'; +import {autobind} from '../helpers'; +import OperationStateObserver, {PUSH, PULL, FETCH} from '../models/operation-state-observer'; +import GitHubTabController from '../controllers/github-tab-controller'; +import ObserveModel from '../views/observe-model'; +import LoadingView from '../views/loading-view'; + +export default class GitHubTabContainer extends React.Component { + static propTypes = { + workspace: PropTypes.object.isRequired, + repository: PropTypes.object, + loginModel: GithubLoginModelPropType.isRequired, + rootHolder: RefHolderPropType.isRequired, + } + + constructor(props) { + super(props); + autobind(this, 'fetchRepositoryData', 'renderRepositoryData'); + + this.state = {}; + } + + static getDerivedStateFromProps(props, state) { + if (props.repository !== state.lastRepository) { + return { + lastRepository: props.repository, + remoteOperationObserver: new OperationStateObserver(props.repository, PUSH, PULL, FETCH), + }; + } + + return null; + } + + fetchRepositoryData(repository) { + return yubikiri({ + workingDirectory: repository.getWorkingDirectoryPath(), + allRemotes: repository.getRemotes(), + branches: repository.getBranches(), + selectedRemoteName: repository.getConfig('atomGithub.currentRemote'), + aheadCount: async query => { + const branches = await query.branches; + const currentBranch = branches.getHeadBranch(); + return repository.getAheadCount(currentBranch.getName()); + }, + pushInProgress: repository.getOperationStates().isPushInProgress(), + }); + } + + render() { + return ( + + {this.renderRepositoryData} + + ); + } + + renderRepositoryData(data) { + if (!data) { + return ; + } + + if (!this.props.repository.isPresent()) { + // TODO include a better message here. + return null; + } + + return ; + } +} diff --git a/lib/controllers/github-tab-controller.js b/lib/controllers/github-tab-controller.js index 0d6aeaad75..949ee7b3d6 100644 --- a/lib/controllers/github-tab-controller.js +++ b/lib/controllers/github-tab-controller.js @@ -1,130 +1,64 @@ import React from 'react'; import PropTypes from 'prop-types'; -import yubikiri from 'yubikiri'; -import RemoteSelectorView from '../views/remote-selector-view'; -import RemoteContainer from '../containers/remote-container'; -import GithubLoginModel from '../models/github-login-model'; -import OperationStateObserver, {PUSH, PULL, FETCH} from '../models/operation-state-observer'; -import ObserveModel from '../views/observe-model'; +import { + GithubLoginModelPropType, RefHolderPropType, RemoteSetPropType, BranchSetPropType, OperationStateObserverPropType, +} from '../prop-types'; import {autobind} from '../helpers'; +import GitHubTabView from '../views/github-tab-view'; -export default class GithubTabController extends React.Component { +export default class GitHubTabController extends React.Component { static propTypes = { workspace: PropTypes.object.isRequired, - repository: PropTypes.object, - loginModel: PropTypes.instanceOf(GithubLoginModel), - } - - static uriPattern = 'atom-github://dock-item/github'; + repository: PropTypes.object.isRequired, + remoteOperationObserver: OperationStateObserverPropType.isRequired, + loginModel: GithubLoginModelPropType.isRequired, + rootHolder: RefHolderPropType.isRequired, - static buildURI() { - return this.uriPattern; + workingDirectory: PropTypes.string.isRequired, + allRemotes: RemoteSetPropType.isRequired, + branches: BranchSetPropType.isRequired, + selectedRemoteName: PropTypes.string.isRequired, + aheadCount: PropTypes.number.isRequired, + pushInProgress: PropTypes.bool.isRequired, } constructor(props) { super(props); - autobind(this, 'handleRemoteSelect'); - - this.state = {}; - } - - static getDerivedStateFromProps(props, state) { - if (props.repository !== state.lastRepository) { - return { - lastRepository: props.repository, - remoteOperationObserver: new OperationStateObserver(props.repository, PUSH, PULL, FETCH), - }; - } - - return null; - } - - fetchModelData(repo) { - return yubikiri({ - workingDirectory: repo.getWorkingDirectoryPath(), - allRemotes: repo.getRemotes(), - branches: repo.getBranches(), - selectedRemoteName: repo.getConfig('atomGithub.currentRemote'), - selectedPrUrl: async query => { - const branches = await query.branches; - const currentBranch = branches.getHeadBranch(); - if (!currentBranch.isPresent()) { return null; } - return repo.getConfig(`branch.${currentBranch.getName()}.atomPrUrl`); - }, - aheadCount: async query => { - const branches = await query.branches; - const currentBranch = branches.getHeadBranch(); - return repo.getAheadCount(currentBranch.getName()); - }, - }); - } - - serialize() { - return { - deserializer: 'GithubDockItem', - uri: this.getURI(), - }; + autobind(this, 'handlePushBranch', 'handleRemoteSelect'); } render() { - return ( - - {data => { return data ? this.renderWithData(data) : null; } } - - ); - } + const gitHubRemotes = this.props.allRemotes.filter(remote => remote.isGithubRepo()); + const currentBranch = this.props.branches.getHeadBranch(); - renderWithData(data) { - const { - workingDirectory, allRemotes, branches, selectedRemoteName, aheadCount, - } = data; - if (!this.props.repository.isPresent()) { - return null; - } - - const remotes = allRemotes.filter(remote => remote.isGithubRepo()); - const currentBranch = branches.getHeadBranch(); - - let remote = remotes.withName(selectedRemoteName); + let currentRemote = gitHubRemotes.withName(this.props.selectedRemoteName); let manyRemotesAvailable = false; - if (!remote.isPresent() && remotes.size() === 1) { - remote = Array.from(remotes)[0]; - } else if (!remote.isPresent() && remotes.size() > 1) { + if (!currentRemote.isPresent() && gitHubRemotes.size() === 1) { + currentRemote = Array.from(gitHubRemotes)[0]; + } else if (!currentRemote.isPresent() && gitHubRemotes.size() > 1) { manyRemotesAvailable = true; } - const pushInProgress = this.props.repository.getOperationStates().isPushInProgress(); - return ( -
    { this.root = c; }} className="github-GithubTabController"> -
    - {/* only supporting GH.com for now, hardcoded values */} - {remote.isPresent() && - this.handlePushBranch(currentBranch, remote)} - remote={remote} - remotes={remotes} - branches={branches} - aheadCount={aheadCount} - pushInProgress={pushInProgress} - /> - } - {!remote.isPresent() && manyRemotesAvailable && - - } - {!remote.isPresent() && !manyRemotesAvailable && this.renderNoRemotes()} -
    -
    + ); } @@ -135,48 +69,8 @@ export default class GithubTabController extends React.Component { }); } - getTitle() { - return 'GitHub (preview)'; - } - - getIconName() { - return 'octoface'; - } - - getDefaultLocation() { - return 'right'; - } - - getPreferredWidth() { - return 400; - } - - getURI() { - return this.constructor.uriPattern; - } - - getWorkingDirectory() { - return this.props.repository.getWorkingDirectoryPath(); - } - - renderNoRemotes() { - return ( -
    - This repository does not have any remotes hosted at GitHub.com. -
    - ); - } - handleRemoteSelect(e, remote) { e.preventDefault(); return this.props.repository.setConfig('atomGithub.currentRemote', remote.getName()); } - - hasFocus() { - return this.root && this.root.contains(document.activeElement); - } - - restoreFocus() { - // No-op - } } diff --git a/lib/items/github-tab-item.js b/lib/items/github-tab-item.js new file mode 100644 index 0000000000..2f77494be3 --- /dev/null +++ b/lib/items/github-tab-item.js @@ -0,0 +1,67 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import {GithubLoginModelPropType} from '../prop-types'; +import RefHolder from '../models/ref-holder'; +import GitHubTabContainer from '../containers/github-tab-container'; + +export default class GitHubTabItem extends React.Component { + static propTypes = { + workspace: PropTypes.object.isRequired, + repository: PropTypes.object, + loginModel: GithubLoginModelPropType.isRequired, + } + + static uriPattern = 'atom-github://dock-item/github'; + + static buildURI() { + return this.uriPattern; + } + + constructor(props) { + super(props); + + this.rootHolder = new RefHolder(); + } + + getTitle() { + return 'GitHub (preview)'; + } + + getIconName() { + return 'octoface'; + } + + getDefaultLocation() { + return 'right'; + } + + getPreferredWidth() { + return 400; + } + + getWorkingDirectory() { + return this.props.repository.getWorkingDirectoryPath(); + } + + serialize() { + return { + deserializer: 'GithubDockItem', + uri: this.getURI(), + }; + } + + render() { + return ( + + ); + } + + hasFocus() { + return this.rootHolder.map(root => root.contains(document.activeElement), () => false); + } + + restoreFocus() { + // No-op + } +} diff --git a/lib/views/github-tab-view.js b/lib/views/github-tab-view.js new file mode 100644 index 0000000000..5a371be384 --- /dev/null +++ b/lib/views/github-tab-view.js @@ -0,0 +1,81 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { + GithubLoginModelPropType, RefHolderPropType, RemoteSetPropType, RemotePropType, BranchSetPropType, BranchPropType, + OperationStateObserverPropType, +} from '../prop-types'; +import RemoteSelectorView from '../views/remote-selector-view'; +import RemoteContainer from '../containers/remote-container'; + +export default class GitHubTabView extends React.Component { + static propTypes = { + workspace: PropTypes.object.isRequired, + remoteOperationObserver: OperationStateObserverPropType.isRequired, + loginModel: GithubLoginModelPropType.isRequired, + rootHolder: RefHolderPropType.isRequired, + + workingDirectory: PropTypes.string.isRequired, + branches: BranchSetPropType.isRequired, + currentBranch: BranchPropType.isRequired, + remotes: RemoteSetPropType.isRequired, + currentRemote: RemotePropType.isRequired, + manyRemotesAvailable: PropTypes.bool.isRequired, + aheadCount: PropTypes.number.isRequired, + pushInProgress: PropTypes.bool.isRequired, + + handlePushBranch: PropTypes.func.isRequired, + handleRemoteSelect: PropTypes.func.isRequired, + } + + render() { + return ( +
    +
    + {this.renderRemote()} +
    +
    + ); + } + + renderRemote() { + if (this.props.currentRemote.isPresent()) { + // Single, chosen or unambiguous remote + // only supporting GH.com for now, hardcoded values + return ( + this.props.handlePushBranch(this.props.currentBranch, this.props.currentRemote)} + remote={this.props.currentRemote} + remotes={this.props.remotes} + branches={this.props.branches} + aheadCount={this.props.aheadCount} + pushInProgress={this.props.pushInProgress} + /> + ); + } + + if (this.props.manyRemotesAvailable) { + // No chosen remote, multiple remotes hosted on GitHub instances + return ( + + ); + } + + // No remotes available + // TODO: display a view that lets you create a repository on GitHub + return ( +
    + This repository does not have any remotes hosted at GitHub.com. +
    + ); + } +} From e0cf9906e5978fa30c21b3d59ffdf83d5cfe193f Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 19 Jul 2018 14:20:58 -0700 Subject: [PATCH 0582/4847] Add jsx-a11y eslint plugin --- .eslintrc | 5 +- package-lock.json | 3519 +++++++++++++++++++++++++-------------------- package.json | 1 + 3 files changed, 1980 insertions(+), 1545 deletions(-) diff --git a/.eslintrc b/.eslintrc index 9ba2e4bb2d..a877d432c4 100644 --- a/.eslintrc +++ b/.eslintrc @@ -11,7 +11,10 @@ "atom" ] }, - "extends": ["fbjs-opensource"], + "plugins": [ + "jsx-a11y" + ], + "extends": ["fbjs-opensource", "plugin:jsx-a11y/recommended"], "rules": { "linebreak-style": 0, "no-param-reassign": 0, diff --git a/package-lock.json b/package-lock.json index 351ca57f38..e11cbfade9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "github", - "version": "0.18.0", + "version": "0.18.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -26,9 +26,18 @@ "dev": true, "requires": { "@babel/types": "7.0.0-beta.49", - "lodash": "^4.17.5", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "jsesc": "2.5.1", + "lodash": "4.17.5", + "source-map": "0.5.7", + "trim-right": "1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", + "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", + "dev": true + } } }, "@babel/helper-function-name": { @@ -66,8 +75,40 @@ "integrity": "sha1-lr3GtD4TSCASumaRsQGEktOWIsw=", "dev": true, "requires": { - "esutils": "^2.0.2", - "js-tokens": "^3.0.0" + "chalk": "2.4.1", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } } }, "@babel/parser": { @@ -85,7 +126,7 @@ "@babel/code-frame": "7.0.0-beta.49", "@babel/parser": "7.0.0-beta.49", "@babel/types": "7.0.0-beta.49", - "lodash": "^4.17.5" + "lodash": "4.17.5" } }, "@babel/traverse": { @@ -100,8 +141,27 @@ "@babel/helper-split-export-declaration": "7.0.0-beta.49", "@babel/parser": "7.0.0-beta.49", "@babel/types": "7.0.0-beta.49", - "invariant": "^2.2.0", - "lodash": "^4.17.5" + "debug": "3.1.0", + "globals": "11.7.0", + "invariant": "2.2.4", + "lodash": "4.17.5" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "dev": true + } } }, "@babel/types": { @@ -110,25 +170,25 @@ "integrity": "sha1-t+Oxw/TUz+Eb34yJ8e/V4WF7h6Y=", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.5", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "2.0.0" } }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "dev": true, "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" + "call-me-maybe": "1.0.1", + "glob-to-regexp": "0.3.0" } }, "@sinonjs/formatio": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", - "integrity": "sha1-hNt+nrVTHfGKjF4L+25EnlXmVLI=", + "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", "dev": true, "requires": { "samsam": "1.3.0" @@ -137,27 +197,27 @@ "@smashwilson/enzyme-adapter-react-16": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@smashwilson/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.2.tgz", - "integrity": "sha1-8NRWRn/qp5AwV8vF5PqsZKWoBsg=", + "integrity": "sha512-YGotyPAPOwi9vbRzvTutDgqYbBo5gX8mELNHPICcAXilV9XMa0yxqCQ6OY4ItIO5dPiRkc9RkjSYBr2M1fFOZw==", "dev": true, "requires": { - "@smashwilson/enzyme-adapter-utils": "^1.0.0", - "lodash": "^4.17.4", - "object.assign": "^4.1.0", - "object.values": "^1.0.4", - "prop-types": "^15.6.0", - "react-reconciler": "^0.7.0", - "react-test-renderer": "^16.0.0-0" + "@smashwilson/enzyme-adapter-utils": "1.0.0", + "lodash": "4.17.5", + "object.assign": "4.1.0", + "object.values": "1.0.4", + "prop-types": "15.6.2", + "react-reconciler": "0.7.0", + "react-test-renderer": "16.4.1" } }, "@smashwilson/enzyme-adapter-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@smashwilson/enzyme-adapter-utils/-/enzyme-adapter-utils-1.0.0.tgz", - "integrity": "sha1-H5zSVcvNm1Fd8WkCGgLbEMX8Ydc=", + "integrity": "sha512-/kQoTFU5bdbZbh6C9Ohxz1BgoHW+n2BX/kGUcS3DucGZfVNl4Em9lJqzd3aelyZSJz+cRX/FuE6ccnO6MnZc0Q==", "dev": true, "requires": { - "lodash": "^4.17.4", - "object.assign": "^4.1.0", - "prop-types": "^15.6.0" + "lodash": "4.17.5", + "object.assign": "4.1.0", + "prop-types": "15.6.2" } }, "@types/node": { @@ -178,7 +238,7 @@ "integrity": "sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw==", "dev": true, "requires": { - "acorn": "^5.0.3" + "acorn": "5.7.1" } }, "ajv": { @@ -186,10 +246,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" } }, "ajv-keywords": { @@ -198,16 +258,36 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", "dev": true }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, "amdefine": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, "ansi-escapes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha1-9zIHu4EgfXX9bIPxJa8m7qN4yjA=", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", "dev": true }, "ansi-regex": { @@ -222,11 +302,11 @@ }, "append-transform": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", "dev": true, "requires": { - "default-require-extensions": "^2.0.0" + "default-require-extensions": "2.0.0" } }, "aproba": { @@ -236,7 +316,7 @@ }, "archy": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, @@ -245,17 +325,35 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "delegates": "1.0.0", + "readable-stream": "2.3.3" } }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "sprintf-js": "1.0.3" + } + }, + "aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7", + "commander": "2.16.0" + }, + "dependencies": { + "commander": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz", + "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==", + "dev": true + } } }, "arr-diff": { @@ -276,13 +374,23 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.11.0" + } + }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "^1.0.1" + "array-uniq": "1.0.3" } }, "array-uniq": { @@ -303,8 +411,8 @@ "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" + "define-properties": "1.1.2", + "es-abstract": "1.11.0" } }, "arrify": { @@ -340,9 +448,15 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, "async": { "version": "1.5.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, @@ -360,9 +474,9 @@ "atom-babel6-transpiler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/atom-babel6-transpiler/-/atom-babel6-transpiler-1.2.0.tgz", - "integrity": "sha1-OcgHq8H9WqZDqvCut8DqE3j+Y1Y=", + "integrity": "sha512-lZucrjVyRtPAPPJxvICCEBsAC1qn48wUHaIlieriWCXTXLqtLC2PvkQU7vNvU2w1eZ7tw9m0lojZ8PbpVyWTvg==", "requires": { - "babel-core": "6.x" + "babel-core": "6.26.3" } }, "atom-mocha-test-runner": { @@ -371,10 +485,10 @@ "integrity": "sha1-qPZQm40pqAn8tv9H8FiEthLNxqk=", "dev": true, "requires": { - "etch": "^0.8.0", - "grim": "^2.0.1", - "less": "^2.7.1", - "mocha": "^3.0.0", + "etch": "0.8.0", + "grim": "2.0.2", + "less": "2.7.3", + "mocha": "3.5.3", "tmp": "0.0.31" }, "dependencies": { @@ -391,12 +505,12 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.2", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "has-flag": { @@ -409,7 +523,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", "requires": { - "has-flag": "^1.0.0" + "has-flag": "1.0.0" } } } @@ -424,14 +538,23 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", "integrity": "sha1-1NDpudv8p3vwjusKikcVUP454ok=" }, + "axobject-query": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.1.tgz", + "integrity": "sha1-Bd+nBa2orZ25k/polvItOVsLCgc=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7" + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" } }, "babel-core": { @@ -439,25 +562,25 @@ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", "integrity": "sha1-suLwnjQtDwyI4vAuBneUEl51wgc=", "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.1", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.5.1", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.5", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" }, "dependencies": { "babel-runtime": { @@ -465,8 +588,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-template": { @@ -474,11 +597,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.5" } }, "babel-traverse": { @@ -486,15 +609,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.5" } }, "babel-types": { @@ -502,10 +625,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "babylon": { @@ -531,10 +654,10 @@ "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=", "dev": true, "requires": { - "babel-code-frame": "^6.22.0", - "babel-traverse": "^6.23.1", - "babel-types": "^6.23.0", - "babylon": "^6.17.0" + "babel-code-frame": "6.26.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4" } }, "babel-generator": { @@ -542,14 +665,14 @@ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", "integrity": "sha1-GERAjTuPDTWkBOp6wYDwh6YBvZA=", "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.5", + "source-map": "0.5.7", + "trim-right": "1.0.1" }, "dependencies": { "babel-runtime": { @@ -557,8 +680,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-types": { @@ -566,10 +689,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "regenerator-runtime": { @@ -589,9 +712,9 @@ "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "esutils": "^2.0.2" + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "esutils": "2.0.2" }, "dependencies": { "babel-runtime": { @@ -599,8 +722,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-types": { @@ -608,10 +731,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "regenerator-runtime": { @@ -632,10 +755,10 @@ "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", "dev": true, "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helper-define-map": { @@ -644,10 +767,10 @@ "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.5" }, "dependencies": { "babel-runtime": { @@ -656,8 +779,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-types": { @@ -666,10 +789,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "regenerator-runtime": { @@ -691,11 +814,11 @@ "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helper-get-function-arity": { @@ -703,8 +826,8 @@ "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helper-hoist-variables": { @@ -713,8 +836,8 @@ "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helper-optimise-call-expression": { @@ -723,8 +846,8 @@ "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helper-replace-supers": { @@ -733,12 +856,12 @@ "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", "dev": true, "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" } }, "babel-helpers": { @@ -746,8 +869,8 @@ "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-template": "6.25.0" } }, "babel-messages": { @@ -755,7 +878,7 @@ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-chai-assert-async": { @@ -769,7 +892,7 @@ "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-istanbul": { @@ -778,10 +901,10 @@ "integrity": "sha1-NsWbIZLvzoHFs3gyG3QXWt0cmkU=", "dev": true, "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.13.0", - "find-up": "^2.1.0", - "istanbul-lib-instrument": "^1.10.1", - "test-exclude": "^4.2.1" + "babel-plugin-syntax-object-rest-spread": "6.13.0", + "find-up": "2.1.0", + "istanbul-lib-instrument": "1.10.1", + "test-exclude": "4.2.1" }, "dependencies": { "babylon": { @@ -802,13 +925,13 @@ "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", "dev": true, "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.0", - "semver": "^5.3.0" + "babel-generator": "6.26.1", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.18.0", + "istanbul-lib-coverage": "1.2.0", + "semver": "5.4.1" } } } @@ -818,8 +941,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-relay/-/babel-plugin-relay-1.6.0.tgz", "integrity": "sha1-oiTaUkNi1pA6UkIUobhAUw/fvSg=", "requires": { - "babel-runtime": "^6.23.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-plugin-syntax-class-properties": { @@ -853,10 +976,10 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-plugin-syntax-class-properties": "^6.8.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "babel-helper-function-name": "6.24.1", + "babel-plugin-syntax-class-properties": "6.13.0", + "babel-runtime": "6.25.0", + "babel-template": "6.25.0" } }, "babel-plugin-transform-es2015-arrow-functions": { @@ -865,7 +988,7 @@ "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-block-scoped-functions": { @@ -874,7 +997,7 @@ "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-block-scoping": { @@ -883,11 +1006,11 @@ "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.5" }, "dependencies": { "babel-runtime": { @@ -896,8 +1019,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-template": { @@ -906,11 +1029,11 @@ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.5" } }, "babel-traverse": { @@ -919,15 +1042,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.5" } }, "babel-types": { @@ -936,10 +1059,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "babylon": { @@ -968,15 +1091,15 @@ "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", "dev": true, "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "babel-helper-define-map": "6.26.0", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" } }, "babel-plugin-transform-es2015-computed-properties": { @@ -985,8 +1108,8 @@ "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-template": "6.25.0" } }, "babel-plugin-transform-es2015-destructuring": { @@ -995,7 +1118,7 @@ "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-for-of": { @@ -1004,7 +1127,7 @@ "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-function-name": { @@ -1013,9 +1136,9 @@ "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-plugin-transform-es2015-literals": { @@ -1024,7 +1147,7 @@ "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-modules-commonjs": { @@ -1032,10 +1155,10 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", "integrity": "sha1-WKeThjqefKhwvcWogRF/+sJ9tvM=", "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" }, "dependencies": { "babel-runtime": { @@ -1043,8 +1166,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babel-template": { @@ -1052,11 +1175,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.5" } }, "babel-traverse": { @@ -1064,15 +1187,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.5" } }, "babel-types": { @@ -1080,10 +1203,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" } }, "babylon": { @@ -1109,8 +1232,8 @@ "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", "dev": true, "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-parameters": { @@ -1119,12 +1242,12 @@ "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", "dev": true, "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" } }, "babel-plugin-transform-es2015-shorthand-properties": { @@ -1133,8 +1256,8 @@ "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-plugin-transform-es2015-spread": { @@ -1143,7 +1266,7 @@ "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es2015-template-literals": { @@ -1152,7 +1275,7 @@ "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es3-member-expression-literals": { @@ -1161,7 +1284,7 @@ "integrity": "sha1-cz00RPPsxBvvjtGmpOCWV7iWnrs=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-es3-property-literals": { @@ -1170,7 +1293,7 @@ "integrity": "sha1-sgeNWELiKr9A9z6M3pzTcRq9V1g=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-flow-strip-types": { @@ -1178,8 +1301,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", "requires": { - "babel-plugin-syntax-flow": "^6.18.0", - "babel-runtime": "^6.22.0" + "babel-plugin-syntax-flow": "6.18.0", + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-object-rest-spread": { @@ -1187,8 +1310,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" + "babel-plugin-syntax-object-rest-spread": "6.13.0", + "babel-runtime": "6.26.0" }, "dependencies": { "babel-runtime": { @@ -1196,8 +1319,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "regenerator-runtime": { @@ -1212,7 +1335,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=", "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-react-jsx": { @@ -1220,9 +1343,9 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", "requires": { - "babel-helper-builder-react-jsx": "^6.24.1", - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" + "babel-helper-builder-react-jsx": "6.26.0", + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-react-jsx-self": { @@ -1230,8 +1353,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz", "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=", "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-react-jsx-source": { @@ -1239,8 +1362,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz", "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=", "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.25.0" } }, "babel-plugin-transform-strict-mode": { @@ -1248,8 +1371,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-runtime": "6.25.0", + "babel-types": "6.25.0" } }, "babel-polyfill": { @@ -1258,9 +1381,9 @@ "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "regenerator-runtime": "^0.10.5" + "babel-runtime": "6.26.0", + "core-js": "2.5.0", + "regenerator-runtime": "0.10.5" }, "dependencies": { "babel-runtime": { @@ -1269,8 +1392,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" }, "dependencies": { "regenerator-runtime": { @@ -1289,34 +1412,34 @@ "integrity": "sha1-IvNY5mVAc6z2HkegUqd317zPA68=", "dev": true, "requires": { - "babel-plugin-check-es2015-constants": "^6.8.0", - "babel-plugin-syntax-class-properties": "^6.8.0", - "babel-plugin-syntax-flow": "^6.8.0", - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-plugin-syntax-trailing-function-commas": "^6.8.0", - "babel-plugin-transform-class-properties": "^6.8.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.8.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.8.0", - "babel-plugin-transform-es2015-block-scoping": "^6.8.0", - "babel-plugin-transform-es2015-classes": "^6.8.0", - "babel-plugin-transform-es2015-computed-properties": "^6.8.0", - "babel-plugin-transform-es2015-destructuring": "^6.8.0", - "babel-plugin-transform-es2015-for-of": "^6.8.0", - "babel-plugin-transform-es2015-function-name": "^6.8.0", - "babel-plugin-transform-es2015-literals": "^6.8.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.8.0", - "babel-plugin-transform-es2015-object-super": "^6.8.0", - "babel-plugin-transform-es2015-parameters": "^6.8.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.8.0", - "babel-plugin-transform-es2015-spread": "^6.8.0", - "babel-plugin-transform-es2015-template-literals": "^6.8.0", - "babel-plugin-transform-es3-member-expression-literals": "^6.8.0", - "babel-plugin-transform-es3-property-literals": "^6.8.0", - "babel-plugin-transform-flow-strip-types": "^6.8.0", - "babel-plugin-transform-object-rest-spread": "^6.8.0", - "babel-plugin-transform-react-display-name": "^6.8.0", - "babel-plugin-transform-react-jsx": "^6.8.0" + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-syntax-class-properties": "6.13.0", + "babel-plugin-syntax-flow": "6.18.0", + "babel-plugin-syntax-jsx": "6.18.0", + "babel-plugin-syntax-object-rest-spread": "6.13.0", + "babel-plugin-syntax-trailing-function-commas": "6.22.0", + "babel-plugin-transform-class-properties": "6.24.1", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.26.0", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es3-member-expression-literals": "6.22.0", + "babel-plugin-transform-es3-property-literals": "6.22.0", + "babel-plugin-transform-flow-strip-types": "6.22.0", + "babel-plugin-transform-object-rest-spread": "6.26.0", + "babel-plugin-transform-react-display-name": "6.25.0", + "babel-plugin-transform-react-jsx": "6.24.1" } }, "babel-preset-flow": { @@ -1324,7 +1447,7 @@ "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=", "requires": { - "babel-plugin-transform-flow-strip-types": "^6.22.0" + "babel-plugin-transform-flow-strip-types": "6.22.0" } }, "babel-preset-react": { @@ -1332,12 +1455,12 @@ "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", "requires": { - "babel-plugin-syntax-jsx": "^6.3.13", - "babel-plugin-transform-react-display-name": "^6.23.0", - "babel-plugin-transform-react-jsx": "^6.24.1", - "babel-plugin-transform-react-jsx-self": "^6.22.0", - "babel-plugin-transform-react-jsx-source": "^6.22.0", - "babel-preset-flow": "^6.23.0" + "babel-plugin-syntax-jsx": "6.18.0", + "babel-plugin-transform-react-display-name": "6.25.0", + "babel-plugin-transform-react-jsx": "6.24.1", + "babel-plugin-transform-react-jsx-self": "6.22.0", + "babel-plugin-transform-react-jsx-source": "6.22.0", + "babel-preset-flow": "6.23.0" } }, "babel-register": { @@ -1345,13 +1468,13 @@ "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" + "babel-core": "6.26.3", + "babel-runtime": "6.26.0", + "core-js": "2.5.0", + "home-or-tmp": "2.0.0", + "lodash": "4.17.5", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" }, "dependencies": { "babel-runtime": { @@ -1359,8 +1482,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "regenerator-runtime": { @@ -1375,8 +1498,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.25.0.tgz", "integrity": "sha1-M7mOql1IK7AajRqmtDetKwGuxBw=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.10.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.10.5" } }, "babel-template": { @@ -1384,11 +1507,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.25.0", - "babel-types": "^6.25.0", - "babylon": "^6.17.2", - "lodash": "^4.2.0" + "babel-runtime": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "lodash": "4.17.5" } }, "babel-traverse": { @@ -1396,15 +1519,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", "requires": { - "babel-code-frame": "^6.22.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-types": "^6.25.0", - "babylon": "^6.17.2", - "debug": "^2.2.0", - "globals": "^9.0.0", - "invariant": "^2.2.0", - "lodash": "^4.2.0" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.5" } }, "babel-types": { @@ -1412,10 +1535,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", "requires": { - "babel-runtime": "^6.22.0", - "esutils": "^2.0.2", - "lodash": "^4.2.0", - "to-fast-properties": "^1.0.1" + "babel-runtime": "6.25.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" }, "dependencies": { "to-fast-properties": { @@ -1441,13 +1564,13 @@ "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", "dev": true, "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" }, "dependencies": { "define-property": { @@ -1456,36 +1579,36 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -1496,7 +1619,7 @@ "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "optional": true, "requires": { - "tweetnacl": "^0.14.3" + "tweetnacl": "0.14.5" } }, "bl": { @@ -1504,8 +1627,8 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha1-oWCRFxcQPAdBDO9j71Gzl8Alr5w=", "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "readable-stream": "2.3.6", + "safe-buffer": "5.1.1" }, "dependencies": { "isarray": { @@ -1518,13 +1641,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -1532,7 +1655,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } } } @@ -1543,31 +1666,39 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "requires": { + "hoek": "4.2.1" + } + }, "brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.2", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -1576,7 +1707,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1599,7 +1730,7 @@ "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", "dev": true, "requires": { - "node-int64": "^0.4.0" + "node-int64": "0.4.0" } }, "buffer-alloc": { @@ -1607,8 +1738,8 @@ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.1.0.tgz", "integrity": "sha1-BVFNM78WVtNUDGhPZbEgLpDsowM=", "requires": { - "buffer-alloc-unsafe": "^0.1.0", - "buffer-fill": "^0.1.0" + "buffer-alloc-unsafe": "0.1.1", + "buffer-fill": "0.1.1" } }, "buffer-alloc-unsafe": { @@ -1638,26 +1769,26 @@ "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", "dev": true, "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" } }, "caching-transform": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-1.0.1.tgz", "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", "dev": true, "requires": { - "md5-hex": "^1.2.0", - "mkdirp": "^0.5.1", - "write-file-atomic": "^1.1.4" + "md5-hex": "1.3.0", + "mkdirp": "0.5.1", + "write-file-atomic": "1.3.4" } }, "call-me-maybe": { @@ -1672,7 +1803,7 @@ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "^0.2.0" + "callsites": "0.2.0" } }, "callsites": { @@ -1698,18 +1829,27 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, "chai": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", "dev": true, "requires": { - "assertion-error": "^1.0.1", - "check-error": "^1.0.1", - "deep-eql": "^3.0.0", - "get-func-name": "^2.0.0", - "pathval": "^1.0.0", - "type-detect": "^4.0.0" + "assertion-error": "1.1.0", + "check-error": "1.0.2", + "deep-eql": "3.0.1", + "get-func-name": "2.0.0", + "pathval": "1.1.0", + "type-detect": "4.0.8" } }, "chai-as-promised": { @@ -1718,7 +1858,7 @@ "integrity": "sha1-CGRdgl3rhpbuYXJdv1kMAS6wDKA=", "dev": true, "requires": { - "check-error": "^1.0.2" + "check-error": "1.0.2" } }, "chalk": { @@ -1726,11 +1866,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "chardet": { @@ -1750,7 +1890,7 @@ "resolved": "https://registry.npmjs.org/checksum/-/checksum-0.1.1.tgz", "integrity": "sha1-3GUn1MkL6FYNvR7Uzs8yl9Uo6ek=", "requires": { - "optimist": "~0.3.5" + "optimist": "0.3.7" } }, "cheerio": { @@ -1759,12 +1899,12 @@ "integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=", "dev": true, "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash": "^4.15.0", - "parse5": "^3.0.1" + "css-select": "1.2.0", + "dom-serializer": "0.1.0", + "entities": "1.1.1", + "htmlparser2": "3.9.2", + "lodash": "4.17.5", + "parse5": "3.0.3" } }, "chownr": { @@ -1784,10 +1924,10 @@ "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", "dev": true, "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" }, "dependencies": { "define-property": { @@ -1796,7 +1936,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -1804,7 +1944,7 @@ "classnames": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha1-Q5Nb/90pHzJtrQogUwmzjQD2UM4=" + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" }, "cli-cursor": { "version": "2.1.0", @@ -1812,7 +1952,7 @@ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "restore-cursor": "^2.0.0" + "restore-cursor": "2.0.0" } }, "cli-width": { @@ -1827,9 +1967,9 @@ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" }, "dependencies": { "string-width": { @@ -1838,9 +1978,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } } } @@ -1861,8 +2001,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "map-visit": "1.0.0", + "object-visit": "1.0.1" } }, "color-convert": { @@ -1870,7 +2010,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=", "requires": { - "color-name": "^1.1.1" + "color-name": "1.1.3" } }, "color-name": { @@ -1889,7 +2029,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } }, "commander": { @@ -1898,12 +2038,12 @@ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", "dev": true, "requires": { - "graceful-readlink": ">= 1.0.0" + "graceful-readlink": "1.0.1" } }, "commondir": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, @@ -1955,11 +2095,11 @@ "integrity": "sha1-EuFZFOqikgTlaGml7Oe54UktKuI=", "dev": true, "requires": { - "js-yaml": "^3.6.1", - "lcov-parse": "^0.0.10", - "log-driver": "^1.2.5", - "minimist": "^1.2.0", - "request": "^2.79.0" + "js-yaml": "3.11.0", + "lcov-parse": "0.0.10", + "log-driver": "1.2.7", + "minimist": "1.2.0", + "request": "2.87.0" } }, "cross-spawn": { @@ -1968,9 +2108,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "lru-cache": "4.1.2", + "shebang-command": "1.2.0", + "which": "1.3.0" }, "dependencies": { "lru-cache": { @@ -1979,8 +2119,8 @@ "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", "dev": true, "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "pseudomap": "1.0.2", + "yallist": "2.1.2" } }, "yallist": { @@ -1997,16 +2137,34 @@ "integrity": "sha1-UYO8R6CVWb78+YzEZXlkmZNZNy8=", "dev": true }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.1" + } + } + } + }, "css-select": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "dev": true, "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", + "boolbase": "1.0.0", + "css-what": "2.1.0", "domutils": "1.5.1", - "nth-check": "~1.0.1" + "nth-check": "1.0.1" } }, "css-what": { @@ -2015,12 +2173,18 @@ "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", "dev": true }, + "damerau-levenshtein": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz", + "integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=", + "dev": true + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "debug": { @@ -2033,7 +2197,7 @@ }, "debug-log": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", "dev": true }, @@ -2054,7 +2218,7 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "requires": { - "mimic-response": "^1.0.0" + "mimic-response": "1.0.0" } }, "dedent-js": { @@ -2069,7 +2233,7 @@ "integrity": "sha1-38lARACtHI/gI+faHfHBR8S0RN8=", "dev": true, "requires": { - "type-detect": "^4.0.0" + "type-detect": "4.0.8" } }, "deep-equal": { @@ -2091,11 +2255,11 @@ }, "default-require-extensions": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", "dev": true, "requires": { - "strip-bom": "^3.0.0" + "strip-bom": "3.0.0" } }, "define-properties": { @@ -2104,8 +2268,8 @@ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", "dev": true, "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" + "foreach": "2.0.5", + "object-keys": "1.0.11" } }, "define-property": { @@ -2114,37 +2278,37 @@ "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "is-descriptor": "1.0.2", + "isobject": "3.0.1" }, "dependencies": { "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -2155,13 +2319,13 @@ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" } }, "delayed-stream": { @@ -2185,7 +2349,7 @@ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "requires": { - "repeating": "^2.0.0" + "repeating": "2.0.1" } }, "detect-libc": { @@ -2211,8 +2375,8 @@ "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "esutils": "2.0.2", + "isarray": "1.0.0" }, "dependencies": { "isarray": { @@ -2229,8 +2393,8 @@ "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "dev": true, "requires": { - "domelementtype": "~1.1.1", - "entities": "~1.1.1" + "domelementtype": "1.1.3", + "entities": "1.1.1" }, "dependencies": { "domelementtype": { @@ -2259,7 +2423,7 @@ "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", "dev": true, "requires": { - "domelementtype": "1" + "domelementtype": "1.3.0" } }, "domutils": { @@ -2268,8 +2432,8 @@ "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "dev": true, "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "dom-serializer": "0.1.0", + "domelementtype": "1.3.0" } }, "dugite": { @@ -2277,12 +2441,12 @@ "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.66.0.tgz", "integrity": "sha1-X9q2aDwLU4p5vb7Emenz0+pyEPk=", "requires": { - "checksum": "^0.1.1", - "mkdirp": "^0.5.1", - "progress": "^2.0.0", - "request": "^2.86.0", - "rimraf": "^2.5.4", - "tar": "^4.0.2" + "checksum": "0.1.1", + "mkdirp": "0.5.1", + "progress": "2.0.0", + "request": "2.87.0", + "rimraf": "2.6.2", + "tar": "4.4.4" } }, "ecc-jsbn": { @@ -2291,19 +2455,33 @@ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "optional": true, "requires": { - "jsbn": "~0.1.0" + "jsbn": "0.1.1" } }, "electron-devtools-installer": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-2.2.4.tgz", - "integrity": "sha1-JhpQM343Eh0zi5ZvB5IutJOah2M=", + "integrity": "sha512-b5kcM3hmUqn64+RUcHjjr8ZMpHS2WJ5YO0pnG9+P/RTdx46of/JrEjuciHWux6pE+On6ynWhHJF53j/EDJN0PA==", "dev": true, "requires": { "7zip": "0.0.6", "cross-unzip": "0.0.2", - "rimraf": "^2.5.2", - "semver": "^5.3.0" + "rimraf": "2.6.2", + "semver": "5.4.1" + } + }, + "emoji-regex": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz", + "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==", + "dev": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "0.4.18" } }, "end-of-stream": { @@ -2311,7 +2489,7 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", "requires": { - "once": "^1.4.0" + "once": "1.4.0" } }, "entities": { @@ -2326,22 +2504,22 @@ "integrity": "sha1-CXGr0Wfy1L8/W9UIIp4cS23FBHk=", "dev": true, "requires": { - "cheerio": "^1.0.0-rc.2", - "function.prototype.name": "^1.0.3", - "has": "^1.0.1", - "is-boolean-object": "^1.0.0", - "is-callable": "^1.1.3", - "is-number-object": "^1.0.3", - "is-string": "^1.0.4", - "is-subset": "^0.1.1", - "lodash": "^4.17.4", - "object-inspect": "^1.5.0", - "object-is": "^1.0.1", - "object.assign": "^4.1.0", - "object.entries": "^1.0.4", - "object.values": "^1.0.4", - "raf": "^3.4.0", - "rst-selector-parser": "^2.2.3" + "cheerio": "1.0.0-rc.2", + "function.prototype.name": "1.1.0", + "has": "1.0.1", + "is-boolean-object": "1.0.0", + "is-callable": "1.1.3", + "is-number-object": "1.0.3", + "is-string": "1.0.4", + "is-subset": "0.1.1", + "lodash": "4.17.5", + "object-inspect": "1.5.0", + "object-is": "1.0.1", + "object.assign": "4.1.0", + "object.entries": "1.0.4", + "object.values": "1.0.4", + "raf": "3.4.0", + "rst-selector-parser": "2.2.3" } }, "errno": { @@ -2351,7 +2529,7 @@ "dev": true, "optional": true, "requires": { - "prr": "~0.0.0" + "prr": "0.0.0" } }, "error": { @@ -2360,9 +2538,9 @@ "integrity": "sha1-v2n/JR+0onnBmtzNqmth6Q2b8So=", "dev": true, "requires": { - "camelize": "^1.0.0", - "string-template": "~0.2.0", - "xtend": "~4.0.0" + "camelize": "1.0.0", + "string-template": "0.2.1", + "xtend": "4.0.1" } }, "error-ex": { @@ -2371,7 +2549,7 @@ "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { - "is-arrayish": "^0.2.1" + "is-arrayish": "0.2.1" } }, "es-abstract": { @@ -2380,11 +2558,11 @@ "integrity": "sha1-zOh9UY8Elok7GjDNhGGDVTVIBoE=", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", - "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "es-to-primitive": "1.1.1", + "function-bind": "1.1.1", + "has": "1.0.1", + "is-callable": "1.1.3", + "is-regex": "1.0.4" } }, "es-to-primitive": { @@ -2393,9 +2571,9 @@ "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", "dev": true, "requires": { - "is-callable": "^1.1.1", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.1" + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" } }, "escape-string-regexp": { @@ -2409,44 +2587,44 @@ "integrity": "sha512-D5nG2rErquLUstgUaxJlWB5+gu+U/3VDY0fk/Iuq8y9CUFy/7Y6oF4N2cR1tV8knzQvciIbfqfohd359xTLIKQ==", "dev": true, "requires": { - "ajv": "^6.5.0", - "babel-code-frame": "^6.26.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^4.0.0", - "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.5.0", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^5.2.0", - "is-resolvable": "^1.1.0", - "js-yaml": "^3.11.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.5", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^1.1.0", - "require-uncached": "^1.0.3", - "semver": "^5.5.0", - "string.prototype.matchall": "^2.0.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^4.0.3", - "text-table": "^0.2.0" + "ajv": "6.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "cross-spawn": "6.0.5", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "4.0.0", + "eslint-visitor-keys": "1.0.0", + "espree": "4.0.0", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.7.0", + "ignore": "3.3.10", + "imurmurhash": "0.1.4", + "inquirer": "5.2.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.11.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.5", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.5.0", + "string.prototype.matchall": "2.0.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.3", + "text-table": "0.2.0" }, "dependencies": { "ajv": { @@ -2455,10 +2633,10 @@ "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.1" + "fast-deep-equal": "2.0.1", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.2.2" } }, "ansi-regex": { @@ -2473,7 +2651,7 @@ "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.1" } }, "chalk": { @@ -2482,9 +2660,9 @@ "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "cross-spawn": { @@ -2493,11 +2671,11 @@ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "nice-try": "1.0.4", + "path-key": "2.0.1", + "semver": "5.5.0", + "shebang-command": "1.2.0", + "which": "1.3.0" } }, "debug": { @@ -2515,7 +2693,7 @@ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "esutils": "^2.0.2" + "esutils": "2.0.2" } }, "fast-deep-equal": { @@ -2548,7 +2726,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } }, "supports-color": { @@ -2557,7 +2735,7 @@ "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -2568,13 +2746,13 @@ "integrity": "sha1-n2yIvtUXwGDuqcQ0BqBXMw2whJc=", "dev": true, "requires": { - "babel-eslint": "^7.1.1", - "eslint-plugin-babel": "^4.0.1", - "eslint-plugin-flowtype": "^2.30.0", - "eslint-plugin-jasmine": "^2.2.0", - "eslint-plugin-prefer-object-spread": "^1.1.0", - "eslint-plugin-react": "^6.9.0", - "fbjs-eslint-utils": "^1.0.0" + "babel-eslint": "7.2.3", + "eslint-plugin-babel": "4.1.2", + "eslint-plugin-flowtype": "2.46.3", + "eslint-plugin-jasmine": "2.9.3", + "eslint-plugin-prefer-object-spread": "1.2.1", + "eslint-plugin-react": "6.10.3", + "fbjs-eslint-utils": "1.0.0" } }, "eslint-plugin-babel": { @@ -2589,7 +2767,7 @@ "integrity": "sha1-foQTHYfvGLSWsYEESFkzdIYLTo4=", "dev": true, "requires": { - "lodash": "^4.15.0" + "lodash": "4.17.5" } }, "eslint-plugin-jasmine": { @@ -2598,6 +2776,42 @@ "integrity": "sha1-Bb86uCfXkWkc7ujCGVm5wNVqaww=", "dev": true }, + "eslint-plugin-jsx-a11y": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.1.tgz", + "integrity": "sha512-JsxNKqa3TwmPypeXNnI75FntkUktGzI1wSa1LgNZdSOMI+B4sxnr1lSF8m8lPiz4mKiC+14ysZQM4scewUrP7A==", + "dev": true, + "requires": { + "aria-query": "3.0.0", + "array-includes": "3.0.3", + "ast-types-flow": "0.0.7", + "axobject-query": "2.0.1", + "damerau-levenshtein": "1.0.4", + "emoji-regex": "6.5.1", + "has": "1.0.3", + "jsx-ast-utils": "2.0.1" + }, + "dependencies": { + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "jsx-ast-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", + "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", + "dev": true, + "requires": { + "array-includes": "3.0.3" + } + } + } + }, "eslint-plugin-prefer-object-spread": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-object-spread/-/eslint-plugin-prefer-object-spread-1.2.1.tgz", @@ -2610,11 +2824,11 @@ "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", "dev": true, "requires": { - "array.prototype.find": "^2.0.1", - "doctrine": "^1.2.2", - "has": "^1.0.1", - "jsx-ast-utils": "^1.3.4", - "object.assign": "^4.0.4" + "array.prototype.find": "2.0.4", + "doctrine": "1.5.0", + "has": "1.0.1", + "jsx-ast-utils": "1.4.1", + "object.assign": "4.1.0" } }, "eslint-scope": { @@ -2623,8 +2837,8 @@ "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "esrecurse": "4.2.1", + "estraverse": "4.2.0" } }, "eslint-visitor-keys": { @@ -2639,8 +2853,8 @@ "integrity": "sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg==", "dev": true, "requires": { - "acorn": "^5.6.0", - "acorn-jsx": "^4.1.1" + "acorn": "5.7.1", + "acorn-jsx": "4.1.1" } }, "esprima": { @@ -2652,10 +2866,10 @@ "esquery": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { - "estraverse": "^4.0.0" + "estraverse": "4.2.0" } }, "esrecurse": { @@ -2664,7 +2878,7 @@ "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", "dev": true, "requires": { - "estraverse": "^4.1.0" + "estraverse": "4.2.0" } }, "estraverse": { @@ -2684,7 +2898,7 @@ "integrity": "sha1-VPYZV0NG+KPueXP1T7vQG1YnItY=", "dev": true, "requires": { - "virtual-dom": "^2.0.1" + "virtual-dom": "2.1.1" } }, "ev-store": { @@ -2693,13 +2907,13 @@ "integrity": "sha1-GrDH+CE2UF3XSzHRdwHLK+bSZVg=", "dev": true, "requires": { - "individual": "^3.0.0" + "individual": "3.0.0" } }, "event-kit": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.0.tgz", - "integrity": "sha1-L3KxHitfUzzByVA4cEBiSkoCX+g=" + "integrity": "sha512-tUDxeNC9JzN2Tw/f8mLtksY34v1hHmaR7lV7X4p04XSjaeUhFMfzjF6Nwov9e0EKGEx63BaKcgXKxjpQaPo0wg==" }, "execa": { "version": "0.7.0", @@ -2707,13 +2921,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" } }, "expand-brackets": { @@ -2722,13 +2936,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -2737,7 +2951,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -2746,7 +2960,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -2767,8 +2981,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -2777,7 +2991,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -2785,21 +2999,21 @@ "external-editor": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha1-BFURz9jRM/OEZnPRBHwVTiFK09U=", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" + "chardet": "0.4.2", + "iconv-lite": "0.4.18", + "tmp": "0.0.33" }, "dependencies": { "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "os-tmpdir": "~1.0.2" + "os-tmpdir": "1.0.2" } } } @@ -2810,14 +3024,14 @@ "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", "dev": true, "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -2826,7 +3040,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -2835,36 +3049,36 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -2885,11 +3099,11 @@ "integrity": "sha512-wSyW1TBK3ia5V+te0rGPXudeMHoUQW6O5Y9oATiaGhpENmEifPDlOdhpsnlj5HoG6ttIvGiY1DdCmI9X2xGMhg==", "dev": true, "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.1", - "micromatch": "^3.1.10" + "@mrmlnc/readdir-enhanced": "2.2.1", + "glob-parent": "3.1.0", + "is-glob": "4.0.0", + "merge2": "1.2.1", + "micromatch": "3.1.10" } }, "fast-json-stable-stringify": { @@ -2909,7 +3123,7 @@ "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", "dev": true, "requires": { - "bser": "^2.0.0" + "bser": "2.0.0" } }, "fbjs": { @@ -2917,13 +3131,13 @@ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.9" + "core-js": "1.2.7", + "isomorphic-fetch": "2.2.1", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "promise": "7.3.1", + "setimmediate": "1.0.5", + "ua-parser-js": "0.7.14" }, "dependencies": { "core-js": { @@ -2936,8 +3150,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" + "encoding": "0.1.12", + "is-stream": "1.1.0" } } } @@ -2954,7 +3168,7 @@ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5" + "escape-string-regexp": "1.0.5" } }, "file-entry-cache": { @@ -2963,8 +3177,8 @@ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "flat-cache": "1.3.0", + "object-assign": "4.1.1" } }, "fill-range": { @@ -2973,10 +3187,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -2985,20 +3199,20 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } }, "find-cache-dir": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", "dev": true, "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" + "commondir": "1.0.1", + "make-dir": "1.3.0", + "pkg-dir": "2.0.0" } }, "find-up": { @@ -3007,7 +3221,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "^2.0.0" + "locate-path": "2.0.0" } }, "flat-cache": { @@ -3016,10 +3230,10 @@ "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "dev": true, "requires": { - "circular-json": "^0.3.1", - "del": "^2.0.2", - "graceful-fs": "^4.1.2", - "write": "^0.2.1" + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" } }, "for-in": { @@ -3036,11 +3250,40 @@ }, "foreground-child": { "version": "1.5.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", "dev": true, "requires": { - "signal-exit": "^3.0.0" + "cross-spawn": "4.0.2", + "signal-exit": "3.0.2" + }, + "dependencies": { + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "requires": { + "lru-cache": "4.1.3", + "which": "1.3.0" + } + }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } } }, "forever-agent": { @@ -3053,9 +3296,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "^0.4.0", + "asynckit": "0.4.0", "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "mime-types": "2.1.16" } }, "fragment-cache": { @@ -3064,7 +3307,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "^0.2.2" + "map-cache": "0.2.2" } }, "fs-constants": { @@ -3075,11 +3318,11 @@ "fs-extra": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha1-DYUhIuW8W+tFP7Ao6cDJvzY0DJQ=", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" } }, "fs-minipass": { @@ -3087,7 +3330,7 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", "integrity": "sha1-BsJ3IYRU7CiN93raVKA7hwKqy50=", "requires": { - "minipass": "^2.2.1" + "minipass": "2.3.3" } }, "fs.realpath": { @@ -3098,7 +3341,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "function.prototype.name": { @@ -3107,9 +3350,9 @@ "integrity": "sha1-i9djzAr4YKhZzF1JOE10uTLNIyc=", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "is-callable": "^1.1.3" + "define-properties": "1.1.2", + "function-bind": "1.1.1", + "is-callable": "1.1.3" } }, "functional-red-black-tree": { @@ -3123,14 +3366,14 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" }, "dependencies": { "string-width": { @@ -3138,9 +3381,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } } } @@ -3174,7 +3417,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "github-from-package": { @@ -3187,12 +3430,12 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "glob-parent": { @@ -3201,8 +3444,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "3.1.0", + "path-dirname": "1.0.2" }, "dependencies": { "is-glob": { @@ -3211,7 +3454,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } } } @@ -3228,8 +3471,8 @@ "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", "dev": true, "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" + "min-document": "2.19.0", + "process": "0.5.2" } }, "globals": { @@ -3243,12 +3486,12 @@ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, "graceful-fs": { @@ -3267,18 +3510,18 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.13.2.tgz", "integrity": "sha1-THQK48Iigj5wBAlvgy57k7IQgnA=", "requires": { - "iterall": "^1.2.1" + "iterall": "1.2.2" } }, "graphql-compiler": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/graphql-compiler/-/graphql-compiler-1.6.0.tgz", - "integrity": "sha1-JPFGzfiLgOBFMipXKhpdhLnCqdU=", + "integrity": "sha512-9r6IHZYA9N+teTfiIC2X4WcHgRjzfSCtEI4Sxe80eMOckvWhT84d2rESQfMpJl+zelxyqFTs+HTHnApRRwy0/Q==", "dev": true, "requires": { - "chalk": "^1.1.1", - "fb-watchman": "^2.0.0", - "immutable": "~3.7.6" + "chalk": "1.1.3", + "fb-watchman": "2.0.0", + "immutable": "3.7.6" } }, "grim": { @@ -3287,7 +3530,7 @@ "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==", "dev": true, "requires": { - "event-kit": "^2.0.0" + "event-kit": "2.5.0" } }, "growl": { @@ -3298,22 +3541,39 @@ }, "handlebars": { "version": "4.0.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { - "async": "^1.4.0", - "source-map": "^0.4.4", - "uglify-js": "^2.6" + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" }, "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.10", + "wordwrap": "0.0.3" + } + }, "source-map": { "version": "0.4.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { - "amdefine": ">=0.0.4" + "amdefine": "1.0.1" } } } @@ -3328,8 +3588,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "requires": { - "ajv": "^5.1.0", - "har-schema": "^2.0.0" + "ajv": "5.5.2", + "har-schema": "2.0.0" } }, "has": { @@ -3338,7 +3598,7 @@ "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", "dev": true, "requires": { - "function-bind": "^1.0.2" + "function-bind": "1.1.1" } }, "has-ansi": { @@ -3346,7 +3606,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "has-flag": { @@ -3371,9 +3631,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" } }, "has-values": { @@ -3382,8 +3642,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "is-number": "3.0.0", + "kind-of": "4.0.0" }, "dependencies": { "kind-of": { @@ -3392,11 +3652,22 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" + } + }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", @@ -3412,19 +3683,24 @@ "deep-equal": "0.2.1" } }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" + }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" } }, "hosted-git-info": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha1-IyNbKasjDFdqqw1PE/wEawsDgiI=", + "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", "dev": true }, "htmlparser2": { @@ -3433,12 +3709,12 @@ "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", "dev": true, "requires": { - "domelementtype": "^1.3.0", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^2.0.2" + "domelementtype": "1.3.0", + "domhandler": "2.4.1", + "domutils": "1.5.1", + "entities": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.3" } }, "http-signature": { @@ -3446,16 +3722,15 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.1" } }, "iconv-lite": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==", - "dev": true + "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" }, "ignore": { "version": "3.3.10", @@ -3493,8 +3768,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -3513,19 +3788,19 @@ "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.1.0", - "figures": "^2.0.0", - "lodash": "^4.3.0", + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.5", "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^5.5.2", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" + "run-async": "2.3.0", + "rxjs": "5.5.11", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" }, "dependencies": { "ansi-regex": { @@ -3540,7 +3815,7 @@ "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.1" } }, "chalk": { @@ -3549,9 +3824,9 @@ "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "strip-ansi": { @@ -3560,7 +3835,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } }, "supports-color": { @@ -3569,7 +3844,7 @@ "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3579,7 +3854,7 @@ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", "requires": { - "loose-envify": "^1.0.0" + "loose-envify": "1.3.1" } }, "invert-kv": { @@ -3594,7 +3869,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -3603,7 +3878,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -3631,7 +3906,7 @@ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { - "builtin-modules": "^1.0.0" + "builtin-modules": "1.1.1" } }, "is-callable": { @@ -3646,7 +3921,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -3655,7 +3930,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -3669,18 +3944,18 @@ "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" }, "dependencies": { "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } @@ -3702,7 +3977,7 @@ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "is-fullwidth-code-point": { @@ -3710,7 +3985,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "is-glob": { @@ -3719,7 +3994,7 @@ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { - "is-extglob": "^2.1.1" + "is-extglob": "2.1.1" } }, "is-number": { @@ -3728,7 +4003,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -3737,7 +4012,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -3760,7 +4035,7 @@ "integrity": "sha1-dkZiRnH9fqVYzNmieVGC8pWPGyQ=", "dev": true, "requires": { - "is-number": "^4.0.0" + "is-number": "4.0.0" }, "dependencies": { "is-number": { @@ -3780,10 +4055,10 @@ "is-path-in-cwd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha1-WsSLNF72dTOb1sekipEhELJBz1I=", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "requires": { - "is-path-inside": "^1.0.0" + "is-path-inside": "1.0.1" } }, "is-path-inside": { @@ -3792,7 +4067,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "^1.0.1" + "path-is-inside": "1.0.2" } }, "is-plain-object": { @@ -3800,7 +4075,7 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "is-promise": { @@ -3815,7 +4090,7 @@ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { - "has": "^1.0.1" + "has": "1.0.1" } }, "is-resolvable": { @@ -3885,7 +4160,19 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { - "whatwg-fetch": ">=0.10.0" + "node-fetch": "1.7.3", + "whatwg-fetch": "2.0.4" + }, + "dependencies": { + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + } } }, "isstream": { @@ -3901,11 +4188,11 @@ }, "istanbul-lib-hook": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.0.tgz", "integrity": "sha512-qm3dt628HKpCVtIjbdZLuQyXn0+LO8qz+YHQDfkeXuSk5D+p299SEV5DrnUUnPi2SXvdMmWapMYWiuE75o2rUQ==", "dev": true, "requires": { - "append-transform": "^1.0.0" + "append-transform": "1.0.0" } }, "istanbul-lib-instrument": { @@ -3919,8 +4206,8 @@ "@babel/template": "7.0.0-beta.49", "@babel/traverse": "7.0.0-beta.49", "@babel/types": "7.0.0-beta.49", - "istanbul-lib-coverage": "^2.0.0", - "semver": "^5.5.0" + "istanbul-lib-coverage": "2.0.0", + "semver": "5.5.0" }, "dependencies": { "ansi-styles": { @@ -3928,7 +4215,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.1" } }, "chalk": { @@ -3936,9 +4223,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "debug": { @@ -3970,36 +4257,58 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } }, "istanbul-lib-report": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.0.tgz", "integrity": "sha512-RiELmy9oIRYUv36ITOAhVum9PUvuj6bjyXVEKEHNiD1me6qXtxfx7vSEJWnjOGk2QmYw/GRFjLXWJv3qHpLceQ==", "dev": true, "requires": { - "istanbul-lib-coverage": "^2.0.0", - "make-dir": "^1.3.0" + "istanbul-lib-coverage": "2.0.0", + "make-dir": "1.3.0", + "supports-color": "5.4.0" + }, + "dependencies": { + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } } }, "istanbul-lib-source-maps": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-2.0.0.tgz", "integrity": "sha512-jenUeC0gMSSMGkvqD9xuNfs3nD7XWeXLhqaIkqHsNZ3DJBWPdlKEydE7Ya5aTgdWjrEQhrCYTv+J606cGC2vuQ==", "dev": true, "requires": { - "istanbul-lib-coverage": "^2.0.0", - "make-dir": "^1.3.0", - "rimraf": "^2.6.2", - "source-map": "^0.6.1" + "debug": "3.1.0", + "istanbul-lib-coverage": "2.0.0", + "make-dir": "1.3.0", + "rimraf": "2.6.2", + "source-map": "0.6.1" }, "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "source-map": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } @@ -4007,11 +4316,11 @@ }, "istanbul-reports": { "version": "1.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.0.tgz", "integrity": "sha512-HeZG0WHretI9FXBni5wZ9DOgNziqDCEwetxnme5k1Vv5e81uTqcsy3fMH99gXGDGKr1ea87TyGseDMa2h4HEUA==", "dev": true, "requires": { - "handlebars": "^4.0.11" + "handlebars": "4.0.11" } }, "iterall": { @@ -4054,8 +4363,8 @@ "integrity": "sha1-WXwai9VxUvJtYizkEXhRpR9euu8=", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "1.0.10", + "esprima": "4.0.0" } }, "jsbn": { @@ -4069,12 +4378,6 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -4092,7 +4395,7 @@ "dev": true, "optional": true, "requires": { - "jsonify": "~0.0.0" + "jsonify": "0.0.0" } }, "json-stable-stringify-without-jsonify": { @@ -4122,7 +4425,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "requires": { - "graceful-fs": "^4.1.6" + "graceful-fs": "4.1.11" } }, "jsonify": { @@ -4152,7 +4455,7 @@ "just-extend": { "version": "1.1.27", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha1-7G55QQ/5FORyZSq/oOYDwD1g6QU=", + "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", "dev": true }, "keytar": { @@ -4161,7 +4464,7 @@ "integrity": "sha1-igamV3/fY3PgqmsRInfmPex3/RI=", "requires": { "nan": "2.8.0", - "prebuild-install": "^2.4.1" + "prebuild-install": "2.5.3" } }, "kind-of": { @@ -4170,13 +4473,18 @@ "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", "dev": true }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "invert-kv": "^1.0.0" + "invert-kv": "1.0.0" } }, "lcov-parse": { @@ -4191,14 +4499,14 @@ "integrity": "sha1-zBJg9RyQCp7A2R+2mYE54CUHtjs=", "dev": true, "requires": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "mime": "^1.2.11", - "mkdirp": "^0.5.0", - "promise": "^7.1.1", + "errno": "0.1.4", + "graceful-fs": "4.1.11", + "image-size": "0.5.5", + "mime": "1.4.1", + "mkdirp": "0.5.1", + "promise": "7.3.1", "request": "2.81.0", - "source-map": "^0.5.3" + "source-map": "0.5.7" }, "dependencies": { "ajv": { @@ -4208,8 +4516,8 @@ "dev": true, "optional": true, "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" + "co": "4.6.0", + "json-stable-stringify": "1.0.1" } }, "assert-plus": { @@ -4232,7 +4540,7 @@ "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, "requires": { - "hoek": "2.x.x" + "hoek": "2.16.3" } }, "combined-stream": { @@ -4249,7 +4557,7 @@ "dev": true, "optional": true, "requires": { - "boom": "2.x.x" + "boom": "2.10.1" } }, "form-data": { @@ -4259,9 +4567,9 @@ "dev": true, "optional": true, "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.16" }, "dependencies": { "combined-stream": { @@ -4271,7 +4579,7 @@ "dev": true, "optional": true, "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } } } @@ -4290,8 +4598,8 @@ "dev": true, "optional": true, "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" + "ajv": "4.11.8", + "har-schema": "1.0.5" } }, "hawk": { @@ -4301,10 +4609,10 @@ "dev": true, "optional": true, "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" } }, "hoek": { @@ -4320,9 +4628,9 @@ "dev": true, "optional": true, "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.14.1" } }, "performance-now": { @@ -4346,28 +4654,28 @@ "dev": true, "optional": true, "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~4.2.1", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "performance-now": "^0.2.0", - "qs": "~6.4.0", - "safe-buffer": "^5.0.1", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.0.0" + "aws-sign2": "0.6.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.16", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.6", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" }, "dependencies": { "combined-stream": { @@ -4377,7 +4685,7 @@ "dev": true, "optional": true, "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } }, "tough-cookie": { @@ -4387,7 +4695,7 @@ "dev": true, "optional": true, "requires": { - "punycode": "^1.4.1" + "punycode": "1.4.1" } } } @@ -4399,7 +4707,7 @@ "dev": true, "optional": true, "requires": { - "hoek": "2.x.x" + "hoek": "2.16.3" } }, "tough-cookie": { @@ -4417,8 +4725,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "1.1.2", + "type-check": "0.3.2" } }, "load-json-file": { @@ -4427,10 +4735,10 @@ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" } }, "locate-path": { @@ -4439,8 +4747,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "2.0.0", + "path-exists": "3.0.0" } }, "lodash": { @@ -4454,8 +4762,8 @@ "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", "dev": true, "requires": { - "lodash._basecopy": "^3.0.0", - "lodash.keys": "^3.0.0" + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" } }, "lodash._basecopy": { @@ -4488,9 +4796,9 @@ "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", "dev": true, "requires": { - "lodash._baseassign": "^3.0.0", - "lodash._basecreate": "^3.0.0", - "lodash._isiterateecall": "^3.0.0" + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" } }, "lodash.flattendeep": { @@ -4529,9 +4837,9 @@ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" } }, "lodash.memoize": { @@ -4556,12 +4864,17 @@ "integrity": "sha1-5AqMTR8UtTaqA+QqU3x6268MIL4=", "dev": true }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, "loose-envify": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "^3.0.0" + "js-tokens": "3.0.2" } }, "lru-cache": { @@ -4572,16 +4885,16 @@ }, "make-dir": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { - "pify": "^3.0.0" + "pify": "3.0.0" }, "dependencies": { "pify": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true } @@ -4599,21 +4912,21 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "^1.0.0" + "object-visit": "1.0.1" } }, "md5-hex": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz", "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", "dev": true, "requires": { - "md5-o-matic": "^0.1.1" + "md5-o-matic": "0.1.1" } }, "md5-o-matic": { "version": "0.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", "dev": true }, @@ -4623,21 +4936,21 @@ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "1.2.0" } }, "merge-source-map": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", "dev": true, "requires": { - "source-map": "^0.6.1" + "source-map": "0.6.1" }, "dependencies": { "source-map": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } @@ -4652,22 +4965,22 @@ "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.9", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "mime": { @@ -4687,7 +5000,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=", "requires": { - "mime-db": "~1.29.0" + "mime-db": "1.29.0" } }, "mimic-fn": { @@ -4707,7 +5020,7 @@ "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", "dev": true, "requires": { - "dom-walk": "^0.1.0" + "dom-walk": "0.1.1" } }, "minimatch": { @@ -4715,7 +5028,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.8" } }, "minimist": { @@ -4726,10 +5039,10 @@ "minipass": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz", - "integrity": "sha1-p9zIt7gz9dNodZzOVE3MtV9Q8jM=", + "integrity": "sha512-/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw==", "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" + "safe-buffer": "5.1.2", + "yallist": "3.0.2" }, "dependencies": { "safe-buffer": { @@ -4744,7 +5057,7 @@ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz", "integrity": "sha1-EeE2WM5GvDpwomeqxYNZ0eDCnOs=", "requires": { - "minipass": "^2.2.1" + "minipass": "2.3.3" } }, "mixin-deep": { @@ -4753,8 +5066,8 @@ "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", "dev": true, "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "for-in": "1.0.2", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -4763,7 +5076,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -4791,20 +5104,61 @@ "requires": { "browser-stdout": "1.3.0", "commander": "2.9.0", + "debug": "2.6.8", "diff": "3.2.0", "escape-string-regexp": "1.0.5", + "glob": "7.1.1", "growl": "1.9.2", "he": "1.1.1", "json3": "3.3.2", "lodash.create": "3.1.1", - "mkdirp": "0.5.1" + "mkdirp": "0.5.1", + "supports-color": "3.1.2" }, "dependencies": { + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "diff": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", "dev": true + }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } } } }, @@ -4814,7 +5168,7 @@ "integrity": "sha1-gpOC/8Bla2Z+e+ZQoJSgba69Uk8=", "dev": true, "requires": { - "request-json": "^0.6.1" + "request-json": "0.6.3" }, "dependencies": { "mime-db": { @@ -4827,7 +5181,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "requires": { - "mime-db": "~1.33.0" + "mime-db": "1.33.0" } }, "request": { @@ -4835,28 +5189,28 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", - "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "hawk": "~6.0.2", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", - "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "stringstream": "~0.0.5", - "tough-cookie": "~2.3.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.6", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" } } } @@ -4867,10 +5221,10 @@ "integrity": "sha1-kBmEuev51g9xXvDo4EwG5KsSJFc=", "dev": true, "requires": { - "debug": "^2.2.0", - "mkdirp": "~0.5.1", - "mocha": "^2.2.5", - "xml": "^1.0.0" + "debug": "2.6.9", + "mkdirp": "0.5.1", + "mocha": "2.5.3", + "xml": "1.0.1" }, "dependencies": { "commander": { @@ -4897,8 +5251,8 @@ "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", "dev": true, "requires": { - "inherits": "2", - "minimatch": "0.3" + "inherits": "2.0.3", + "minimatch": "0.3.0" } }, "minimatch": { @@ -4907,8 +5261,8 @@ "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", "dev": true, "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "lru-cache": "2.7.3", + "sigmund": "1.0.1" } }, "mocha": { @@ -4987,18 +5341,18 @@ "integrity": "sha1-h59xUMstq3pHElkGbBBO7m4Pp8I=", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-odd": "2.0.0", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "is-extendable": { @@ -5006,7 +5360,7 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -5023,10 +5377,10 @@ "integrity": "sha1-bnsPTmi/w+dMmervLto55RMUNDk=", "dev": true, "requires": { - "nomnom": "~1.6.2", - "railroad-diagrams": "^1.0.0", + "nomnom": "1.6.2", + "railroad-diagrams": "1.0.0", "randexp": "0.4.6", - "semver": "^5.4.1" + "semver": "5.4.1" } }, "next-tick": { @@ -5044,14 +5398,14 @@ "nise": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.2.tgz", - "integrity": "sha1-qaOADjmUmUr55FIzPVSdYPcrjow=", + "integrity": "sha512-BxH/DxoQYYdhKgVAfqVy4pzXRZELHOIewzoesxpjYvpU+7YOalQhGNPf7wAx8pLrTNPrHRDlLOkAl8UI0ZpXjw==", "dev": true, "requires": { - "@sinonjs/formatio": "^2.0.0", - "just-extend": "^1.1.27", - "lolex": "^2.3.2", - "path-to-regexp": "^1.7.0", - "text-encoding": "^0.6.4" + "@sinonjs/formatio": "2.0.0", + "just-extend": "1.1.27", + "lolex": "2.7.1", + "path-to-regexp": "1.7.0", + "text-encoding": "0.6.4" } }, "node-abi": { @@ -5059,15 +5413,15 @@ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.0.tgz", "integrity": "sha1-PCdRXLhC9bvBMqMSVPnx4cVce4M=", "requires": { - "semver": "^5.4.1" + "semver": "5.4.1" } }, "node-emoji": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz", - "integrity": "sha1-buxr+wdCHiFIx1xrunJCH4UwqCY=", + "integrity": "sha512-+ktMAh1Jwas+TnGodfCfjUbJKoANqPaJFN0z0iqh41eqD8dvguNzcitVSBSVK1pidz0AqGbLKcoVuVLRVZ/aVg==", "requires": { - "lodash.toarray": "^4.4.0" + "lodash.toarray": "4.4.0" } }, "node-fetch": { @@ -5088,8 +5442,8 @@ "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", "dev": true, "requires": { - "colors": "0.5.x", - "underscore": "~1.4.4" + "colors": "0.5.1", + "underscore": "1.4.4" } }, "noop-logger": { @@ -5103,10 +5457,10 @@ "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "2.6.0", + "is-builtin-module": "1.0.0", + "semver": "5.4.1", + "validate-npm-package-license": "3.0.3" } }, "npm-run-path": { @@ -5115,7 +5469,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "^2.0.0" + "path-key": "2.0.1" } }, "npmlog": { @@ -5123,10 +5477,10 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" } }, "nth-check": { @@ -5135,7 +5489,7 @@ "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", "dev": true, "requires": { - "boolbase": "~1.0.0" + "boolbase": "1.0.0" } }, "number-is-nan": { @@ -5149,73 +5503,73 @@ "integrity": "sha1-4Awm6b0zq16B7emSu+STCEhYmbY=", "dev": true, "requires": { - "archy": "^1.0.0", - "arrify": "^1.0.1", - "caching-transform": "^1.0.1", - "convert-source-map": "^1.5.1", - "debug-log": "^1.0.1", - "find-cache-dir": "^1.0.0", - "find-up": "^2.1.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.0", - "istanbul-lib-hook": "^2.0.0", - "istanbul-lib-instrument": "^2.2.0", - "istanbul-lib-report": "^2.0.0", - "istanbul-lib-source-maps": "^2.0.0", - "istanbul-reports": "^1.5.0", - "make-dir": "^1.3.0", - "md5-hex": "^2.0.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^4.2.2", + "archy": "1.0.0", + "arrify": "1.0.1", + "caching-transform": "1.0.1", + "convert-source-map": "1.5.1", + "debug-log": "1.0.1", + "find-cache-dir": "1.0.0", + "find-up": "2.1.0", + "foreground-child": "1.5.6", + "glob": "7.1.2", + "istanbul-lib-coverage": "2.0.0", + "istanbul-lib-hook": "2.0.0", + "istanbul-lib-instrument": "2.2.0", + "istanbul-lib-report": "2.0.0", + "istanbul-lib-source-maps": "2.0.0", + "istanbul-reports": "1.5.0", + "make-dir": "1.3.0", + "md5-hex": "2.0.0", + "merge-source-map": "1.1.0", + "resolve-from": "4.0.0", + "rimraf": "2.6.2", + "signal-exit": "3.0.2", + "spawn-wrap": "1.4.2", + "test-exclude": "4.2.2", "yargs": "11.1.0", - "yargs-parser": "^9.0.2" + "yargs-parser": "9.0.2" }, "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "camelcase": { "version": "1.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" }, "cliui": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", + "center-align": "0.1.3", + "right-align": "0.1.3", "wordwrap": "0.0.2" }, "dependencies": { "wordwrap": { "version": "0.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" } } }, "cross-spawn": { "version": "4.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" + "lru-cache": "4.1.3", + "which": "1.3.0" } }, "debug": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { "ms": "2.0.0" @@ -5223,150 +5577,158 @@ }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "kind-of": { "version": "3.2.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } }, "lru-cache": { "version": "4.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "pseudomap": "1.0.2", + "yallist": "2.1.2" } }, "md5-hex": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz", "integrity": "sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM=", "dev": true, "requires": { - "md5-o-matic": "^0.1.1" + "md5-o-matic": "0.1.1" } }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "optimist": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" + "minimist": "0.0.8", + "wordwrap": "0.0.3" } }, "resolve-from": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "semver": { "version": "5.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" }, "strip-ansi": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } }, "supports-color": { "version": "5.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } }, "test-exclude": { "version": "4.2.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.2.tgz", "integrity": "sha512-2kTGf+3tykCfrWVREgyTR0bmVO0afE6i7zVXi/m+bZZ8ujV89Aulxdcdv32yH+unVFg3Y5o6GA8IzsHnGQuFgQ==", "dev": true, "requires": { - "arrify": "^1.0.1", - "minimatch": "^3.0.4", - "read-pkg-up": "^3.0.0", - "require-main-filename": "^1.0.1" + "arrify": "1.0.1", + "minimatch": "3.0.4", + "read-pkg-up": "3.0.0", + "require-main-filename": "1.0.1" }, "dependencies": { "load-json-file": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "graceful-fs": "4.1.11", + "parse-json": "4.0.0", + "pify": "3.0.0", + "strip-bom": "3.0.0" } }, "parse-json": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "error-ex": "1.3.1", + "json-parse-better-errors": "1.0.2" + }, + "dependencies": { + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + } } }, "path-type": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "pify": "^3.0.0" + "pify": "3.0.0" } }, "pify": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, "read-pkg": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "load-json-file": "4.0.0", + "normalize-package-data": "2.4.0", + "path-type": "3.0.0" } }, "read-pkg-up": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "find-up": "2.1.0", + "read-pkg": "3.0.0" } }, "strip-bom": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true } @@ -5374,69 +5736,69 @@ }, "yallist": { "version": "2.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, "yargs": { "version": "11.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" + "cliui": "4.1.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "9.0.2" }, "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true }, "cliui": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" } }, "yargs-parser": { "version": "9.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" } } } }, "yargs-parser": { "version": "9.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" }, "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true } @@ -5460,9 +5822,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" }, "dependencies": { "define-property": { @@ -5471,7 +5833,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "kind-of": { @@ -5480,7 +5842,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5509,7 +5871,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "^3.0.0" + "isobject": "3.0.1" } }, "object.assign": { @@ -5518,10 +5880,10 @@ "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "1.1.2", + "function-bind": "1.1.1", + "has-symbols": "1.0.0", + "object-keys": "1.0.11" } }, "object.entries": { @@ -5530,10 +5892,10 @@ "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" + "define-properties": "1.1.2", + "es-abstract": "1.11.0", + "function-bind": "1.1.1", + "has": "1.0.1" } }, "object.pick": { @@ -5542,7 +5904,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "object.values": { @@ -5551,10 +5913,10 @@ "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" + "define-properties": "1.1.2", + "es-abstract": "1.11.0", + "function-bind": "1.1.1", + "has": "1.0.1" } }, "once": { @@ -5562,7 +5924,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "onetime": { @@ -5571,7 +5933,7 @@ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "1.2.0" } }, "optimist": { @@ -5579,7 +5941,7 @@ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", "requires": { - "wordwrap": "~0.0.2" + "wordwrap": "0.0.3" } }, "optionator": { @@ -5588,12 +5950,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" }, "dependencies": { "wordwrap": { @@ -5615,9 +5977,9 @@ "integrity": "sha1-QrwpAKa1uL0XN2yOiCtlr8zyS/I=", "dev": true, "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" } }, "os-tmpdir": { @@ -5637,7 +5999,7 @@ "integrity": "sha1-DpK2vty1nwIsE9DxlJ3ILRWQnxw=", "dev": true, "requires": { - "p-try": "^1.0.0" + "p-try": "1.0.0" } }, "p-locate": { @@ -5646,7 +6008,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "^1.1.0" + "p-limit": "1.2.0" } }, "p-try": { @@ -5661,7 +6023,7 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "^1.2.0" + "error-ex": "1.3.1" } }, "parse5": { @@ -5670,7 +6032,7 @@ "integrity": "sha1-BC95L/3TaFFVHPTp4Gazh0q0W1w=", "dev": true, "requires": { - "@types/node": "*" + "@types/node": "9.6.4" } }, "pascalcase": { @@ -5723,7 +6085,7 @@ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { - "pify": "^2.0.0" + "pify": "2.3.0" } }, "pathval": { @@ -5755,22 +6117,22 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "^2.0.0" + "pinkie": "2.0.4" } }, "pkg-dir": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "find-up": "^2.1.0" + "find-up": "2.1.0" } }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, "posix-character-classes": { @@ -5784,21 +6146,21 @@ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.5.3.tgz", "integrity": "sha1-n2XyQngtNwKWNTcQ6byENJDBn2k=", "requires": { - "detect-libc": "^1.0.3", - "expand-template": "^1.0.2", + "detect-libc": "1.0.3", + "expand-template": "1.1.0", "github-from-package": "0.0.0", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "node-abi": "^2.2.0", - "noop-logger": "^0.1.1", - "npmlog": "^4.0.1", - "os-homedir": "^1.0.1", - "pump": "^2.0.1", - "rc": "^1.1.6", - "simple-get": "^2.7.0", - "tar-fs": "^1.13.0", - "tunnel-agent": "^0.6.0", - "which-pm-runs": "^1.0.0" + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "node-abi": "2.4.0", + "noop-logger": "0.1.1", + "npmlog": "4.1.2", + "os-homedir": "1.0.2", + "pump": "2.0.1", + "rc": "1.2.7", + "simple-get": "2.8.1", + "tar-fs": "1.16.2", + "tunnel-agent": "0.6.0", + "which-pm-runs": "1.0.0" } }, "prelude-ls": { @@ -5833,16 +6195,16 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", "requires": { - "asap": "~2.0.3" + "asap": "2.0.6" } }, "prop-types": { "version": "15.6.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", - "integrity": "sha1-BdXKd7RFPphdYPx/+MhZCUpJcQI=", + "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", "requires": { - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" + "loose-envify": "1.3.1", + "object-assign": "4.1.1" } }, "prr": { @@ -5862,8 +6224,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.1", + "once": "1.4.0" } }, "punycode": { @@ -5882,7 +6244,7 @@ "integrity": "sha1-ooh2iBtLwsqRF9QTgWPduA94FXU=", "dev": true, "requires": { - "performance-now": "^2.1.0" + "performance-now": "2.1.0" } }, "railroad-diagrams": { @@ -5898,7 +6260,7 @@ "dev": true, "requires": { "discontinuous-range": "1.0.0", - "ret": "~0.1.10" + "ret": "0.1.15" } }, "rc": { @@ -5906,32 +6268,10 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz", "integrity": "sha1-ihDKMNWI0ARkNgNyuJDQbazQIpc=", "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "react": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/react/-/react-16.4.1.tgz", - "integrity": "sha1-3lG6V2S1280fkHkDe4Yr0muC/jI=", - "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.0" - } - }, - "react-dom": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.1.tgz", - "integrity": "sha1-f4sCI7Ol++IFEWxW3rhd4yaF2tY=", - "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "deep-extend": "0.5.1", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" } }, "react-input-autosize": { @@ -5939,7 +6279,7 @@ "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.1.tgz", "integrity": "sha1-7EKPoVsVkplPtfmqFbsetrr0IPg=", "requires": { - "prop-types": "^15.5.8" + "prop-types": "15.6.2" }, "dependencies": { "core-js": { @@ -5952,8 +6292,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" + "encoding": "0.1.12", + "is-stream": "1.1.0" } } } @@ -5961,29 +6301,29 @@ "react-is": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.4.1.tgz", - "integrity": "sha1-1iTEZQ0sZdvVLHJiK784lDXZd24=", + "integrity": "sha512-xpb0PpALlFWNw/q13A+1aHeyJyLYCg0/cCHPUA43zYluZuIPHaHL3k8OBsTgQtxqW0FhyDEMvi8fZ/+7+r4OSQ==", "dev": true }, "react-reconciler": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.7.0.tgz", - "integrity": "sha1-lhSJQQPl8Tje7rXquvPugOsdAm0=", + "integrity": "sha512-50JwZ3yNyMS8fchN+jjWEJOH3Oze7UmhxeoJLn2j6f3NjpfCRbcmih83XTWmzqtar/ivd5f7tvQhvvhism2fgg==", "dev": true, "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "prop-types": "15.6.2" } }, "react-relay": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/react-relay/-/react-relay-1.6.0.tgz", - "integrity": "sha1-eg7KQ1yBubAdiRfUvKZQfu+83+Q=", + "integrity": "sha512-8clmRHXNo96pcdkA8ZeiqF7xGjE+mjSbdX/INj5upRm2M8AprSrFk2Oz5nH084O+0hvXQhZtFyraXJWQO9ld3A==", "requires": { - "babel-runtime": "^6.23.0", - "fbjs": "^0.8.14", - "prop-types": "^15.5.8", + "babel-runtime": "6.25.0", + "fbjs": "0.8.16", + "prop-types": "15.6.2", "relay-runtime": "1.6.0" } }, @@ -5992,9 +6332,9 @@ "resolved": "https://registry.npmjs.org/react-select/-/react-select-1.2.1.tgz", "integrity": "sha1-ov5YpWnrFNyqZUOBYmC5flOBINE=", "requires": { - "classnames": "^2.2.4", - "prop-types": "^15.5.8", - "react-input-autosize": "^2.1.2" + "classnames": "2.2.6", + "prop-types": "15.6.2", + "react-input-autosize": "2.2.1" }, "dependencies": { "core-js": { @@ -6007,8 +6347,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" + "encoding": "0.1.12", + "is-stream": "1.1.0" } } } @@ -6016,13 +6356,13 @@ "react-test-renderer": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.4.1.tgz", - "integrity": "sha1-8vswwse1F9tuWxDtILtrCnzNjXA=", + "integrity": "sha512-wyyiPxRZOTpKnNIgUBOB6xPLTpIzwcQMIURhZvzUqZzezvHjaGNsDPBhMac5fIY3Jf5NuKxoGvV64zDSOECPPQ==", "dev": true, "requires": { - "fbjs": "^0.8.16", - "object-assign": "^4.1.1", - "prop-types": "^15.6.0", - "react-is": "^16.4.1" + "fbjs": "0.8.16", + "object-assign": "4.1.1", + "prop-types": "15.6.2", + "react-is": "16.4.1" } }, "read-pkg": { @@ -6031,9 +6371,9 @@ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" } }, "read-pkg-up": { @@ -6042,8 +6382,8 @@ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "find-up": "2.1.0", + "read-pkg": "2.0.0" } }, "readable-stream": { @@ -6051,13 +6391,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" }, "dependencies": { "isarray": { @@ -6083,8 +6423,8 @@ "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" }, "dependencies": { "is-extendable": { @@ -6092,7 +6432,7 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -6103,61 +6443,61 @@ "integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==", "dev": true, "requires": { - "define-properties": "^1.1.2" + "define-properties": "1.1.2" } }, "regexpp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha1-DjUW3Qt5BPQT0tQZPc5GGMOmias=", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", "dev": true }, "relay-compiler": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/relay-compiler/-/relay-compiler-1.6.0.tgz", - "integrity": "sha1-ChvI0owc8x2JhRCKdhumwNtI1KE=", + "integrity": "sha512-qm9Xp/5tcpMli0z4WFYeb4E16ynxTKtmaAPT077vDpAzalBB2f71JEkQJUdrvVzcdr5m53LuXhXBODkUNkLQkg==", "dev": true, "requires": { "@babel/generator": "7.0.0-beta.40", "@babel/types": "7.0.0-beta.40", - "babel-polyfill": "^6.20.0", - "babel-preset-fbjs": "^2.1.4", - "babel-runtime": "^6.23.0", - "babel-traverse": "^6.26.0", + "babel-polyfill": "6.26.0", + "babel-preset-fbjs": "2.1.4", + "babel-runtime": "6.25.0", + "babel-traverse": "6.26.0", "babylon": "7.0.0-beta.40", - "chalk": "^1.1.1", - "fast-glob": "^2.0.0", - "fb-watchman": "^2.0.0", - "fbjs": "^0.8.14", + "chalk": "1.1.3", + "fast-glob": "2.2.1", + "fb-watchman": "2.0.0", + "fbjs": "0.8.16", "graphql-compiler": "1.6.0", - "immutable": "~3.7.6", + "immutable": "3.7.6", "relay-runtime": "1.6.0", - "signedsource": "^1.0.0", - "yargs": "^9.0.0" + "signedsource": "1.0.0", + "yargs": "9.0.1" }, "dependencies": { "@babel/generator": { "version": "7.0.0-beta.40", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.40.tgz", - "integrity": "sha1-q2H5VW9PcdvRE4lJx5W7miHjAuo=", + "integrity": "sha512-c91BQcXyTq/5aFV4afgOionxZS1dxWt8OghEx5Q52SKssdGRFSiMKnk9tGkev1pYULPJBqjSDZU2Pcuc58ffZw==", "dev": true, "requires": { "@babel/types": "7.0.0-beta.40", - "jsesc": "^2.5.1", - "lodash": "^4.2.0", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "jsesc": "2.5.1", + "lodash": "4.17.5", + "source-map": "0.5.7", + "trim-right": "1.0.1" } }, "@babel/types": { "version": "7.0.0-beta.40", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.40.tgz", - "integrity": "sha1-JcPXquFBJqvgX8sJjGWma21rjBQ=", + "integrity": "sha512-uXCGCzTgMZxcSUzutCPtZmXbVC+cvENgS2e0tRuhn+Y1hZnMb8IHP0Trq7Q2MB/eFmG5pKrAeTIUfQIe5kA4Tg==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.2.0", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "2.0.0" } }, "babel-traverse": { @@ -6166,15 +6506,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.5" }, "dependencies": { "babel-runtime": { @@ -6183,8 +6523,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "babylon": { @@ -6201,10 +6541,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" }, "dependencies": { "babel-runtime": { @@ -6213,8 +6553,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.5.0", + "regenerator-runtime": "0.11.1" } }, "to-fast-properties": { @@ -6228,7 +6568,7 @@ "babylon": { "version": "7.0.0-beta.40", "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.40.tgz", - "integrity": "sha1-kfyM1W1euYso5v3kEEXylXd5lAo=", + "integrity": "sha512-AVxF2EcxvGD5hhOuLTOLAXBb0VhwWpEX0HyHdAI2zU+AAP4qEwtQj8voz1JR3uclGai0rfcE+dCTHnNMOnimFg==", "dev": true }, "jsesc": { @@ -6248,10 +6588,10 @@ "relay-runtime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/relay-runtime/-/relay-runtime-1.6.0.tgz", - "integrity": "sha1-K3AFj7d6TJOhcXUs4Uf47o2KiLk=", + "integrity": "sha512-UJiEHp8CX2uFxXdM0nVLTCQ6yAT0GLmyMceXLISuW/l2a9jrS9a4MdZgdr/9UkkYno7Sj1hU/EUIQ0GaVkou8g==", "requires": { - "babel-runtime": "^6.23.0", - "fbjs": "^0.8.14" + "babel-runtime": "6.25.0", + "fbjs": "0.8.16" } }, "repeat-element": { @@ -6263,42 +6603,41 @@ "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "requires": { - "is-finite": "^1.0.0" + "is-finite": "1.0.2" } }, "request": { "version": "2.87.0", "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", - "integrity": "sha1-MvACNc0I1IK00NaNuTqCnA7VdW4=", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", - "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", - "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "tough-cookie": "~2.3.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" }, "dependencies": { "mime-db": { @@ -6311,7 +6650,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha1-bzI/YKg9ERRvgx/xH9ZuL+VQO7g=", "requires": { - "mime-db": "~1.33.0" + "mime-db": "1.33.0" } } } @@ -6322,7 +6661,55 @@ "integrity": "sha512-5TVnMD3LaeK0GRCyFlsNgJf5Fjg8J8j7VEfsoJESSWZlWRgPIf7IojsBLbTHcg2798JrrRkJ6L3k1+wj4sglgw==", "dev": true, "requires": { - "depd": "1.1.2" + "depd": "1.1.2", + "request": "2.83.0" + }, + "dependencies": { + "mime-db": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "dev": true, + "requires": { + "mime-db": "1.35.0" + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.19", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.6", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + } } }, "require-directory": { @@ -6343,8 +6730,8 @@ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" + "caller-path": "0.1.0", + "resolve-from": "1.0.1" } }, "resolve-from": { @@ -6365,8 +6752,8 @@ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" + "onetime": "2.0.1", + "signal-exit": "3.0.2" } }, "ret": { @@ -6375,12 +6762,20 @@ "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", "dev": true }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "requires": { + "align-text": "0.1.4" + } + }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "requires": { - "glob": "^7.0.5" + "glob": "7.1.2" } }, "rst-selector-parser": { @@ -6389,8 +6784,8 @@ "integrity": "sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=", "dev": true, "requires": { - "lodash.flattendeep": "^4.4.0", - "nearley": "^2.7.10" + "lodash.flattendeep": "4.4.0", + "nearley": "2.13.0" } }, "run-async": { @@ -6399,7 +6794,7 @@ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true, "requires": { - "is-promise": "^2.1.0" + "is-promise": "2.1.0" } }, "rxjs": { @@ -6422,13 +6817,13 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "~0.1.10" + "ret": "0.1.15" } }, "samsam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha1-jR2TUOJWItow3j5EumkrUiGrfFA=", + "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", "dev": true }, "semver": { @@ -6447,10 +6842,10 @@ "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" }, "dependencies": { "extend-shallow": { @@ -6459,7 +6854,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -6475,7 +6870,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "1.0.0" } }, "shebang-regex": { @@ -6511,33 +6906,33 @@ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", "integrity": "sha1-DiLpHUV12HYgYgvJEwjVenf0S10=", "requires": { - "decompress-response": "^3.3.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" + "decompress-response": "3.3.0", + "once": "1.4.0", + "simple-concat": "1.0.0" } }, "sinon": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.0.1.tgz", - "integrity": "sha1-Qke5fdj+y+Hhn4uBal5+7TmTvP4=", + "integrity": "sha512-rfszhNcfamK2+ofIPi9XqeH89pH7KGDcAtM+F9CsjHXOK3jzWG99vyhyD2V+r7s4IipmWcWUFYq4ftZ9/Eu2Wg==", "dev": true, "requires": { - "@sinonjs/formatio": "^2.0.0", - "diff": "^3.5.0", - "lodash.get": "^4.4.2", - "lolex": "^2.4.2", - "nise": "^1.3.3", - "supports-color": "^5.4.0", - "type-detect": "^4.0.8" + "@sinonjs/formatio": "2.0.0", + "diff": "3.5.0", + "lodash.get": "4.4.2", + "lolex": "2.7.1", + "nise": "1.4.2", + "supports-color": "5.4.0", + "type-detect": "4.0.8" }, "dependencies": { "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -6550,10 +6945,10 @@ "slice-ansi": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha1-BE8aSdiEL/MHqta1Be0Xi9lQE00=", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0" + "is-fullwidth-code-point": "2.0.0" }, "dependencies": { "is-fullwidth-code-point": { @@ -6566,24 +6961,24 @@ }, "slide": { "version": "1.1.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", "dev": true }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.1", + "use": "3.1.0" }, "dependencies": { "define-property": { @@ -6592,7 +6987,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -6601,7 +6996,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -6612,9 +7007,9 @@ "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", "dev": true, "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" }, "dependencies": { "define-property": { @@ -6623,36 +7018,36 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -6663,7 +7058,7 @@ "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", "dev": true, "requires": { - "kind-of": "^3.2.0" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -6672,11 +7067,19 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "requires": { + "hoek": "4.2.1" + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -6688,11 +7091,11 @@ "integrity": "sha1-etD1k/IoFZjoVN+A8ZquS5LXoRo=", "dev": true, "requires": { - "atob": "^2.0.0", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "atob": "2.1.1", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" } }, "source-map-support": { @@ -6700,7 +7103,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", "integrity": "sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8=", "requires": { - "source-map": "^0.5.6" + "source-map": "0.5.7" } }, "source-map-url": { @@ -6711,48 +7114,48 @@ }, "spawn-wrap": { "version": "1.4.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", "dev": true, "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" + "foreground-child": "1.5.6", + "mkdirp": "0.5.1", + "os-homedir": "1.0.2", + "rimraf": "2.6.2", + "signal-exit": "3.0.2", + "which": "1.3.0" } }, "spdx-correct": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha1-BaW01xU6GVvJLDxCW2nzsqlSTII=", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" } }, "spdx-exceptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha1-LHrmEFbHFKW5ubKyr30xHvXHj+k=", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" } }, "spdx-license-ids": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=", + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", "dev": true }, "split": { @@ -6760,7 +7163,7 @@ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", "integrity": "sha1-YFvZvjA6pZ+zX5Ip++oN3snqB9k=", "requires": { - "through": "2" + "through": "2.3.8" } }, "split-string": { @@ -6769,7 +7172,7 @@ "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "extend-shallow": "3.0.2" }, "dependencies": { "is-extendable": { @@ -6777,7 +7180,7 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -6793,14 +7196,14 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" } }, "static-extend": { @@ -6809,8 +7212,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "define-property": "0.2.5", + "object-copy": "0.1.0" }, "dependencies": { "define-property": { @@ -6819,7 +7222,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -6836,8 +7239,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" }, "dependencies": { "ansi-regex": { @@ -6858,7 +7261,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } } } @@ -6869,11 +7272,11 @@ "integrity": "sha512-WoZ+B2ypng1dp4iFLF2kmZlwwlE19gmjgKuhL1FJfDgCREWb3ye3SDVHSzLH6bxfnvYmkCxbzkmWcQZHA4P//Q==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.10.0", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "regexp.prototype.flags": "^1.2.0" + "define-properties": "1.1.2", + "es-abstract": "1.11.0", + "function-bind": "1.1.1", + "has-symbols": "1.0.0", + "regexp.prototype.flags": "1.2.0" } }, "string_decoder": { @@ -6881,7 +7284,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "stringstream": { @@ -6894,7 +7297,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "strip-bom": { @@ -6931,12 +7334,12 @@ "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", "dev": true, "requires": { - "ajv": "^6.0.1", - "ajv-keywords": "^3.0.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", + "ajv": "6.5.2", + "ajv-keywords": "3.2.0", + "chalk": "2.4.1", + "lodash": "4.17.5", "slice-ansi": "1.0.0", - "string-width": "^2.1.1" + "string-width": "2.1.1" }, "dependencies": { "ajv": { @@ -6945,10 +7348,10 @@ "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.1" + "fast-deep-equal": "2.0.1", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.2.2" } }, "ansi-styles": { @@ -6957,7 +7360,7 @@ "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.1" } }, "chalk": { @@ -6966,9 +7369,9 @@ "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "fast-deep-equal": { @@ -6989,7 +7392,7 @@ "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -6999,13 +7402,13 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.4.tgz", "integrity": "sha1-7IQJ+un2ZaQ1XMO0CH0IICMruM0=", "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.3", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" + "chownr": "1.0.1", + "fs-minipass": "1.2.5", + "minipass": "2.3.3", + "minizlib": "1.1.0", + "mkdirp": "0.5.1", + "safe-buffer": "5.1.2", + "yallist": "3.0.2" }, "dependencies": { "safe-buffer": { @@ -7020,10 +7423,10 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.2.tgz", "integrity": "sha1-F+Ujl0fjmffnc0T19TNl8Er1NXc=", "requires": { - "chownr": "^1.0.1", - "mkdirp": "^0.5.1", - "pump": "^1.0.0", - "tar-stream": "^1.1.2" + "chownr": "1.0.1", + "mkdirp": "0.5.1", + "pump": "1.0.3", + "tar-stream": "1.6.0" }, "dependencies": { "pump": { @@ -7031,8 +7434,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", "integrity": "sha1-Xf6DEcM7v2/BgmH580cCxHwIqVQ=", "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.1", + "once": "1.4.0" } } } @@ -7042,13 +7445,13 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.0.tgz", "integrity": "sha1-pQ76p7F3YLgsJ7PK5KMBqCVKVxU=", "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.1.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.0.0", - "to-buffer": "^1.1.0", - "xtend": "^4.0.0" + "bl": "1.2.2", + "buffer-alloc": "1.1.0", + "end-of-stream": "1.4.1", + "fs-constants": "1.0.0", + "readable-stream": "2.3.3", + "to-buffer": "1.1.1", + "xtend": "4.0.1" } }, "temp": { @@ -7056,8 +7459,8 @@ "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", "requires": { - "os-tmpdir": "^1.0.0", - "rimraf": "~2.2.6" + "os-tmpdir": "1.0.2", + "rimraf": "2.2.8" }, "dependencies": { "rimraf": { @@ -7073,11 +7476,11 @@ "integrity": "sha1-36Ii8DSAvKaSB8pyizfXS0X3JPo=", "dev": true, "requires": { - "arrify": "^1.0.1", - "micromatch": "^3.1.8", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", - "require-main-filename": "^1.0.1" + "arrify": "1.0.1", + "micromatch": "3.1.10", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "require-main-filename": "1.0.1" }, "dependencies": { "find-up": { @@ -7086,8 +7489,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" } }, "load-json-file": { @@ -7096,11 +7499,11 @@ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" } }, "path-exists": { @@ -7109,7 +7512,7 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "^2.0.0" + "pinkie-promise": "2.0.1" } }, "path-type": { @@ -7118,9 +7521,9 @@ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, "read-pkg": { @@ -7129,9 +7532,9 @@ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" } }, "read-pkg-up": { @@ -7140,8 +7543,8 @@ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "find-up": "1.1.2", + "read-pkg": "1.1.0" } }, "strip-bom": { @@ -7150,7 +7553,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "^0.2.0" + "is-utf8": "0.2.1" } } } @@ -7189,7 +7592,7 @@ "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", "dev": true, "requires": { - "os-tmpdir": "~1.0.1" + "os-tmpdir": "1.0.2" } }, "to-buffer": { @@ -7215,7 +7618,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -7224,7 +7627,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -7235,10 +7638,10 @@ "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", "dev": true, "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" }, "dependencies": { "is-extendable": { @@ -7246,7 +7649,7 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -7257,8 +7660,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "3.0.0", + "repeat-string": "1.6.1" } }, "tough-cookie": { @@ -7266,7 +7669,7 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha1-7GDO44rGdQY//JelwYlwV47oNlU=", "requires": { - "punycode": "^1.4.1" + "punycode": "1.4.1" } }, "tree-kill": { @@ -7284,7 +7687,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "^5.0.1" + "safe-buffer": "5.1.1" } }, "tweetnacl": { @@ -7299,7 +7702,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "prelude-ls": "1.1.2" } }, "type-detect": { @@ -7315,24 +7718,52 @@ }, "uglify-js": { "version": "2.8.29", - "resolved": false, + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "optional": true, "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" }, "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + } + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + }, "yargs": { "version": "3.10.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, "optional": true, "requires": { - "decamelize": "^1.0.0", + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", "window-size": "0.1.0" } } @@ -7340,7 +7771,7 @@ }, "uglify-to-browserify": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "dev": true, "optional": true @@ -7357,10 +7788,10 @@ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" }, "dependencies": { "extend-shallow": { @@ -7369,7 +7800,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "set-value": { @@ -7378,10 +7809,10 @@ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" } } } @@ -7397,8 +7828,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "has-value": "0.3.1", + "isobject": "3.0.1" }, "dependencies": { "has-value": { @@ -7407,9 +7838,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" }, "dependencies": { "isobject": { @@ -7443,7 +7874,7 @@ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { - "punycode": "^2.1.0" + "punycode": "2.1.1" }, "dependencies": { "punycode": { @@ -7463,10 +7894,10 @@ "use": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha1-FHFr8D/f79AwQK71jYtLhfOnxUQ=", + "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", "dev": true, "requires": { - "kind-of": "^6.0.2" + "kind-of": "6.0.2" } }, "util-deprecate": { @@ -7482,11 +7913,11 @@ "validate-npm-package-license": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha1-gWQ7y+8b3+zUYjeT3EZIlIupgzg=", + "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", "dev": true, "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" } }, "verror": { @@ -7494,9 +7925,9 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "^1.0.0", + "assert-plus": "1.0.0", "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "extsprintf": "1.3.0" } }, "virtual-dom": { @@ -7506,11 +7937,11 @@ "dev": true, "requires": { "browser-split": "0.0.1", - "error": "^4.3.0", - "ev-store": "^7.0.0", - "global": "^4.3.0", - "is-object": "^1.0.1", - "next-tick": "^0.2.2", + "error": "4.4.0", + "ev-store": "7.0.0", + "global": "4.3.2", + "is-object": "1.0.1", + "next-tick": "0.2.2", "x-is-array": "0.1.0", "x-is-string": "0.1.0" } @@ -7525,7 +7956,7 @@ "resolved": "https://registry.npmjs.org/what-the-status/-/what-the-status-1.0.3.tgz", "integrity": "sha1-lP3NAR/7U6Ijnnb6+NrL78mHdRA=", "requires": { - "split": "^1.0.0" + "split": "1.0.1" } }, "whatwg-fetch": { @@ -7538,7 +7969,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", "requires": { - "isexe": "^2.0.0" + "isexe": "2.0.0" } }, "which-module": { @@ -7557,7 +7988,7 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", "integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=", "requires": { - "string-width": "^1.0.2" + "string-width": "1.0.2" }, "dependencies": { "string-width": { @@ -7565,16 +7996,16 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } } } }, "window-size": { "version": "0.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "dev": true, "optional": true @@ -7590,8 +8021,8 @@ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "string-width": "1.0.2", + "strip-ansi": "3.0.1" }, "dependencies": { "string-width": { @@ -7600,9 +8031,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } } } @@ -7618,18 +8049,18 @@ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "^0.5.1" + "mkdirp": "0.5.1" } }, "write-file-atomic": { "version": "1.3.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" } }, "x-is-array": { @@ -7672,19 +8103,19 @@ "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", "dev": true, "requires": { - "camelcase": "^4.1.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "read-pkg-up": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^7.0.0" + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" } }, "yargs-parser": { @@ -7693,7 +8124,7 @@ "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" } }, "yubikiri": { diff --git a/package.json b/package.json index 08fafe3b35..dc5aab4b9f 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "enzyme": "3.3.0", "eslint": "5.0.1", "eslint-config-fbjs-opensource": "1.0.0", + "eslint-plugin-jsx-a11y": "^6.1.1", "hock": "1.3.2", "lodash.isequal": "4.5.0", "mkdirp": "0.5.1", From d75a4ca89ef800c9b61aed3a11b186deb882ce68 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 19 Jul 2018 15:54:55 -0700 Subject: [PATCH 0583/4847] make `ChangedFilesCountView` a button --- lib/views/changed-files-count-view.js | 4 ++-- styles/changed-files-count-view.less | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/views/changed-files-count-view.js b/lib/views/changed-files-count-view.js index e0170e360d..051e824614 100644 --- a/lib/views/changed-files-count-view.js +++ b/lib/views/changed-files-count-view.js @@ -21,14 +21,14 @@ export default class ChangedFilesCountView extends React.Component { ? '1 file' : `${this.props.changedFilesCount} files`; return ( - {label} {this.props.mergeConflictsPresent && } - + ); } } diff --git a/styles/changed-files-count-view.less b/styles/changed-files-count-view.less index 31ebf01cd8..093cd2c98a 100644 --- a/styles/changed-files-count-view.less +++ b/styles/changed-files-count-view.less @@ -3,6 +3,8 @@ // Used in the status-bar .github-ChangedFilesCount { + background-color: inherit; + border: none; &.icon-diff::before { margin-right: .2em; From 67ece04fe3113c02ff91a9245bf3043953c251f4 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 19 Jul 2018 15:55:10 -0700 Subject: [PATCH 0584/4847] install react again --- package-lock.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/package-lock.json b/package-lock.json index e11cbfade9..cf5cf4232d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6274,6 +6274,28 @@ "strip-json-comments": "2.0.1" } }, + "react": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.4.0.tgz", + "integrity": "sha512-K0UrkLXSAekf5nJu89obKUM7o2vc6MMN9LYoKnCa+c+8MJRAT120xzPLENcWSRc7GYKIg0LlgJRDorrufdglQQ==", + "requires": { + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "prop-types": "15.6.2" + } + }, + "react-dom": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.0.tgz", + "integrity": "sha512-bbLd+HYpBEnYoNyxDe9XpSG2t9wypMohwQPvKw8Hov3nF7SJiJIgK56b46zHpBUpHb06a1iEuw7G3rbrsnNL6w==", + "requires": { + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "prop-types": "15.6.2" + } + }, "react-input-autosize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.1.tgz", From 5a85e07546f74085603f93e8cdec7c091ca1fa68 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 19 Jul 2018 15:56:43 -0700 Subject: [PATCH 0585/4847] add alt tags for images --- lib/containers/issueish-tooltip-container.js | 2 +- lib/containers/user-mention-tooltip-container.js | 2 +- lib/views/timeline-items/commit-view.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/containers/issueish-tooltip-container.js b/lib/containers/issueish-tooltip-container.js index 11b6df3bb6..792c97c1cd 100644 --- a/lib/containers/issueish-tooltip-container.js +++ b/lib/containers/issueish-tooltip-container.js @@ -43,7 +43,7 @@ class IssueishTooltip extends React.Component {

    {title}

    - + {`${author.name}'s {author.login}
    diff --git a/lib/containers/user-mention-tooltip-container.js b/lib/containers/user-mention-tooltip-container.js index 78f70c6da5..f00d2a3981 100644 --- a/lib/containers/user-mention-tooltip-container.js +++ b/lib/containers/user-mention-tooltip-container.js @@ -29,7 +29,7 @@ class UserMentionTooltip extends React.Component { return (
    - + repository owner's avatar
    diff --git a/lib/views/timeline-items/commit-view.js b/lib/views/timeline-items/commit-view.js index 3213a2a3bf..20b9bba0ae 100644 --- a/lib/views/timeline-items/commit-view.js +++ b/lib/views/timeline-items/commit-view.js @@ -33,7 +33,7 @@ export class BareCommitView extends React.Component { if (!this.authoredByCommitter(commit)) { return ( author's avatar ); @@ -49,7 +49,7 @@ export class BareCommitView extends React.Component { author's avatar {this.renderCommitter(commit)} From c7eb45f5cf2d682a32957133aced7cdc9e433c21 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 19 Jul 2018 15:57:29 -0700 Subject: [PATCH 0586/4847] disable no-onchange lint rule for `SelectBranchView` --- lib/views/branch-menu-view.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/views/branch-menu-view.js b/lib/views/branch-menu-view.js index 2a67566edb..e81adf7254 100644 --- a/lib/views/branch-menu-view.js +++ b/lib/views/branch-menu-view.js @@ -68,6 +68,7 @@ export default class BranchMenuView extends React.Component { ); const selectBranchView = ( + /* eslint-disable jsx-a11y/no-onchange */ (this.passwordInput = e)} className="input-text github-CredentialDialog-Password" value={this.state.password} onChange={this.onPasswordChange} tabIndex="2" /> +
    @@ -122,4 +127,8 @@ export default class CredentialDialog extends React.Component { focusFirstInput() { (this.usernameInput || this.passwordInput).focus(); } + + toggleShowPassword() { + this.setState({showPassword: !this.state.showPassword}); + } } diff --git a/styles/dialog.less b/styles/dialog.less index 161d8d3293..e5e0e784c9 100644 --- a/styles/dialog.less +++ b/styles/dialog.less @@ -19,7 +19,22 @@ &Label { flex: 1; margin: @github-dialog-spacing; + position: relative; line-height: 2; + + &Button { + position: absolute; + background: transparent; + right: .2em; + bottom: 0; + border: none; + color: #000; + cursor: pointer; + + &:hover { + color: #888; + } + } } &Buttons { From 0870a3545a4074d77cf91f70b86f389e697a8e2d Mon Sep 17 00:00:00 2001 From: Eric Cornelissen Date: Sun, 25 Nov 2018 15:51:01 +0200 Subject: [PATCH 1986/4847] Style show/hide credentials button using the active theme --- styles/dialog.less | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/styles/dialog.less b/styles/dialog.less index e5e0e784c9..ef9df6efbe 100644 --- a/styles/dialog.less +++ b/styles/dialog.less @@ -25,14 +25,14 @@ &Button { position: absolute; background: transparent; - right: .2em; + right: .3em; bottom: 0; border: none; - color: #000; + color: @text-color-subtle; cursor: pointer; &:hover { - color: #888; + color: @text-color-highlight; } } } From dfccca2e5308d8da065fac0308cdee6b24e34c12 Mon Sep 17 00:00:00 2001 From: Eric Cornelissen Date: Sun, 25 Nov 2018 16:59:17 +0200 Subject: [PATCH 1987/4847] Test show/hide credentials button --- test/views/credential-dialog.test.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/views/credential-dialog.test.js b/test/views/credential-dialog.test.js index a98e71613b..86bd080494 100644 --- a/test/views/credential-dialog.test.js +++ b/test/views/credential-dialog.test.js @@ -85,4 +85,24 @@ describe('CredentialDialog', function() { assert.isFalse(wrapper.find('.github-CredentialDialog-remember').exists()); }); }); + + describe('show password', function() { + it('sets the passwords input type to "text" on the first click', function() { + wrapper = mount(app); + + wrapper.find('.github-DialogLabelButton').simulate('click'); + + const passwordInput = wrapper.find('.github-CredentialDialog-Password'); + assert.equal(passwordInput.prop('type'), 'text'); + }); + + it('sets the passwords input type back to "password" on the second click', function() { + wrapper = mount(app); + + wrapper.find('.github-DialogLabelButton').simulate('click').simulate('click'); + + const passwordInput = wrapper.find('.github-CredentialDialog-Password'); + assert.equal(passwordInput.prop('type'), 'password'); + }); + }); }); From 5be7bd69ef05fe59a667eab379375d6367ae9011 Mon Sep 17 00:00:00 2001 From: Benjamin Gray Date: Mon, 26 Nov 2018 21:55:02 +1100 Subject: [PATCH 1988/4847] Only log error if enabled --- lib/models/workdir-cache.js | 12 +++++++----- package.json | 5 +++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/models/workdir-cache.js b/lib/models/workdir-cache.js index 08bbc87385..dcb946dfb0 100644 --- a/lib/models/workdir-cache.js +++ b/lib/models/workdir-cache.js @@ -50,11 +50,13 @@ export default class WorkdirCache { const gitDir = await CompositeGitStrategy.create(startDir).exec(['rev-parse', '--absolute-git-dir']); return this.revParse(path.resolve(gitDir, '..')); } catch (e) { - // eslint-disable-next-line no-console - console.error( - `Unable to locate git workspace root for ${startPath}. Expected if ${startPath} is not in a git repository.`, - e, - ); + if (atom.config.get('github.reportCannotLocateWorkspaceError')) { + // eslint-disable-next-line no-console + console.error( + `Unable to locate git workspace root for ${startPath}. Expected if ${startPath} is not in a git repository.`, + e, + ); + } return null; } } diff --git a/package.json b/package.json index 628a56bc5d..94ea85116d 100644 --- a/package.json +++ b/package.json @@ -189,6 +189,11 @@ "type": "string", "default": "", "description": "Comma-separated list of email addresses to exclude from the co-author selection list" + }, + "reportCannotLocateWorkspaceError": { + "type": "boolean", + "default": "false", + "description": "Log an error to the console if a git repository cannot be located for the opened file " } }, "deserializers": { From 80a923f71d097f682a70627486a9b512e4582e7a Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 26 Nov 2018 14:41:14 +0100 Subject: [PATCH 1989/4847] =?UTF-8?q?=E2=9E=95=20CommitDetailContainer=20t?= =?UTF-8?q?est?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commit-detail-container.test.js | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 test/containers/commit-detail-container.test.js diff --git a/test/containers/commit-detail-container.test.js b/test/containers/commit-detail-container.test.js new file mode 100644 index 0000000000..c3ad0d4771 --- /dev/null +++ b/test/containers/commit-detail-container.test.js @@ -0,0 +1,72 @@ +import React from 'react'; +import {mount} from 'enzyme'; + +import CommitDetailContainer from '../../lib/containers/commit-detail-container'; +import CommitDetailItem from '../../lib/items/commit-detail-item'; +import {cloneRepository, buildRepository} from '../helpers'; + +describe.only('CommitDetailContainer', function() { + let atomEnv, repository; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + + const workdir = await cloneRepository('multiple-commits'); + repository = await buildRepository(workdir); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + function buildApp(override = {}) { + + const props = { + repository, + sha: '18920c900bfa6e4844853e7e246607a31c3e2e8c', + + itemType: CommitDetailItem, + workspace: atomEnv.workspace, + commands: atomEnv.commands, + keymaps: atomEnv.keymaps, + tooltips: atomEnv.tooltips, + config: atomEnv.config, + + destroy: () => {}, + + ...override, + }; + + return ; + } + + it('renders a loading spinner while the repository is loading', function() { + const wrapper = mount(buildApp()); + assert.isTrue(wrapper.find('LoadingView').exists()); + }); + + it('renders a loading spinner while the file patch is being loaded', async function() { + await repository.getLoadPromise(); + const patchPromise = repository.getStagedChangesPatch(); + let resolveDelayedPromise = () => {}; + const delayedPromise = new Promise(resolve => { + resolveDelayedPromise = resolve; + }); + sinon.stub(repository, 'getCommit').returns(delayedPromise); + + const wrapper = mount(buildApp()); + + assert.isTrue(wrapper.find('LoadingView').exists()); + resolveDelayedPromise(patchPromise); + await assert.async.isFalse(wrapper.update().find('LoadingView').exists()); + }); + + it('renders a CommitDetailController once the commit is loaded', async function() { + await repository.getLoadPromise(); + const commit = await repository.getCommit('18920c900bfa6e4844853e7e246607a31c3e2e8c'); + + const wrapper = mount(buildApp()); + await assert.async.isTrue(wrapper.update().find('CommitDetailController').exists()); + assert.strictEqual(wrapper.find('CommitDetailController').prop('commit'), commit); + }); +}); From 70a707bbf897e9e2b044050371b4664e793663f8 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 26 Nov 2018 14:42:31 +0100 Subject: [PATCH 1990/4847] =?UTF-8?q?=F0=9F=94=A5=20`.only`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/containers/commit-detail-container.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/containers/commit-detail-container.test.js b/test/containers/commit-detail-container.test.js index c3ad0d4771..2fccdc3614 100644 --- a/test/containers/commit-detail-container.test.js +++ b/test/containers/commit-detail-container.test.js @@ -5,7 +5,7 @@ import CommitDetailContainer from '../../lib/containers/commit-detail-container' import CommitDetailItem from '../../lib/items/commit-detail-item'; import {cloneRepository, buildRepository} from '../helpers'; -describe.only('CommitDetailContainer', function() { +describe('CommitDetailContainer', function() { let atomEnv, repository; beforeEach(async function() { From 369ee23d9d259060ece73eef5bd497bf9a15ee7a Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 26 Nov 2018 15:48:14 +0100 Subject: [PATCH 1991/4847] =?UTF-8?q?=E2=9E=95=20[wip]=20CommitDetailContr?= =?UTF-8?q?oller=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commit-detail-controller.test.js | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 test/controllers/commit-detail-controller.test.js diff --git a/test/controllers/commit-detail-controller.test.js b/test/controllers/commit-detail-controller.test.js new file mode 100644 index 0000000000..60065958c3 --- /dev/null +++ b/test/controllers/commit-detail-controller.test.js @@ -0,0 +1,74 @@ +import React from 'react'; +import moment from 'moment'; +import {shallow, mount} from 'enzyme'; + +import {cloneRepository, buildRepository} from '../helpers'; +import CommitDetailItem from '../../lib/items/commit-detail-item'; +import CommitDetailController from '../../lib/controllers/commit-detail-controller'; +import Commit from '../../lib/models/commit'; +import {multiFilePatchBuilder} from '../builder/patch'; + +describe.only('CommitDetailController', function() { + + let atomEnv, repository, commit; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + repository = await buildRepository(await cloneRepository('multiple-commits')); + commit = await repository.getCommit('18920c900bfa6e4844853e7e246607a31c3e2e8c'); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + function buildApp(override = {}) { + const props = { + repository, + commit, + itemType: CommitDetailItem, + + workspace: atomEnv.workspace, + commands: atomEnv.commands, + keymaps: atomEnv.keymaps, + tooltips: atomEnv.tooltips, + config: atomEnv.config, + destroy: () => {}, + + ...override, + }; + + return ; + } + + it('sets `disableStageUnstage` flag to true for MultiFilePatchController', function() { + const wrapper = mount(buildApp()); + assert.strictEqual(wrapper.find('MultiFilePatchController').prop('disableStageUnstage'), true); + }); + + it('passes unrecognized props to a MultiFilePatchController', function() { + const extra = Symbol('extra'); + const wrapper = shallow(buildApp({extra})); + + assert.strictEqual(wrapper.find('MultiFilePatchController').prop('extra'), extra); + }); + + it('renders commit details properly', function() { + const newCommit = new Commit({ + sha: '420', + authorEmail: 'very@nice.com', + authorDate: moment().subtract(2, 'days').unix(), + messageSubject: 'subject', + messageBody: 'messageBody 🌙', + }); + const {multiFilePatch: mfp} = multiFilePatchBuilder().addFilePatch().build(); + sinon.stub(newCommit, 'getMultiFileDiff').returns(mfp); + const wrapper = mount(buildApp({commit: newCommit})); + + assert.strictEqual(wrapper.find('h3.github-CommitDetailView-title').text(), 'subject'); + assert.strictEqual(wrapper.find('pre.github-CommitDetailView-moreText').text(), 'messageBody 🌙'); + assert.strictEqual(wrapper.find('span.github-CommitDetailView-metaText').text(), 'very@nice.com committed 2 days ago'); + + }); + +}); From a9c40efd824b676e1fbee568ed9351d6b883508d Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 26 Nov 2018 16:10:49 +0100 Subject: [PATCH 1992/4847] more tests --- test/controllers/commit-detail-controller.test.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/controllers/commit-detail-controller.test.js b/test/controllers/commit-detail-controller.test.js index 60065958c3..9764d2f00a 100644 --- a/test/controllers/commit-detail-controller.test.js +++ b/test/controllers/commit-detail-controller.test.js @@ -65,9 +65,12 @@ describe.only('CommitDetailController', function() { sinon.stub(newCommit, 'getMultiFileDiff').returns(mfp); const wrapper = mount(buildApp({commit: newCommit})); - assert.strictEqual(wrapper.find('h3.github-CommitDetailView-title').text(), 'subject'); - assert.strictEqual(wrapper.find('pre.github-CommitDetailView-moreText').text(), 'messageBody 🌙'); - assert.strictEqual(wrapper.find('span.github-CommitDetailView-metaText').text(), 'very@nice.com committed 2 days ago'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-title').text(), 'subject'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), 'messageBody 🌙'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-metaText').text(), 'very@nice.com committed 2 days ago'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-sha').text(), '420'); + /* TODO fix href test */ + assert.strictEqual(wrapper.find('.github-CommitDetailView-sha a').prop('href'), '420'); }); From dbe16e2946a489fdbd7785b59f9a66e473c2026c Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 26 Nov 2018 16:23:52 +0100 Subject: [PATCH 1993/4847] add test for co-authored commits --- .../commit-detail-controller.test.js | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/test/controllers/commit-detail-controller.test.js b/test/controllers/commit-detail-controller.test.js index 9764d2f00a..f7a2ad2e19 100644 --- a/test/controllers/commit-detail-controller.test.js +++ b/test/controllers/commit-detail-controller.test.js @@ -8,7 +8,7 @@ import CommitDetailController from '../../lib/controllers/commit-detail-controll import Commit from '../../lib/models/commit'; import {multiFilePatchBuilder} from '../builder/patch'; -describe.only('CommitDetailController', function() { +describe('CommitDetailController', function() { let atomEnv, repository, commit; @@ -59,19 +59,41 @@ describe.only('CommitDetailController', function() { authorEmail: 'very@nice.com', authorDate: moment().subtract(2, 'days').unix(), messageSubject: 'subject', - messageBody: 'messageBody 🌙', + messageBody: 'messageBody', }); const {multiFilePatch: mfp} = multiFilePatchBuilder().addFilePatch().build(); sinon.stub(newCommit, 'getMultiFileDiff').returns(mfp); const wrapper = mount(buildApp({commit: newCommit})); assert.strictEqual(wrapper.find('.github-CommitDetailView-title').text(), 'subject'); - assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), 'messageBody 🌙'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), 'messageBody'); assert.strictEqual(wrapper.find('.github-CommitDetailView-metaText').text(), 'very@nice.com committed 2 days ago'); assert.strictEqual(wrapper.find('.github-CommitDetailView-sha').text(), '420'); /* TODO fix href test */ - assert.strictEqual(wrapper.find('.github-CommitDetailView-sha a').prop('href'), '420'); + // assert.strictEqual(wrapper.find('.github-CommitDetailView-sha a').prop('href'), '420'); + assert.strictEqual(wrapper.find('img.github-RecentCommit-avatar').prop('src'), 'https://avatars.githubusercontent.com/u/e?email=very%40nice.com&s=32'); + }); + it('renders multiple avatars for co-authored commit', function() { + const newCommit = new Commit({ + sha: '420', + authorEmail: 'very@nice.com', + authorDate: moment().subtract(2, 'days').unix(), + messageSubject: 'subject', + messageBody: 'messageBody', + coAuthors: [{name: 'two', email: 'two@coauthor.com'}, {name: 'three', email: 'three@coauthor.com'}], + }); + const {multiFilePatch: mfp} = multiFilePatchBuilder().addFilePatch().build(); + sinon.stub(newCommit, 'getMultiFileDiff').returns(mfp); + const wrapper = mount(buildApp({commit: newCommit})); + assert.deepEqual( + wrapper.find('img.github-RecentCommit-avatar').map(w => w.prop('src')), + [ + 'https://avatars.githubusercontent.com/u/e?email=very%40nice.com&s=32', + 'https://avatars.githubusercontent.com/u/e?email=two%40coauthor.com&s=32', + 'https://avatars.githubusercontent.com/u/e?email=three%40coauthor.com&s=32', + ], + ); }); }); From ef7e68afbb11eb2a5d4a869292d430b16269ddf6 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 26 Nov 2018 16:28:03 +0100 Subject: [PATCH 1994/4847] verify multifilepatchcontroller better --- test/controllers/commit-detail-controller.test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/controllers/commit-detail-controller.test.js b/test/controllers/commit-detail-controller.test.js index f7a2ad2e19..d045d8b6d5 100644 --- a/test/controllers/commit-detail-controller.test.js +++ b/test/controllers/commit-detail-controller.test.js @@ -41,9 +41,10 @@ describe('CommitDetailController', function() { return ; } - it('sets `disableStageUnstage` flag to true for MultiFilePatchController', function() { + it('has a MultiFilePatchController that has `disableStageUnstage` flag set to true', function() { const wrapper = mount(buildApp()); - assert.strictEqual(wrapper.find('MultiFilePatchController').prop('disableStageUnstage'), true); + assert.isTrue(wrapper.find('MultiFilePatchController').exists()); + assert.isTrue(wrapper.find('MultiFilePatchController').prop('disableStageUnstage')); }); it('passes unrecognized props to a MultiFilePatchController', function() { From 9d15000b1202aca849aab3bb6aaba5c84438a9a1 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 27 Nov 2018 15:41:30 +0900 Subject: [PATCH 1995/4847] Update screenshots with the commit preview --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 04f232016b..07b7ea2bea 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ The Atom GitHub package provides Git and GitHub integration for Atom. Check out [github.atom.io](https://github.atom.io) for more information. -git-integration +GitHub for Atom -merge-conflicts +git-integration -github-integration +github-integration ## Installation From 7c7fb1acec4caa90c69736fcfeb115e5995079de Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 27 Nov 2018 15:12:43 -0500 Subject: [PATCH 1996/4847] Hand-offs explicitly in Slack Co-Authored-By: Katrina Uychaco --- docs/core-team-process.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/core-team-process.md b/docs/core-team-process.md index 5559ab93a7..3e9fe3406a 100644 --- a/docs/core-team-process.md +++ b/docs/core-team-process.md @@ -57,9 +57,9 @@ The problem at hand is decomposed into a queue of relatively independent tasks t ### 3. Hand-offs -In this method, each developer (or pair) tackles a single problem in serial during their working hours. When the next developer becomes available, the previous one writes a summary of their efforts and progress in a hand-off, either synchronously and interactively in Slack or asynchronously with a pull request comment. Once the next developer is caught up, they make progress and hand off to the next, and so on. +In this method, each developer (or pair) tackles a single problem in serial during their working hours. When the next developer becomes available, the previous one writes a summary of their efforts and progress in a hand-off, synchronously and interactively in a dedicated Slack channel. Once the next developer is caught up, they make progress and hand off to the next, and so on. -> Example: developer A logs in during their morning and works for a few hours on the next phase of a feature implementation. They make some progress on the model, but don't progress the controller beyond some stubs and don't get a chance to touch the view at all. When developer B logs in, developer A shares their progress with a conversation in Slack or Zoom until developer B is confident that they understand the problem's current state, at which point developer B begins working and making commits to the feature branch. Developer B implements the view, correcting and adding some methods to the model as needed. Finally, developer C logs in, and developers A and C pair to write the controller methods. They write a comment on the pull request as they wrap up describing the changes that they've made together. Developer B returns the next day, puts the finishing touches on the tests, writes or refines some documentation on the new code, and merges the pull request. +> Example: developer A logs in during their morning and works for a few hours on the next phase of a feature implementation. They make some progress on the model, but don't progress the controller beyond some stubs and don't get a chance to touch the view at all. When developer B logs in, developer A shares their progress with a conversation in Slack until developer B is confident that they understand the problem's current state, at which point developer B begins working and making commits to the feature branch. Developer B implements the view, correcting and adding some methods to the model as needed. Finally, developer C logs in, and developers A and C pair to write the controller methods. They update Slack with their progress as they wrap up describing the changes that they've made together. Developer B returns the next day, puts the finishing touches on the tests, writes or refines some documentation on the new code, and merges the pull request. :+1: _Advantages:_ From 3567cd17717920a122d370e937b5c6aa3fe7af8f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 27 Nov 2018 15:16:21 -0500 Subject: [PATCH 1997/4847] Feature-specific project board Co-Authored-By: Katrina Uychaco Co-Authored-By: Tilde Ann Thurium Co-Authored-By: Vanessa Yuen --- docs/core-team-process.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core-team-process.md b/docs/core-team-process.md index 3e9fe3406a..825ee6e974 100644 --- a/docs/core-team-process.md +++ b/docs/core-team-process.md @@ -103,7 +103,7 @@ Use a package configuration setting to control when features under development a ## All together -Each set of developers who are online synchronously can divide work into Seams. As that set changes when people come online and drop offline, we use Handoffs to pass context along. +Each set of developers who are online synchronously can divide work into Seams. As that set changes when people come online and drop offline, we use Handoffs to pass context along. Remaining tasking is tracked in a dedicated, loosely-managed feature project linked from the feature request PR. As we work, we push commits to a common branch, against a common pull request. Depending on the feature under construction, we either Dark Ship code in an early state or hide its entry points behind a Feature Flag. From 934a8565e83385d7682a332ff50bbb8b8351623b Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 27 Nov 2018 22:19:17 +0100 Subject: [PATCH 1998/4847] fix arguments passed during serialization --- lib/items/commit-detail-item.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/items/commit-detail-item.js b/lib/items/commit-detail-item.js index ed8f5f1936..ea29e43a9a 100644 --- a/lib/items/commit-detail-item.js +++ b/lib/items/commit-detail-item.js @@ -80,7 +80,7 @@ export default class CommitDetailItem extends React.Component { serialize() { return { deserializer: 'CommitDetailStub', - uri: CommitDetailItem.buildURI(this.props.sha), + uri: CommitDetailItem.buildURI(this.props.workingDirectory, this.props.sha), }; } From 1057245ed2326d1ec1b3866bb70815dc7aa5dc73 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 27 Nov 2018 22:30:17 +0100 Subject: [PATCH 1999/4847] get started with `CommitDetailItem` tests --- test/items/commit-detail-item.test.js | 73 +++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 test/items/commit-detail-item.test.js diff --git a/test/items/commit-detail-item.test.js b/test/items/commit-detail-item.test.js new file mode 100644 index 0000000000..4c236d03cc --- /dev/null +++ b/test/items/commit-detail-item.test.js @@ -0,0 +1,73 @@ +import React from 'react'; +import {mount} from 'enzyme'; + +import CommitDetailItem from '../../lib/items/commit-detail-item'; +import PaneItem from '../../lib/atom/pane-item'; +import WorkdirContextPool from '../../lib/models/workdir-context-pool'; +import {cloneRepository} from '../helpers'; + +describe.only('CommitDetailItem', function() { + let atomEnv, repository, pool; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + const workdir = await cloneRepository('multiple-commits'); + + pool = new WorkdirContextPool({ + workspace: atomEnv.workspace, + }); + + repository = pool.add(workdir).getRepository(); + }); + + afterEach(function() { + atomEnv.destroy(); + pool.clear(); + }); + + function buildPaneApp(override = {}) { + const props = { + workdirContextPool: pool, + workspace: atomEnv.workspace, + commands: atomEnv.commands, + keymaps: atomEnv.keymaps, + tooltips: atomEnv.tooltips, + config: atomEnv.config, + discardLines: () => {}, + ...override, + }; + + return ( + + {({itemHolder, params}) => { + return ( + + ); + }} + + ); + } + + function open(wrapper, options = {}) { + const opts = { + workingDirectory: repository.getWorkingDirectoryPath(), + sha: '18920c900bfa6e4844853e7e246607a31c3e2e8c', + ...options, + }; + const uri = CommitDetailItem.buildURI(opts.workingDirectory); + return atomEnv.workspace.open(uri); + } + + it('constructs and opens the correct URI', async function() { + const wrapper = mount(buildPaneApp()); + await open(wrapper); + + assert.isTrue(wrapper.update().find('CommitDetailItem').exists()); + }); + +}); From b75bab63cd4861084d139d138571436fa73ef028 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 27 Nov 2018 22:37:33 +0100 Subject: [PATCH 2000/4847] add several more tests --- test/items/commit-detail-item.test.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/test/items/commit-detail-item.test.js b/test/items/commit-detail-item.test.js index 4c236d03cc..f0bc2eeb89 100644 --- a/test/items/commit-detail-item.test.js +++ b/test/items/commit-detail-item.test.js @@ -59,7 +59,7 @@ describe.only('CommitDetailItem', function() { sha: '18920c900bfa6e4844853e7e246607a31c3e2e8c', ...options, }; - const uri = CommitDetailItem.buildURI(opts.workingDirectory); + const uri = CommitDetailItem.buildURI(opts.workingDirectory, opts.sha); return atomEnv.workspace.open(uri); } @@ -70,4 +70,27 @@ describe.only('CommitDetailItem', function() { assert.isTrue(wrapper.update().find('CommitDetailItem').exists()); }); + it('passes extra props to its container', async function() { + const extra = Symbol('extra'); + const wrapper = mount(buildPaneApp({extra})); + await open(wrapper); + + assert.strictEqual(wrapper.update().find('CommitDetailItem').prop('extra'), extra); + }); + + it('serializes itself as a CommitDetailItem', async function() { + const wrapper = mount(buildPaneApp()); + const item0 = await open(wrapper, {workingDirectory: '/dir0', sha: '420'}); + assert.deepEqual(item0.serialize(), { + deserializer: 'CommitDetailStub', + uri: 'atom-github://commit-detail?workdir=%2Fdir0&sha=420', + }); + + const item1 = await open(wrapper, {workingDirectory: '/dir1', sha: '1337'}); + assert.deepEqual(item1.serialize(), { + deserializer: 'CommitDetailStub', + uri: 'atom-github://commit-detail?workdir=%2Fdir1&sha=1337', + }); + }); + }); From 5add6404099bfdc7263db5907bd579cd327ff27d Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 27 Nov 2018 22:43:50 +0100 Subject: [PATCH 2001/4847] and MOAR --- test/items/commit-detail-item.test.js | 52 +++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/items/commit-detail-item.test.js b/test/items/commit-detail-item.test.js index f0bc2eeb89..4d0f376986 100644 --- a/test/items/commit-detail-item.test.js +++ b/test/items/commit-detail-item.test.js @@ -93,4 +93,56 @@ describe.only('CommitDetailItem', function() { }); }); + it('locates the repository from the context pool', async function() { + const wrapper = mount(buildPaneApp()); + await open(wrapper); + + assert.strictEqual(wrapper.update().find('CommitDetailContainer').prop('repository'), repository); + }); + + it('passes an absent repository if the working directory is unrecognized', async function() { + const wrapper = mount(buildPaneApp()); + await open(wrapper, {workingDirectory: '/nah'}); + + assert.isTrue(wrapper.update().find('CommitDetailContainer').prop('repository').isAbsent()); + }); + + it('returns a fixed title and icon', async function() { + const wrapper = mount(buildPaneApp()); + const item = await open(wrapper, {sha: '1337'}); + + assert.strictEqual(item.getTitle(), 'Commit: 1337'); + assert.strictEqual(item.getIconName(), 'git-commit'); + }); + + it('terminates pending state', async function() { + const wrapper = mount(buildPaneApp()); + + const item = await open(wrapper); + const callback = sinon.spy(); + const sub = item.onDidTerminatePendingState(callback); + + assert.strictEqual(callback.callCount, 0); + item.terminatePendingState(); + assert.strictEqual(callback.callCount, 1); + item.terminatePendingState(); + assert.strictEqual(callback.callCount, 1); + + sub.dispose(); + }); + + it('may be destroyed once', async function() { + const wrapper = mount(buildPaneApp()); + + const item = await open(wrapper); + const callback = sinon.spy(); + const sub = item.onDidDestroy(callback); + + assert.strictEqual(callback.callCount, 0); + item.destroy(); + assert.strictEqual(callback.callCount, 1); + + sub.dispose(); + }); + }); From 81315d2fbde0f852339a6c82450494e7afcd5c6e Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 27 Nov 2018 23:00:06 +0100 Subject: [PATCH 2002/4847] add sha accessor --- lib/items/commit-detail-item.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/items/commit-detail-item.js b/lib/items/commit-detail-item.js index ea29e43a9a..fdfc39e638 100644 --- a/lib/items/commit-detail-item.js +++ b/lib/items/commit-detail-item.js @@ -77,6 +77,10 @@ export default class CommitDetailItem extends React.Component { return this.props.workingDirectory; } + getSha() { + return this.props.sha; + } + serialize() { return { deserializer: 'CommitDetailStub', From 7a10d03841f473b529a31f39326608d74e9550ba Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 27 Nov 2018 23:00:34 +0100 Subject: [PATCH 2003/4847] i *think* this is it for `CommitDetailItem` tests??? :thinking: --- test/items/commit-detail-item.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/items/commit-detail-item.test.js b/test/items/commit-detail-item.test.js index 4d0f376986..7199b6b20d 100644 --- a/test/items/commit-detail-item.test.js +++ b/test/items/commit-detail-item.test.js @@ -145,4 +145,11 @@ describe.only('CommitDetailItem', function() { sub.dispose(); }); + it('has an item-level accessor for the current working directory & sha', async function() { + const wrapper = mount(buildPaneApp()); + const item = await open(wrapper, {workingDirectory: '/dir7', sha: '420'}); + assert.strictEqual(item.getWorkingDirectory(), '/dir7'); + assert.strictEqual(item.getSha(), '420'); + }); + }); From ae893960013187a712f4c8aad45541366f152fec Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 28 Nov 2018 21:34:05 +0900 Subject: [PATCH 2004/4847] Add focus styling to selections --- styles/file-patch-view.less | 61 +++++++++++++++++++++++++----------- styles/hunk-header-view.less | 24 +++++++++++--- 2 files changed, 63 insertions(+), 22 deletions(-) diff --git a/styles/file-patch-view.less b/styles/file-patch-view.less index 3de411746a..fcf9a7cb48 100644 --- a/styles/file-patch-view.less +++ b/styles/file-patch-view.less @@ -32,14 +32,6 @@ } } - // Editor overrides - - atom-text-editor { - .selection .region { - background-color: mix(@button-background-color-selected, @syntax-background-color, 24%); - } - } - &-header { display: flex; justify-content: space-between; @@ -220,11 +212,6 @@ min-width: 6ch; // Fit up to 4 characters (+1 padding on each side) opacity: 1; padding: 0 1ch 0 0; - - &.github-FilePatchView-line--selected { - color: contrast(@button-background-color-selected); - background: @button-background-color-selected; - } } &.icons .line-number { @@ -249,11 +236,6 @@ &.github-FilePatchView-line--nonewline:before { content: @no-newline; } - - &.github-FilePatchView-line--selected { - color: contrast(@button-background-color-selected); - background: @button-background-color-selected; - } } } @@ -272,6 +254,49 @@ } } + +// States + +// Selected +.github-FilePatchView { + .gutter { + &.old .line-number, + &.new .line-number, + &.icons .line-number { + &.github-FilePatchView-line--selected { + color: @text-color-selected; + background: @background-color-selected; + } + } + } + + atom-text-editor { + .selection .region { + background-color: transparent; + } + } +} + +// Selected + focused +.github-FilePatchView:focus-within { + .gutter { + &.old .line-number, + &.new .line-number, + &.icons .line-number { + &.github-FilePatchView-line--selected { + color: contrast(@button-background-color-selected); + background: @button-background-color-selected; + } + } + } + + atom-text-editor { + .selection .region { + background-color: mix(@button-background-color-selected, @syntax-background-color, 24%); + } + } +} + .gitub-FilePatchHeaderView-basename { font-weight: bold; } diff --git a/styles/hunk-header-view.less b/styles/hunk-header-view.less index 11cffdec76..5d4bfa61de 100644 --- a/styles/hunk-header-view.less +++ b/styles/hunk-header-view.less @@ -68,9 +68,10 @@ } } +// Selected .github-HunkHeaderView--isSelected { - color: contrast(@button-background-color-selected); - background-color: @button-background-color-selected; + color: @text-color-selected; + background-color: @background-color-selected; border-color: transparent; .github-HunkHeaderView-title { color: inherit; @@ -78,7 +79,22 @@ .github-HunkHeaderView-title, .github-HunkHeaderView-stageButton, .github-HunkHeaderView-discardButton { - &:hover { background-color: lighten(@button-background-color-selected, 4%); } - &:active { background-color: darken(@button-background-color-selected, 4%); } + &:hover { background-color: @background-color-highlight; } + &:active { background-color: @background-color-selected; } + } +} + + +// Selected + focused +.github-FilePatchView:focus-within { + .github-HunkHeaderView--isSelected { + color: contrast(@button-background-color-selected); + background-color: @button-background-color-selected; + .github-HunkHeaderView-title, + .github-HunkHeaderView-stageButton, + .github-HunkHeaderView-discardButton { + &:hover { background-color: lighten(@button-background-color-selected, 4%); } + &:active { background-color: darken(@button-background-color-selected, 4%); } + } } } From cdbe9ea4a9dd3bdfeb198c907ed14effb63fc74d Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 28 Nov 2018 21:47:59 +0900 Subject: [PATCH 2005/4847] Add hover styles to recent commits --- styles/recent-commits.less | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/styles/recent-commits.less b/styles/recent-commits.less index 31e0d2034c..f9ad97ef66 100644 --- a/styles/recent-commits.less +++ b/styles/recent-commits.less @@ -87,6 +87,11 @@ color: @text-color-subtle; } + &:hover { + color: @text-color-highlight; + background: @background-color-highlight; + } + &.is-selected { // is selected color: @text-color-selected; From a537d84956fd909e150bfae0698c6c4cdd0661c8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 09:53:19 -0500 Subject: [PATCH 2006/4847] Allow the FilePatchView to control scrolling within the AtomTextEditor Ensuring that the is the element that handles scrolling within the DOM gives us a substantial performance boost, because it can tile its lines and decorations and render much less content on any given frame. Moving the scrolling here gets us a "fixed" header for free, too :wink: --- lib/controllers/commit-detail-controller.js | 2 +- styles/commit-detail.less | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/controllers/commit-detail-controller.js b/lib/controllers/commit-detail-controller.js index ab5ca27953..d73bf852f2 100644 --- a/lib/controllers/commit-detail-controller.js +++ b/lib/controllers/commit-detail-controller.js @@ -55,7 +55,7 @@ export default class CommitDetailController extends React.Component {
    diff --git a/styles/commit-detail.less b/styles/commit-detail.less index fc8db7a940..6f8c24f975 100644 --- a/styles/commit-detail.less +++ b/styles/commit-detail.less @@ -3,19 +3,13 @@ @default-padding: @component-padding; @avatar-dimensions: 16px; -.github-CommitDetail { - - &-root { - // TODO: Remove if CommitDetailView gets moved to a editor decoration - overflow-y: auto; - } - -} - - .github-CommitDetailView { + display: flex; + flex-direction: column; + height: 100%; &-header { + flex: 0; padding: @default-padding; padding-bottom: 0; background-color: @syntax-background-color; From 5c7aa08f03effb162b2408255cd0d2e08c9fda5c Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 28 Nov 2018 14:51:58 +0100 Subject: [PATCH 2007/4847] remove jump to file --- lib/views/file-patch-header-view.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/views/file-patch-header-view.js b/lib/views/file-patch-header-view.js index c76311f353..5eb5476d08 100644 --- a/lib/views/file-patch-header-view.js +++ b/lib/views/file-patch-header-view.js @@ -74,14 +74,18 @@ export default class FilePatchHeaderView extends React.Component { } renderButtonGroup() { - return ( - - {!this.props.disableStageUnstage && this.renderUndoDiscardButton()} - {!this.props.disableStageUnstage && this.renderMirrorPatchButton()} - {this.renderOpenFileButton()} - {!this.props.disableStageUnstage && this.renderToggleFileButton()} - - ); + if (this.props.disableStageUnstage) { + return null; + } else { + return ( + + {this.renderUndoDiscardButton()} + {this.renderMirrorPatchButton()} + {this.renderOpenFileButton()} + {this.renderToggleFileButton()} + + ); + } } renderUndoDiscardButton() { From fc6ca8ac95dc2d25627383a4347cbe788bfdea2e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 10:38:09 -0500 Subject: [PATCH 2008/4847] Cover that last line in CommitDetailItem --- test/items/commit-detail-item.test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/items/commit-detail-item.test.js b/test/items/commit-detail-item.test.js index 7199b6b20d..6a6d4e89d3 100644 --- a/test/items/commit-detail-item.test.js +++ b/test/items/commit-detail-item.test.js @@ -152,4 +152,17 @@ describe.only('CommitDetailItem', function() { assert.strictEqual(item.getSha(), '420'); }); + it('passes a focus() call to the component designated as its initial focus', async function() { + const wrapper = mount(buildPaneApp()); + const item = await open(wrapper); + wrapper.update(); + + const refHolder = wrapper.find('CommitDetailContainer').prop('refInitialFocus'); + const initialFocus = await refHolder.getPromise(); + sinon.spy(initialFocus, 'focus'); + + item.focus(); + + assert.isTrue(initialFocus.focus.called); + }); }); From b61b9ae96f5c4ee89941f2f86730fece51d88ea2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 10:38:16 -0500 Subject: [PATCH 2009/4847] :fire: dot only --- test/items/commit-detail-item.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/items/commit-detail-item.test.js b/test/items/commit-detail-item.test.js index 6a6d4e89d3..eecbc66cf6 100644 --- a/test/items/commit-detail-item.test.js +++ b/test/items/commit-detail-item.test.js @@ -6,7 +6,7 @@ import PaneItem from '../../lib/atom/pane-item'; import WorkdirContextPool from '../../lib/models/workdir-context-pool'; import {cloneRepository} from '../helpers'; -describe.only('CommitDetailItem', function() { +describe('CommitDetailItem', function() { let atomEnv, repository, pool; beforeEach(async function() { From 867397f5b48266a486fb3a509762377a7ed8c7f3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 10:46:13 -0500 Subject: [PATCH 2010/4847] Ensure we return a valid Commit to suppress console errors --- test/containers/commit-detail-container.test.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/containers/commit-detail-container.test.js b/test/containers/commit-detail-container.test.js index 2fccdc3614..e4dff8718f 100644 --- a/test/containers/commit-detail-container.test.js +++ b/test/containers/commit-detail-container.test.js @@ -5,6 +5,8 @@ import CommitDetailContainer from '../../lib/containers/commit-detail-container' import CommitDetailItem from '../../lib/items/commit-detail-item'; import {cloneRepository, buildRepository} from '../helpers'; +const VALID_SHA = '18920c900bfa6e4844853e7e246607a31c3e2e8c'; + describe('CommitDetailContainer', function() { let atomEnv, repository; @@ -23,7 +25,7 @@ describe('CommitDetailContainer', function() { const props = { repository, - sha: '18920c900bfa6e4844853e7e246607a31c3e2e8c', + sha: VALID_SHA, itemType: CommitDetailItem, workspace: atomEnv.workspace, @@ -47,7 +49,7 @@ describe('CommitDetailContainer', function() { it('renders a loading spinner while the file patch is being loaded', async function() { await repository.getLoadPromise(); - const patchPromise = repository.getStagedChangesPatch(); + const commitPromise = repository.getCommit(VALID_SHA); let resolveDelayedPromise = () => {}; const delayedPromise = new Promise(resolve => { resolveDelayedPromise = resolve; @@ -57,13 +59,13 @@ describe('CommitDetailContainer', function() { const wrapper = mount(buildApp()); assert.isTrue(wrapper.find('LoadingView').exists()); - resolveDelayedPromise(patchPromise); + resolveDelayedPromise(commitPromise); await assert.async.isFalse(wrapper.update().find('LoadingView').exists()); }); it('renders a CommitDetailController once the commit is loaded', async function() { await repository.getLoadPromise(); - const commit = await repository.getCommit('18920c900bfa6e4844853e7e246607a31c3e2e8c'); + const commit = await repository.getCommit(VALID_SHA); const wrapper = mount(buildApp()); await assert.async.isTrue(wrapper.update().find('CommitDetailController').exists()); From b27744610eab776f72814bbc14fe7bc480fcbe1e Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 28 Nov 2018 18:50:04 +0100 Subject: [PATCH 2011/4847] remove `disableStageUnstage` flag and use `itemType` as checker instead --- lib/controllers/commit-detail-controller.js | 1 - lib/controllers/multi-file-patch-controller.js | 1 - lib/views/file-patch-header-view.js | 3 +-- lib/views/hunk-header-view.js | 1 - lib/views/multi-file-patch-view.js | 4 ---- test/controllers/commit-detail-controller.test.js | 3 +-- 6 files changed, 2 insertions(+), 11 deletions(-) diff --git a/lib/controllers/commit-detail-controller.js b/lib/controllers/commit-detail-controller.js index d73bf852f2..b5b3c3f5bb 100644 --- a/lib/controllers/commit-detail-controller.js +++ b/lib/controllers/commit-detail-controller.js @@ -57,7 +57,6 @@ export default class CommitDetailController extends React.Component { multiFilePatch={commit.getMultiFileDiff()} autoHeight={false} {...this.props} - disableStageUnstage={true} />
    ); diff --git a/lib/controllers/multi-file-patch-controller.js b/lib/controllers/multi-file-patch-controller.js index 139d15a0a3..667184aae4 100644 --- a/lib/controllers/multi-file-patch-controller.js +++ b/lib/controllers/multi-file-patch-controller.js @@ -26,7 +26,6 @@ export default class MultiFilePatchController extends React.Component { undoLastDiscard: PropTypes.func, surface: PropTypes.func, autoHeight: PropTypes.bool, - disableStageUnstage: PropTypes.bool, } constructor(props) { diff --git a/lib/views/file-patch-header-view.js b/lib/views/file-patch-header-view.js index 5eb5476d08..51131689f0 100644 --- a/lib/views/file-patch-header-view.js +++ b/lib/views/file-patch-header-view.js @@ -26,7 +26,6 @@ export default class FilePatchHeaderView extends React.Component { toggleFile: PropTypes.func.isRequired, itemType: PropTypes.oneOf([ChangedFileItem, CommitPreviewItem, CommitDetailItem]).isRequired, - disableStageUnstage: PropTypes.bool, }; constructor(props) { @@ -74,7 +73,7 @@ export default class FilePatchHeaderView extends React.Component { } renderButtonGroup() { - if (this.props.disableStageUnstage) { + if (this.props.itemType === CommitDetailItem) { return null; } else { return ( diff --git a/lib/views/hunk-header-view.js b/lib/views/hunk-header-view.js index 0c4dd8516d..57e71a28a3 100644 --- a/lib/views/hunk-header-view.js +++ b/lib/views/hunk-header-view.js @@ -28,7 +28,6 @@ export default class HunkHeaderView extends React.Component { toggleSelection: PropTypes.func, discardSelection: PropTypes.func, mouseDown: PropTypes.func.isRequired, - disableStageUnstage: PropTypes.bool, }; constructor(props) { diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index a066c29bac..3cb5a61731 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -59,7 +59,6 @@ export default class MultiFilePatchView extends React.Component { undoLastDiscard: PropTypes.func, discardRows: PropTypes.func, autoHeight: PropTypes.bool, - disableStageUnstage: PropTypes.bool, refInitialFocus: RefHolderPropType, itemType: PropTypes.oneOf([ChangedFileItem, CommitPreviewItem, CommitDetailItem]).isRequired, } @@ -329,7 +328,6 @@ export default class MultiFilePatchView extends React.Component { diveIntoMirrorPatch={() => this.props.diveIntoMirrorPatch(filePatch)} openFile={() => this.didOpenFile({selectedFilePatch: filePatch})} toggleFile={() => this.props.toggleFile(filePatch)} - disableStageUnstage={this.props.disableStageUnstage} /> {this.renderSymlinkChangeMeta(filePatch)} {this.renderExecutableModeChangeMeta(filePatch)} @@ -505,8 +503,6 @@ export default class MultiFilePatchView extends React.Component { toggleSelection={() => this.toggleHunkSelection(hunk, containsSelection)} discardSelection={() => this.discardHunkSelection(hunk, containsSelection)} mouseDown={this.didMouseDownOnHeader} - - disableStageUnstage={this.props.disableStageUnstage} /> diff --git a/test/controllers/commit-detail-controller.test.js b/test/controllers/commit-detail-controller.test.js index d045d8b6d5..92a5659a22 100644 --- a/test/controllers/commit-detail-controller.test.js +++ b/test/controllers/commit-detail-controller.test.js @@ -41,10 +41,9 @@ describe('CommitDetailController', function() { return ; } - it('has a MultiFilePatchController that has `disableStageUnstage` flag set to true', function() { + it('has a MultiFilePatchController', function() { const wrapper = mount(buildApp()); assert.isTrue(wrapper.find('MultiFilePatchController').exists()); - assert.isTrue(wrapper.find('MultiFilePatchController').prop('disableStageUnstage')); }); it('passes unrecognized props to a MultiFilePatchController', function() { From e8620da653cefc3b17e988e11175d927ee667aa1 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 28 Nov 2018 18:50:35 +0100 Subject: [PATCH 2012/4847] use `itemType` in hunk headers too! --- lib/views/hunk-header-view.js | 6 +++++- lib/views/multi-file-patch-view.js | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/views/hunk-header-view.js b/lib/views/hunk-header-view.js index 57e71a28a3..6fd986ee54 100644 --- a/lib/views/hunk-header-view.js +++ b/lib/views/hunk-header-view.js @@ -7,6 +7,9 @@ import {RefHolderPropType} from '../prop-types'; import RefHolder from '../models/ref-holder'; import Tooltip from '../atom/tooltip'; import Keystroke from '../atom/keystroke'; +import ChangedFileItem from '../items/changed-file-item'; +import CommitPreviewItem from '../items/commit-preview-item'; +import CommitDetailItem from '../items/commit-detail-item'; function theBuckStopsHere(event) { event.stopPropagation(); @@ -28,6 +31,7 @@ export default class HunkHeaderView extends React.Component { toggleSelection: PropTypes.func, discardSelection: PropTypes.func, mouseDown: PropTypes.func.isRequired, + itemType: PropTypes.oneOf([ChangedFileItem, CommitPreviewItem, CommitDetailItem]).isRequired, }; constructor(props) { @@ -54,7 +58,7 @@ export default class HunkHeaderView extends React.Component { } renderButtons() { - if (this.props.disableStageUnstage) { + if (this.props.itemType === CommitPreviewItem) { return null; } else { return ( diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 3cb5a61731..5e3d3d73bf 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -503,6 +503,7 @@ export default class MultiFilePatchView extends React.Component { toggleSelection={() => this.toggleHunkSelection(hunk, containsSelection)} discardSelection={() => this.discardHunkSelection(hunk, containsSelection)} mouseDown={this.didMouseDownOnHeader} + itemType={this.props.itemType} /> From 22718c24c38b98b0b4cfbe7e9e9020373a0a0eac Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 13:48:21 -0500 Subject: [PATCH 2013/4847] Totally arbitrary "long commit message threshold" --- lib/models/commit.js | 10 ++++++++ test/models/commit.test.js | 51 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 test/models/commit.test.js diff --git a/lib/models/commit.js b/lib/models/commit.js index f1fbd72a1c..c568de8066 100644 --- a/lib/models/commit.js +++ b/lib/models/commit.js @@ -1,6 +1,8 @@ const UNBORN = Symbol('unborn'); export default class Commit { + static LONG_MESSAGE_THRESHOLD = 1000; + static createUnborn() { return new Commit({unbornRef: UNBORN}); } @@ -40,6 +42,10 @@ export default class Commit { return this.messageBody; } + isBodyLong() { + return this.getMessageBody().length > this.constructor.LONG_MESSAGE_THRESHOLD; + } + getFullMessage() { return `${this.getMessageSubject()}\n\n${this.getMessageBody()}`.trim(); } @@ -77,4 +83,8 @@ export const nullCommit = { isPresent() { return false; }, + + isBodyLong() { + return false; + }, }; diff --git a/test/models/commit.test.js b/test/models/commit.test.js new file mode 100644 index 0000000000..a8cd468a4c --- /dev/null +++ b/test/models/commit.test.js @@ -0,0 +1,51 @@ +import moment from 'moment'; +import dedent from 'dedent-js'; + +import Commit, {nullCommit} from '../../lib/models/commit'; + +describe('Commit', function() { + function buildCommit(override = {}) { + return new Commit({ + sha: '0123456789abcdefghij0123456789abcdefghij', + authorEmail: 'me@email.com', + coAuthors: [], + authorDate: moment('2018-11-28T12:00:00', moment.ISO_8601).unix(), + messageSubject: 'subject', + messageBody: 'body', + ...override, + }); + } + + describe('isBodyLong()', function() { + it('returns false if the commit message body is short', function() { + assert.isFalse(buildCommit({messageBody: 'short'}).isBodyLong()); + }); + + it('returns true if the commit message body is long', function() { + const messageBody = dedent` + Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. Mazim alterum sea ea, + essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore albucius te vis, eam + tantas nullam corrumpit ad, in oratio luptatum eleifend vim. + + Ea salutatus contentiones eos. Eam in veniam facete volutpat, solum appetere adversarium ut quo. Vel cu appetere + urbanitas, usu ut aperiri mediocritatem, alia molestie urbanitas cu qui. Velit antiopam erroribus no eum, + scripta iudicabit ne nam, in duis clita commodo sit. + + Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat comprehensam ut his, et eum + voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei liber putant. Ad doctus + tractatos ius, duo ad civibus alienum, nominati voluptaria sed an. Libris essent philosophia et vix. Nusquam + reprehendunt et mea. Ea eius omnes voluptua sit. + + No cum illud verear efficiantur. Id altera imperdiet nec. Noster audiam accusamus mei at, no zril libris nemore + duo, ius ne rebum doctus fuisset. Legimus epicurei in sit, esse purto suscipit eu qui, oporteat deserunt + delicatissimi sea in. Est id putent accusata convenire, no tibique molestie accommodare quo, cu est fuisset + offendit evertitur. + `; + assert.isTrue(buildCommit({messageBody}).isBodyLong()); + }); + + it('returns false for a null commit', function() { + assert.isFalse(nullCommit.isBodyLong()); + }); + }); +}); From 8434c08aec30d92726d4ac2599297d1e132ddf19 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 13:59:03 -0500 Subject: [PATCH 2014/4847] CommitDetailController is only responsible for message collapse state All markup generation has been moved (verbatim) to CommitDetailView. --- lib/controllers/commit-detail-controller.js | 102 +++------------- lib/views/commit-detail-view.js | 102 ++++++++++++++++ .../commit-detail-controller.test.js | 110 ++++++++++-------- test/views/commit-detail-view.test.js | 69 +++++++++++ 4 files changed, 248 insertions(+), 135 deletions(-) create mode 100644 lib/views/commit-detail-view.js create mode 100644 test/views/commit-detail-view.test.js diff --git a/lib/controllers/commit-detail-controller.js b/lib/controllers/commit-detail-controller.js index b5b3c3f5bb..6e0df0c146 100644 --- a/lib/controllers/commit-detail-controller.js +++ b/lib/controllers/commit-detail-controller.js @@ -1,104 +1,38 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {emojify} from 'node-emoji'; -import moment from 'moment'; -import MultiFilePatchController from './multi-file-patch-controller'; - -const avatarAltText = 'committer avatar'; +import CommitDetailView from '../views/commit-detail-view'; export default class CommitDetailController extends React.Component { static propTypes = { - repository: PropTypes.object.isRequired, - - workspace: PropTypes.object.isRequired, - commands: PropTypes.object.isRequired, - keymaps: PropTypes.object.isRequired, - tooltips: PropTypes.object.isRequired, - config: PropTypes.object.isRequired, + ...CommitDetailView.propTypes, - destroy: PropTypes.func.isRequired, commit: PropTypes.object.isRequired, } - render() { - const commit = this.props.commit; - // const {messageHeadline, messageBody, abbreviatedOid, url} = this.props.item; - // const {avatarUrl, name, date} = this.props.item.committer; - - return ( -
    -
    -
    -
    -

    - {emojify(commit.getMessageSubject())} -

    -
    -                {emojify(commit.getMessageBody())}
    -
    - {/* TODO fix image src */} - {this.renderAuthors()} - - {commit.getAuthorEmail()} committed {this.humanizeTimeSince(commit.getAuthorDate())} - -
    -
    -
    - {/* TODO fix href */} - - {commit.getSha()} - -
    -
    -
    - -
    - ); - } + constructor(props) { + super(props); - humanizeTimeSince(date) { - return moment(date * 1000).fromNow(); + this.state = { + messageCollapsible: this.props.commit.isBodyLong(), + messageOpen: !this.props.commit.isBodyLong(), + }; } - getAuthorInfo() { - const coAuthorCount = this.props.commit.getCoAuthors().length; - return coAuthorCount ? this.props.commit.getAuthorEmail() : `${coAuthorCount + 1} people`; - } - - renderAuthor(email) { - const match = email.match(/^(\d+)\+[^@]+@users.noreply.github.com$/); - - let avatarUrl; - if (match) { - avatarUrl = 'https://avatars.githubusercontent.com/u/' + match[1] + '?s=32'; - } else { - avatarUrl = 'https://avatars.githubusercontent.com/u/e?email=' + encodeURIComponent(email) + '&s=32'; - } - + render() { return ( - {`${email}'s ); } - renderAuthors() { - const coAuthorEmails = this.props.commit.getCoAuthors().map(author => author.email); - const authorEmails = [this.props.commit.getAuthorEmail(), ...coAuthorEmails]; - - return ( - - {authorEmails.map(this.renderAuthor)} - - ); + toggleMessage = () => { + return new Promise(resolve => { + this.setState(prevState => ({messageOpen: !prevState.messageOpen}), resolve); + }); } } diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js new file mode 100644 index 0000000000..96b38f1ec6 --- /dev/null +++ b/lib/views/commit-detail-view.js @@ -0,0 +1,102 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {emojify} from 'node-emoji'; +import moment from 'moment'; + +import MultiFilePatchController from '../controllers/multi-file-patch-controller'; + +export default class CommitDetailView extends React.Component { + static propTypes = { + repository: PropTypes.object.isRequired, + + workspace: PropTypes.object.isRequired, + commands: PropTypes.object.isRequired, + keymaps: PropTypes.object.isRequired, + tooltips: PropTypes.object.isRequired, + config: PropTypes.object.isRequired, + + destroy: PropTypes.func.isRequired, + commit: PropTypes.object.isRequired, + } + + render() { + const commit = this.props.commit; + // const {messageHeadline, messageBody, abbreviatedOid, url} = this.props.item; + // const {avatarUrl, name, date} = this.props.item.committer; + + return ( +
    +
    +
    +
    +

    + {emojify(commit.getMessageSubject())} +

    +
    +                {emojify(commit.getMessageBody())}
    +
    + {/* TODO fix image src */} + {this.renderAuthors()} + + {commit.getAuthorEmail()} committed {this.humanizeTimeSince(commit.getAuthorDate())} + +
    +
    +
    + {/* TODO fix href */} + + {commit.getSha()} + +
    +
    +
    + +
    + ); + } + + humanizeTimeSince(date) { + return moment(date * 1000).fromNow(); + } + + getAuthorInfo() { + const coAuthorCount = this.props.commit.getCoAuthors().length; + return coAuthorCount ? this.props.commit.getAuthorEmail() : `${coAuthorCount + 1} people`; + } + + renderAuthor(email) { + const match = email.match(/^(\d+)\+[^@]+@users.noreply.github.com$/); + + let avatarUrl; + if (match) { + avatarUrl = 'https://avatars.githubusercontent.com/u/' + match[1] + '?s=32'; + } else { + avatarUrl = 'https://avatars.githubusercontent.com/u/e?email=' + encodeURIComponent(email) + '&s=32'; + } + + return ( + {`${email}'s + ); + } + + renderAuthors() { + const coAuthorEmails = this.props.commit.getCoAuthors().map(author => author.email); + const authorEmails = [this.props.commit.getAuthorEmail(), ...coAuthorEmails]; + + return ( + + {authorEmails.map(this.renderAuthor)} + + ); + } +} diff --git a/test/controllers/commit-detail-controller.test.js b/test/controllers/commit-detail-controller.test.js index 92a5659a22..2231af47da 100644 --- a/test/controllers/commit-detail-controller.test.js +++ b/test/controllers/commit-detail-controller.test.js @@ -1,21 +1,20 @@ import React from 'react'; -import moment from 'moment'; -import {shallow, mount} from 'enzyme'; +import {shallow} from 'enzyme'; +import dedent from 'dedent-js'; import {cloneRepository, buildRepository} from '../helpers'; import CommitDetailItem from '../../lib/items/commit-detail-item'; import CommitDetailController from '../../lib/controllers/commit-detail-controller'; -import Commit from '../../lib/models/commit'; -import {multiFilePatchBuilder} from '../builder/patch'; -describe('CommitDetailController', function() { +const VALID_SHA = '18920c900bfa6e4844853e7e246607a31c3e2e8c'; +describe('CommitDetailController', function() { let atomEnv, repository, commit; beforeEach(async function() { atomEnv = global.buildAtomEnvironment(); repository = await buildRepository(await cloneRepository('multiple-commits')); - commit = await repository.getCommit('18920c900bfa6e4844853e7e246607a31c3e2e8c'); + commit = await repository.getCommit(VALID_SHA); }); afterEach(function() { @@ -41,59 +40,68 @@ describe('CommitDetailController', function() { return ; } - it('has a MultiFilePatchController', function() { - const wrapper = mount(buildApp()); - assert.isTrue(wrapper.find('MultiFilePatchController').exists()); + it('forwards props to its CommitDetailView', function() { + const wrapper = shallow(buildApp()); + const view = wrapper.find('CommitDetailView'); + + assert.strictEqual(view.prop('repository'), repository); + assert.strictEqual(view.prop('commit'), commit); + assert.strictEqual(view.prop('itemType'), CommitDetailItem); }); - it('passes unrecognized props to a MultiFilePatchController', function() { + it('passes unrecognized props to its CommitDetailView', function() { const extra = Symbol('extra'); const wrapper = shallow(buildApp({extra})); - - assert.strictEqual(wrapper.find('MultiFilePatchController').prop('extra'), extra); + assert.strictEqual(wrapper.find('CommitDetailView').prop('extra'), extra); }); - it('renders commit details properly', function() { - const newCommit = new Commit({ - sha: '420', - authorEmail: 'very@nice.com', - authorDate: moment().subtract(2, 'days').unix(), - messageSubject: 'subject', - messageBody: 'messageBody', + describe('commit body collapsing', function() { + const LONG_MESSAGE = dedent` + Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. Mazim alterum sea ea, + essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore albucius te vis, eam + tantas nullam corrumpit ad, in oratio luptatum eleifend vim. + + Ea salutatus contentiones eos. Eam in veniam facete volutpat, solum appetere adversarium ut quo. Vel cu appetere + urbanitas, usu ut aperiri mediocritatem, alia molestie urbanitas cu qui. Velit antiopam erroribus no eum, scripta + iudicabit ne nam, in duis clita commodo sit. + + Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat comprehensam ut his, et eum + voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei liber putant. Ad doctus tractatos + ius, duo ad civibus alienum, nominati voluptaria sed an. Libris essent philosophia et vix. Nusquam reprehendunt et + mea. Ea eius omnes voluptua sit. + + No cum illud verear efficiantur. Id altera imperdiet nec. Noster audiam accusamus mei at, no zril libris nemore + duo, ius ne rebum doctus fuisset. Legimus epicurei in sit, esse purto suscipit eu qui, oporteat deserunt + delicatissimi sea in. Est id putent accusata convenire, no tibique molestie accommodare quo, cu est fuisset + offendit evertitur. + `; + + it('is uncollapsible if the commit message is short', function() { + sinon.stub(commit, 'getMessageBody').returns('short'); + const wrapper = shallow(buildApp()); + const view = wrapper.find('CommitDetailView'); + assert.isFalse(view.prop('messageCollapsible')); + assert.isTrue(view.prop('messageOpen')); }); - const {multiFilePatch: mfp} = multiFilePatchBuilder().addFilePatch().build(); - sinon.stub(newCommit, 'getMultiFileDiff').returns(mfp); - const wrapper = mount(buildApp({commit: newCommit})); - - assert.strictEqual(wrapper.find('.github-CommitDetailView-title').text(), 'subject'); - assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), 'messageBody'); - assert.strictEqual(wrapper.find('.github-CommitDetailView-metaText').text(), 'very@nice.com committed 2 days ago'); - assert.strictEqual(wrapper.find('.github-CommitDetailView-sha').text(), '420'); - /* TODO fix href test */ - // assert.strictEqual(wrapper.find('.github-CommitDetailView-sha a').prop('href'), '420'); - assert.strictEqual(wrapper.find('img.github-RecentCommit-avatar').prop('src'), 'https://avatars.githubusercontent.com/u/e?email=very%40nice.com&s=32'); - }); - it('renders multiple avatars for co-authored commit', function() { - const newCommit = new Commit({ - sha: '420', - authorEmail: 'very@nice.com', - authorDate: moment().subtract(2, 'days').unix(), - messageSubject: 'subject', - messageBody: 'messageBody', - coAuthors: [{name: 'two', email: 'two@coauthor.com'}, {name: 'three', email: 'three@coauthor.com'}], + it('is collapsible and begins collapsed if the commit message is long', function() { + sinon.stub(commit, 'getMessageBody').returns(LONG_MESSAGE); + + const wrapper = shallow(buildApp()); + const view = wrapper.find('CommitDetailView'); + assert.isTrue(view.prop('messageCollapsible')); + assert.isFalse(view.prop('messageOpen')); }); - const {multiFilePatch: mfp} = multiFilePatchBuilder().addFilePatch().build(); - sinon.stub(newCommit, 'getMultiFileDiff').returns(mfp); - const wrapper = mount(buildApp({commit: newCommit})); - assert.deepEqual( - wrapper.find('img.github-RecentCommit-avatar').map(w => w.prop('src')), - [ - 'https://avatars.githubusercontent.com/u/e?email=very%40nice.com&s=32', - 'https://avatars.githubusercontent.com/u/e?email=two%40coauthor.com&s=32', - 'https://avatars.githubusercontent.com/u/e?email=three%40coauthor.com&s=32', - ], - ); - }); + it('toggles collapsed state', async function() { + sinon.stub(commit, 'getMessageBody').returns(LONG_MESSAGE); + + const wrapper = shallow(buildApp()); + assert.isFalse(wrapper.find('CommitDetailView').prop('messageOpen')); + + await wrapper.find('CommitDetailView').prop('toggleMessage')(); + + assert.isTrue(wrapper.find('CommitDetailView').prop('messageOpen')); + }); + }); }); diff --git a/test/views/commit-detail-view.test.js b/test/views/commit-detail-view.test.js new file mode 100644 index 0000000000..731a5b7118 --- /dev/null +++ b/test/views/commit-detail-view.test.js @@ -0,0 +1,69 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +describe('CommitDetailView', function() { + it('has a MultiFilePatchController that its itemType set'); + + it('passes unrecognized props to a MultiFilePatchController'); + + it('renders commit details properly'); + + it('renders multiple avatars for co-authored commit'); +}); + +/* +it('has a MultiFilePatchController that has `disableStageUnstage` flag set to true', function() { + const wrapper = mount(buildApp()); + assert.isTrue(wrapper.find('MultiFilePatchController').exists()); + assert.isTrue(wrapper.find('MultiFilePatchController').prop('disableStageUnstage')); +}); + +it('passes unrecognized props to a MultiFilePatchController', function() { + const extra = Symbol('extra'); + const wrapper = shallow(buildApp({extra})); + + assert.strictEqual(wrapper.find('MultiFilePatchController').prop('extra'), extra); +}); + +it('renders commit details properly', function() { + const newCommit = new Commit({ + sha: '420', + authorEmail: 'very@nice.com', + authorDate: moment().subtract(2, 'days').unix(), + messageSubject: 'subject', + messageBody: 'messageBody', + }); + const {multiFilePatch: mfp} = multiFilePatchBuilder().addFilePatch().build(); + sinon.stub(newCommit, 'getMultiFileDiff').returns(mfp); + const wrapper = mount(buildApp({commit: newCommit})); + + assert.strictEqual(wrapper.find('.github-CommitDetailView-title').text(), 'subject'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), 'messageBody'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-metaText').text(), 'very@nice.com committed 2 days ago'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-sha').text(), '420'); + // assert.strictEqual(wrapper.find('.github-CommitDetailView-sha a').prop('href'), '420'); + assert.strictEqual(wrapper.find('img.github-RecentCommit-avatar').prop('src'), 'https://avatars.githubusercontent.com/u/e?email=very%40nice.com&s=32'); +}); + +it('renders multiple avatars for co-authored commit', function() { + const newCommit = new Commit({ + sha: '420', + authorEmail: 'very@nice.com', + authorDate: moment().subtract(2, 'days').unix(), + messageSubject: 'subject', + messageBody: 'messageBody', + coAuthors: [{name: 'two', email: 'two@coauthor.com'}, {name: 'three', email: 'three@coauthor.com'}], + }); + const {multiFilePatch: mfp} = multiFilePatchBuilder().addFilePatch().build(); + sinon.stub(newCommit, 'getMultiFileDiff').returns(mfp); + const wrapper = mount(buildApp({commit: newCommit})); + assert.deepEqual( + wrapper.find('img.github-RecentCommit-avatar').map(w => w.prop('src')), + [ + 'https://avatars.githubusercontent.com/u/e?email=very%40nice.com&s=32', + 'https://avatars.githubusercontent.com/u/e?email=two%40coauthor.com&s=32', + 'https://avatars.githubusercontent.com/u/e?email=three%40coauthor.com&s=32', + ], + ); +}); +*/ From 23ed35b724d7b460acc2cde7d6d3e40d2fd13ec2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 14:36:30 -0500 Subject: [PATCH 2015/4847] Builder for creating test Commits --- test/builder/commit.js | 54 ++++++++++++++++++++++++++++++++++++++ test/models/commit.test.js | 22 +++++----------- 2 files changed, 60 insertions(+), 16 deletions(-) create mode 100644 test/builder/commit.js diff --git a/test/builder/commit.js b/test/builder/commit.js new file mode 100644 index 0000000000..3d4dfef206 --- /dev/null +++ b/test/builder/commit.js @@ -0,0 +1,54 @@ +import moment from 'moment'; + +import Commit from '../../lib/models/commit'; + +class CommitBuilder { + constructor() { + this._sha = '0123456789abcdefghij0123456789abcdefghij'; + this._authorEmail = 'default@email.com'; + this._authorDate = moment('2018-11-28T12:00:00', moment.ISO_8601).unix(); + this._coAuthors = []; + this._messageSubject = 'subject'; + this._messageBody = 'body'; + } + + sha(newSha) { + this._sha = newSha; + return this; + } + + authorEmail(newEmail) { + this._authorEmail = newEmail; + return this; + } + + authorDate(timestamp) { + this._authorDate = timestamp; + return this; + } + + messageSubject(subject) { + this._messageSubject = subject; + return this; + } + + messageBody(body) { + this._messageBody = body; + return this; + } + + build() { + return new Commit({ + sha: this._sha, + authorEmail: this._authorEmail, + authorDate: this._authorDate, + coAuthors: this._coAuthors, + messageSubject: this._messageSubject, + messageBody: this._messageBody, + }); + } +} + +export function commitBuilder() { + return new CommitBuilder(); +} diff --git a/test/models/commit.test.js b/test/models/commit.test.js index a8cd468a4c..1adb497f10 100644 --- a/test/models/commit.test.js +++ b/test/models/commit.test.js @@ -1,24 +1,13 @@ -import moment from 'moment'; import dedent from 'dedent-js'; -import Commit, {nullCommit} from '../../lib/models/commit'; +import {nullCommit} from '../../lib/models/commit'; +import {commitBuilder} from '../builder/commit'; describe('Commit', function() { - function buildCommit(override = {}) { - return new Commit({ - sha: '0123456789abcdefghij0123456789abcdefghij', - authorEmail: 'me@email.com', - coAuthors: [], - authorDate: moment('2018-11-28T12:00:00', moment.ISO_8601).unix(), - messageSubject: 'subject', - messageBody: 'body', - ...override, - }); - } - describe('isBodyLong()', function() { it('returns false if the commit message body is short', function() { - assert.isFalse(buildCommit({messageBody: 'short'}).isBodyLong()); + const commit = commitBuilder().messageBody('short').build(); + assert.isFalse(commit.isBodyLong()); }); it('returns true if the commit message body is long', function() { @@ -41,7 +30,8 @@ describe('Commit', function() { delicatissimi sea in. Est id putent accusata convenire, no tibique molestie accommodare quo, cu est fuisset offendit evertitur. `; - assert.isTrue(buildCommit({messageBody}).isBodyLong()); + const commit = commitBuilder().messageBody(messageBody).build(); + assert.isTrue(commit.isBodyLong()); }); it('returns false for a null commit', function() { From d1237527de6eb258cb2bb0710d9807fb176b340b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 14:56:15 -0500 Subject: [PATCH 2016/4847] setMultiFileDiff() to construct a Commit's diff --- test/builder/commit.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/builder/commit.js b/test/builder/commit.js index 3d4dfef206..a68ada437b 100644 --- a/test/builder/commit.js +++ b/test/builder/commit.js @@ -1,6 +1,7 @@ import moment from 'moment'; import Commit from '../../lib/models/commit'; +import {multiFilePatchBuilder} from './patch'; class CommitBuilder { constructor() { @@ -10,6 +11,8 @@ class CommitBuilder { this._coAuthors = []; this._messageSubject = 'subject'; this._messageBody = 'body'; + + this._multiFileDiff = null; } sha(newSha) { @@ -37,8 +40,14 @@ class CommitBuilder { return this; } + setMultiFileDiff(block = () => {}) { + const builder = multiFilePatchBuilder(); + block(builder); + this._multiFileDiff = builder.build().multiFilePatch; + return this; + } build() { - return new Commit({ + const commit = new Commit({ sha: this._sha, authorEmail: this._authorEmail, authorDate: this._authorDate, @@ -46,6 +55,12 @@ class CommitBuilder { messageSubject: this._messageSubject, messageBody: this._messageBody, }); + + if (this._multiFileDiff !== null) { + commit.setMultiFileDiff(this._multiFileDiff); + } + + return commit; } } From a22b69233e5e10e6fc8724af2ee52cdeed8379ed Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 14:56:28 -0500 Subject: [PATCH 2017/4847] CoAuthor construction --- test/builder/commit.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/builder/commit.js b/test/builder/commit.js index a68ada437b..d9dd960bb7 100644 --- a/test/builder/commit.js +++ b/test/builder/commit.js @@ -46,6 +46,12 @@ class CommitBuilder { this._multiFileDiff = builder.build().multiFilePatch; return this; } + + addCoAuthor(name, email) { + this._coAuthors.push({name, email}); + return this; + } + build() { const commit = new Commit({ sha: this._sha, From 942e7dccda77c95aed4e1a08713e292eaf8c5ec1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 14:56:41 -0500 Subject: [PATCH 2018/4847] PropTypes shuffle :dancer: --- lib/views/commit-detail-view.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index 96b38f1ec6..ec0416a57b 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -4,10 +4,13 @@ import {emojify} from 'node-emoji'; import moment from 'moment'; import MultiFilePatchController from '../controllers/multi-file-patch-controller'; +import CommitDetailItem from '../items/commit-detail-item'; export default class CommitDetailView extends React.Component { static propTypes = { repository: PropTypes.object.isRequired, + commit: PropTypes.object.isRequired, + itemType: PropTypes.oneOf([CommitDetailItem]).isRequired, workspace: PropTypes.object.isRequired, commands: PropTypes.object.isRequired, @@ -16,7 +19,6 @@ export default class CommitDetailView extends React.Component { config: PropTypes.object.isRequired, destroy: PropTypes.func.isRequired, - commit: PropTypes.object.isRequired, } render() { From 1a28b7d3a7b3a62615690b605dc8ad54367e1a0d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 14:56:59 -0500 Subject: [PATCH 2019/4847] Ported CommitDetailView tests, all passing --- test/views/commit-detail-view.test.js | 127 +++++++++++++++----------- 1 file changed, 74 insertions(+), 53 deletions(-) diff --git a/test/views/commit-detail-view.test.js b/test/views/commit-detail-view.test.js index 731a5b7118..0dfc18ef13 100644 --- a/test/views/commit-detail-view.test.js +++ b/test/views/commit-detail-view.test.js @@ -1,69 +1,90 @@ import React from 'react'; import {shallow} from 'enzyme'; +import moment from 'moment'; + +import CommitDetailView from '../../lib/views/commit-detail-view'; +import CommitDetailItem from '../../lib/items/commit-detail-item'; +import {cloneRepository, buildRepository} from '../helpers'; +import {commitBuilder} from '../builder/commit'; describe('CommitDetailView', function() { - it('has a MultiFilePatchController that its itemType set'); + let repository, atomEnv; - it('passes unrecognized props to a MultiFilePatchController'); + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + repository = await buildRepository(await cloneRepository('multiple-commits')); + }); - it('renders commit details properly'); + afterEach(function() { + atomEnv.destroy(); + }); - it('renders multiple avatars for co-authored commit'); -}); + function buildApp(override = {}) { + const props = { + repository, + commit: commitBuilder().build(), + itemType: CommitDetailItem, -/* -it('has a MultiFilePatchController that has `disableStageUnstage` flag set to true', function() { - const wrapper = mount(buildApp()); - assert.isTrue(wrapper.find('MultiFilePatchController').exists()); - assert.isTrue(wrapper.find('MultiFilePatchController').prop('disableStageUnstage')); -}); + workspace: atomEnv.workspace, + commands: atomEnv.commands, + keymaps: atomEnv.keymaps, + tooltips: atomEnv.tooltips, + config: atomEnv.config, -it('passes unrecognized props to a MultiFilePatchController', function() { - const extra = Symbol('extra'); - const wrapper = shallow(buildApp({extra})); + destroy: () => {}, + ...override, + }; - assert.strictEqual(wrapper.find('MultiFilePatchController').prop('extra'), extra); -}); + return ; + } -it('renders commit details properly', function() { - const newCommit = new Commit({ - sha: '420', - authorEmail: 'very@nice.com', - authorDate: moment().subtract(2, 'days').unix(), - messageSubject: 'subject', - messageBody: 'messageBody', + it('has a MultiFilePatchController that its itemType set', function() { + const wrapper = shallow(buildApp({itemType: CommitDetailItem})); + assert.strictEqual(wrapper.find('MultiFilePatchController').prop('itemType'), CommitDetailItem); }); - const {multiFilePatch: mfp} = multiFilePatchBuilder().addFilePatch().build(); - sinon.stub(newCommit, 'getMultiFileDiff').returns(mfp); - const wrapper = mount(buildApp({commit: newCommit})); - assert.strictEqual(wrapper.find('.github-CommitDetailView-title').text(), 'subject'); - assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), 'messageBody'); - assert.strictEqual(wrapper.find('.github-CommitDetailView-metaText').text(), 'very@nice.com committed 2 days ago'); - assert.strictEqual(wrapper.find('.github-CommitDetailView-sha').text(), '420'); - // assert.strictEqual(wrapper.find('.github-CommitDetailView-sha a').prop('href'), '420'); - assert.strictEqual(wrapper.find('img.github-RecentCommit-avatar').prop('src'), 'https://avatars.githubusercontent.com/u/e?email=very%40nice.com&s=32'); -}); - -it('renders multiple avatars for co-authored commit', function() { - const newCommit = new Commit({ - sha: '420', - authorEmail: 'very@nice.com', - authorDate: moment().subtract(2, 'days').unix(), - messageSubject: 'subject', - messageBody: 'messageBody', - coAuthors: [{name: 'two', email: 'two@coauthor.com'}, {name: 'three', email: 'three@coauthor.com'}], + it('passes unrecognized props to a MultiFilePatchController', function() { + const extra = Symbol('extra'); + const wrapper = shallow(buildApp({extra})); + assert.strictEqual(wrapper.find('MultiFilePatchController').prop('extra'), extra); }); - const {multiFilePatch: mfp} = multiFilePatchBuilder().addFilePatch().build(); - sinon.stub(newCommit, 'getMultiFileDiff').returns(mfp); - const wrapper = mount(buildApp({commit: newCommit})); - assert.deepEqual( - wrapper.find('img.github-RecentCommit-avatar').map(w => w.prop('src')), - [ + + it('renders commit details properly', function() { + const commit = commitBuilder() + .sha('420') + .authorEmail('very@nice.com') + .authorDate(moment().subtract(2, 'days').unix()) + .messageSubject('subject') + .messageBody('body') + .setMultiFileDiff() + .build(); + const wrapper = shallow(buildApp({commit})); + + assert.strictEqual(wrapper.find('.github-CommitDetailView-title').text(), 'subject'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), 'body'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-metaText').text(), 'very@nice.com committed 2 days ago'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-sha').text(), '420'); + // assert.strictEqual(wrapper.find('.github-CommitDetailView-sha a').prop('href'), '420'); + assert.strictEqual( + wrapper.find('img.github-RecentCommit-avatar').prop('src'), 'https://avatars.githubusercontent.com/u/e?email=very%40nice.com&s=32', - 'https://avatars.githubusercontent.com/u/e?email=two%40coauthor.com&s=32', - 'https://avatars.githubusercontent.com/u/e?email=three%40coauthor.com&s=32', - ], - ); + ); + }); + + it('renders multiple avatars for co-authored commit', function() { + const commit = commitBuilder() + .authorEmail('blaze@it.com') + .addCoAuthor('two', 'two@coauthor.com') + .addCoAuthor('three', 'three@coauthor.com') + .build(); + const wrapper = shallow(buildApp({commit})); + assert.deepEqual( + wrapper.find('img.github-RecentCommit-avatar').map(w => w.prop('src')), + [ + 'https://avatars.githubusercontent.com/u/e?email=blaze%40it.com&s=32', + 'https://avatars.githubusercontent.com/u/e?email=two%40coauthor.com&s=32', + 'https://avatars.githubusercontent.com/u/e?email=three%40coauthor.com&s=32', + ], + ); + }); }); -*/ From 4d8737cbc321cddefddecd98ed34e6e8304613fa Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 15:48:33 -0500 Subject: [PATCH 2020/4847] Failing tests and initial implementation of abbreviatedBody() --- lib/models/commit.js | 39 +++++++++++++ test/models/commit.test.js | 112 +++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/lib/models/commit.js b/lib/models/commit.js index c568de8066..fb6433ace5 100644 --- a/lib/models/commit.js +++ b/lib/models/commit.js @@ -3,6 +3,8 @@ const UNBORN = Symbol('unborn'); export default class Commit { static LONG_MESSAGE_THRESHOLD = 1000; + static BOUNDARY_SEARCH_THRESHOLD = 100; + static createUnborn() { return new Commit({unbornRef: UNBORN}); } @@ -50,6 +52,43 @@ export default class Commit { return `${this.getMessageSubject()}\n\n${this.getMessageBody()}`.trim(); } + /* + * Return the messageBody, truncated before the character at LONG_MESSAGE_THRESHOLD. If a paragraph boundary is + * found within BOUNDARY_SEARCH_THRESHOLD characters before that position, the message will be truncated at the + * end of the previous paragraph. If there is no paragraph boundary found, but a word boundary is found within + * that range, the text is truncated at that word boundary and an elipsis (...) is added. If neither are found, + * the text is truncated hard at LONG_MESSAGE_THRESHOLD - 3 characters and an elipsis (...) is added. + */ + abbreviatedBody() { + if (!this.isBodyLong()) { + return this.getMessageBody(); + } + + const {LONG_MESSAGE_THRESHOLD, BOUNDARY_SEARCH_THRESHOLD} = this.constructor; + let elipsis = '...'; + let lastParagraphIndex = Infinity; + let lastWordIndex = Infinity; + + const boundarySearch = this.getMessageBody() + .substring(LONG_MESSAGE_THRESHOLD - BOUNDARY_SEARCH_THRESHOLD, LONG_MESSAGE_THRESHOLD); + + const boundaryRx = /\r?\n\r?\n|\s+/g; + let result; + while ((result = boundaryRx.exec(boundarySearch)) !== null) { + if (/\r?\n\r?\n/.test(result[0])) { + // Paragraph boundary. Omit the elipsis + lastParagraphIndex = result.index; + elipsis = ''; + } else if (result.index <= BOUNDARY_SEARCH_THRESHOLD - elipsis.length) { + // Word boundary. Only count if we have room for the elipsis under the cutoff. + lastWordIndex = result.index; + } + } + + const cutoffIndex = Math.min(lastParagraphIndex, lastWordIndex); + return this.getMessageBody().substring(0, cutoffIndex) + elipsis; + } + setMultiFileDiff(multiFileDiff) { this.multiFileDiff = multiFileDiff; } diff --git a/test/models/commit.test.js b/test/models/commit.test.js index 1adb497f10..9e3e7664ea 100644 --- a/test/models/commit.test.js +++ b/test/models/commit.test.js @@ -38,4 +38,116 @@ describe('Commit', function() { assert.isFalse(nullCommit.isBodyLong()); }); }); + + describe('abbreviatedBody()', function() { + it('returns the message body as-is when the body is short', function() { + const commit = commitBuilder().messageBody('short').build(); + assert.strictEqual(commit.abbreviatedBody(), 'short'); + }); + + it('truncates the message body at the nearest paragraph boundary before the cutoff if one is nearby', function() { + // The | is at the 1000-character mark. + const body = dedent` + Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. Mazim alterum sea ea, + essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore albucius te vis, eam + tantas nullam corrumpit ad, in oratio luptatum eleifend vim. + + Ea salutatus contentiones eos. Eam in veniam facete volutpat, solum appetere adversarium ut quo. Vel cu appetere + urbanitas, usu ut aperiri mediocritatem, alia molestie urbanitas cu qui. Velit antiopam erroribus no eum, + scripta iudicabit ne nam, in duis clita commodo sit. + + Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat comprehensam ut his, et eum + voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei liber putant. Ad doctus + tractatos ius, duo ad civibus alienum, nominati voluptaria sed an. Libris essent philosophia et vix. Nusquam + reprehendunt et mea. Ea eius omnes voluptua sit. + + No cum illud verear efficiantur. Id altera imperdiet nec. Noster aud|iam accusamus mei at, no zril libris nemore + duo, ius ne rebum doctus fuisset. Legimus epicurei in sit, esse purto suscipit eu qui, oporteat deserunt + delicatissimi sea in. Est id putent accusata convenire, no tibique molestie accommodare quo, cu est fuisset + offendit evertitur. + `; + + const commit = commitBuilder().messageBody(body).build(); + assert.strictEqual(commit.abbreviatedBody(), dedent` + Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. Mazim alterum sea ea, + essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore albucius te vis, eam + tantas nullam corrumpit ad, in oratio luptatum eleifend vim. + + Ea salutatus contentiones eos. Eam in veniam facete volutpat, solum appetere adversarium ut quo. Vel cu appetere + urbanitas, usu ut aperiri mediocritatem, alia molestie urbanitas cu qui. Velit antiopam erroribus no eum, + scripta iudicabit ne nam, in duis clita commodo sit. + + Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat comprehensam ut his, et eum + voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei liber putant. Ad doctus + tractatos ius, duo ad civibus alienum, nominati voluptaria sed an. Libris essent philosophia et vix. Nusquam + reprehendunt et mea. Ea eius omnes voluptua sit. + `); + }); + + it('truncates the message body at the nearest word boundary before the cutoff if one is nearby', function() { + // The | is at the 1000-character mark. + const body = dedent` + Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. + + Mazim alterum sea ea, essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore + albucius te vis, eam tantas nullam corrumpit ad, in oratio luptatum eleifend vim. Ea salutatus contentiones eos. + Eam in veniam facete volutpat, solum appetere adversarium ut quo. Vel cu appetere urbanitas, usu ut aperiri + mediocritatem, alia molestie urbanitas cu qui. Velit antiopam erroribus no eum, scripta iudicabit ne nam, in + duis clita commodo sit. Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat + comprehensam ut his, et eum voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei + liber putant. Ad doctus tractatos ius, duo ad civibus alienum, nominati voluptaria sed an. Libris essent + philosophia et vix. Nusquam reprehendunt et mea. Ea eius omnes voluptua sit. No cum illud verear efficiantur. Id + altera imperdiet nec. Noster audia|m accusamus mei at, no zril libris nemore duo, ius ne rebum doctus fuisset. + Legimus epicurei in sit, esse purto suscipit eu qui, oporteat deserunt delicatissimi sea in. Est id putent + accusata convenire, no tibique molestie accommodare quo, cu est fuisset offendit evertitur. + `; + + const commit = commitBuilder().messageBody(body).build(); + assert.strictEqual(commit.abbreviatedBody(), dedent` + Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. + + Mazim alterum sea ea, essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore + albucius te vis, eam tantas nullam corrumpit ad, in oratio luptatum eleifend vim. Ea salutatus contentiones eos. + Eam in veniam facete volutpat, solum appetere adversarium ut quo. Vel cu appetere urbanitas, usu ut aperiri + mediocritatem, alia molestie urbanitas cu qui. Velit antiopam erroribus no eum, scripta iudicabit ne nam, in + duis clita commodo sit. Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat + comprehensam ut his, et eum voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei + liber putant. Ad doctus tractatos ius, duo ad civibus alienum, nominati voluptaria sed an. Libris essent + philosophia et vix. Nusquam reprehendunt et mea. Ea eius omnes voluptua sit. No cum illud verear efficiantur. Id + altera imperdiet nec. Noster... + `); + }); + + it('truncates the message body at the character cutoff if no word or paragraph boundaries can be found', function() { + // The | is at the 1000-character mark. + const body = 'Loremipsumdolorsitamet,ethisjustodeleniti,omniumfastidiiadversariumathas.\n\n' + + 'Mazim alterumseaea,essentmalorumpersiusnemei.Nameatemporqualisque,modusdomingtehas.Affertdolore' + + 'albuciustevis,eamtantasnullamcorrumpitad,inoratioluptatumeleifendvim.Easalutatuscontentioneseos.' + + 'Eaminveniamfacetevolutpat,solumappetereadversariumutquo.Velcuappetereurbanitas,usuutaperiri' + + 'mediocritatem,aliamolestieurbanitascuqui.Velitantiopamerroribusnoeum,scriptaiudicabitnenam,in' + + 'duisclitacommodosit.Assumsensibusoporteretevel,vissemperevertiturdefiniebasin.Tamquamfeugiat' + + 'comprehensamuthis,eteumvoluptuaullamcorper,exmeidebitisinciderint.Sitdiscerepertinaxte,anmei' + + 'liberputant.Addoctustractatosius,duoadcivibusalienum,nominativoluptariasedan.Librisessent' + + 'philosophiaetvix.Nusquamreprehenduntetmea.Eaeiusomnesvoluptuasit.Nocumilludverearefficiantur.Id' + + 'alteraimperdietnec.Nosteraudiamaccusamusmeiat,nozrillibrisnemoreduo,iusnerebumdoctusfuisset.' + + 'Legimusepicureiinsit,essepurtosuscipiteuqui,oporteatdeseruntdelicatissimiseain.Estidputent' + + '|accusataconvenire,notibiquemolestieaccommodarequo,cuestfuissetoffenditevertitur.'; + + const commit = commitBuilder().messageBody(body).build(); + assert.strictEqual( + commit.abbreviatedBody(), + 'Loremipsumdolorsitamet,ethisjustodeleniti,omniumfastidiiadversariumathas.\n\n' + + 'Mazim alterumseaea,essentmalorumpersiusnemei.Nameatemporqualisque,modusdomingtehas.Affertdolore' + + 'albuciustevis,eamtantasnullamcorrumpitad,inoratioluptatumeleifendvim.Easalutatuscontentioneseos.' + + 'Eaminveniamfacetevolutpat,solumappetereadversariumutquo.Velcuappetereurbanitas,usuutaperiri' + + 'mediocritatem,aliamolestieurbanitascuqui.Velitantiopamerroribusnoeum,scriptaiudicabitnenam,in' + + 'duisclitacommodosit.Assumsensibusoporteretevel,vissemperevertiturdefiniebasin.Tamquamfeugiat' + + 'comprehensamuthis,eteumvoluptuaullamcorper,exmeidebitisinciderint.Sitdiscerepertinaxte,anmei' + + 'liberputant.Addoctustractatosius,duoadcivibusalienum,nominativoluptariasedan.Librisessent' + + 'philosophiaetvix.Nusquamreprehenduntetmea.Eaeiusomnesvoluptuasit.Nocumilludverearefficiantur.Id' + + 'alteraimperdietnec.Nosteraudiamaccusamusmeiat,nozrillibrisnemoreduo,iusnerebumdoctusfuisset.' + + 'Legimusepicureiinsit,essepurtosuscipiteuqui,oporteatdeseruntdelicatissimiseain.Estidput...', + ); + }); + }); }); From 4ceba4b4ca61ae6e4da2218b9cb00e0bd0fc5d62 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 28 Nov 2018 15:52:06 -0500 Subject: [PATCH 2021/4847] Pending tests for collapsing and uncollapsing message bodies --- test/views/commit-detail-view.test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/views/commit-detail-view.test.js b/test/views/commit-detail-view.test.js index 0dfc18ef13..357505912e 100644 --- a/test/views/commit-detail-view.test.js +++ b/test/views/commit-detail-view.test.js @@ -23,6 +23,8 @@ describe('CommitDetailView', function() { const props = { repository, commit: commitBuilder().build(), + messageCollapsible: false, + messageOpen: true, itemType: CommitDetailItem, workspace: atomEnv.workspace, @@ -87,4 +89,14 @@ describe('CommitDetailView', function() { ], ); }); + + describe('commit message collapsibility', function() { + it('renders the full message when messageCollapsible is false'); + + it('renders an abbreviated message when messageCollapsible is true and messageOpen is false'); + + it('renders the full message when messageCollapsible is true and messageOpen is true'); + + it('calls toggleMessage the "See More" or "See Less" buttons are clicked'); + }); }); From 38b0fa9e40b40e6f9a8c1034c1d7f5b6e700e0e3 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 28 Nov 2018 13:11:40 -0800 Subject: [PATCH 2022/4847] :fire: autoHeight as a prop since it's always false --- lib/controllers/commit-preview-controller.js | 1 - lib/controllers/multi-file-patch-controller.js | 1 - lib/views/multi-file-patch-view.js | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/controllers/commit-preview-controller.js b/lib/controllers/commit-preview-controller.js index ff5f3cf72b..f1ce3c988c 100644 --- a/lib/controllers/commit-preview-controller.js +++ b/lib/controllers/commit-preview-controller.js @@ -23,7 +23,6 @@ export default class CommitPreviewController extends React.Component { return ( ); diff --git a/lib/controllers/multi-file-patch-controller.js b/lib/controllers/multi-file-patch-controller.js index 667184aae4..cdba88def6 100644 --- a/lib/controllers/multi-file-patch-controller.js +++ b/lib/controllers/multi-file-patch-controller.js @@ -25,7 +25,6 @@ export default class MultiFilePatchController extends React.Component { discardLines: PropTypes.func, undoLastDiscard: PropTypes.func, surface: PropTypes.func, - autoHeight: PropTypes.bool, } constructor(props) { diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 5e3d3d73bf..5e35e5033b 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -58,7 +58,6 @@ export default class MultiFilePatchView extends React.Component { toggleSymlinkChange: PropTypes.func, undoLastDiscard: PropTypes.func, discardRows: PropTypes.func, - autoHeight: PropTypes.bool, refInitialFocus: RefHolderPropType, itemType: PropTypes.oneOf([ChangedFileItem, CommitPreviewItem, CommitDetailItem]).isRequired, } @@ -241,7 +240,7 @@ export default class MultiFilePatchView extends React.Component { buffer={this.props.multiFilePatch.getBuffer()} lineNumberGutterVisible={false} autoWidth={false} - autoHeight={this.props.autoHeight} + autoHeight={false} readOnly={true} softWrapped={true} From 205c43754631120585824ac433e8fbd844469156 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 28 Nov 2018 14:42:02 -0800 Subject: [PATCH 2023/4847] collapse and uncollapse commit message bodies --- lib/views/commit-detail-view.js | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index ec0416a57b..dafdcb1123 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -19,6 +19,10 @@ export default class CommitDetailView extends React.Component { config: PropTypes.object.isRequired, destroy: PropTypes.func.isRequired, + + messageCollapsible: PropTypes.bool.isRequired, + messageOpen: PropTypes.bool.isRequired, + toggleMessage: PropTypes.func.isRequired, } render() { @@ -33,9 +37,9 @@ export default class CommitDetailView extends React.Component {

    {emojify(commit.getMessageSubject())} + {this.renderShowMoreButton()}

    -
    -                {emojify(commit.getMessageBody())}
    + {this.renderCommitMessageBody(commit)}
    {/* TODO fix image src */} {this.renderAuthors()} @@ -62,6 +66,25 @@ export default class CommitDetailView extends React.Component { ); } + renderCommitMessageBody(commit) { + if (this.props.messageOpen || !this.props.messageCollapsible) { + return ( +
    +          {emojify(commit.getMessageBody())}
    + ); + } + } + + renderShowMoreButton() { + if (!this.props.messageCollapsible) { + return null; + } + const buttonText = this.props.messageOpen ? 'Hide More' : 'Show More'; + return ( + + ); + } + humanizeTimeSince(date) { return moment(date * 1000).fromNow(); } From ec10f482e22823995def2968eb11d6451c5a16d4 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 28 Nov 2018 14:45:53 -0800 Subject: [PATCH 2024/4847] return null if we're not gonna render the commit message body --- lib/views/commit-detail-view.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index dafdcb1123..11a3981f99 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -72,6 +72,8 @@ export default class CommitDetailView extends React.Component {
               {emojify(commit.getMessageBody())}
    ); + } else { + return null; } } From e1102d07bd0cdc2f5b31ca4242edd3fea453e659 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 28 Nov 2018 14:56:19 -0800 Subject: [PATCH 2025/4847] style the button --- lib/views/commit-detail-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index 11a3981f99..b965f70eb2 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -83,7 +83,7 @@ export default class CommitDetailView extends React.Component { } const buttonText = this.props.messageOpen ? 'Hide More' : 'Show More'; return ( - + ); } From 1af8a5d119256a46e4822acece992a7b6f0153fb Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 28 Nov 2018 16:51:35 -0800 Subject: [PATCH 2026/4847] :fire: some dead code --- lib/views/commit-detail-view.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index b965f70eb2..125be8778b 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -27,8 +27,6 @@ export default class CommitDetailView extends React.Component { render() { const commit = this.props.commit; - // const {messageHeadline, messageBody, abbreviatedOid, url} = this.props.item; - // const {avatarUrl, name, date} = this.props.item.committer; return (
    From 6a3d65cc7fe8584e5747ec5f826f8b75da6b153b Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 28 Nov 2018 16:53:56 -0800 Subject: [PATCH 2027/4847] unit tests for commit message collapsibility --- test/views/commit-detail-view.test.js | 63 +++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/test/views/commit-detail-view.test.js b/test/views/commit-detail-view.test.js index 357505912e..ee39d83e40 100644 --- a/test/views/commit-detail-view.test.js +++ b/test/views/commit-detail-view.test.js @@ -1,6 +1,7 @@ import React from 'react'; import {shallow} from 'enzyme'; import moment from 'moment'; +import dedent from 'dedent-js'; import CommitDetailView from '../../lib/views/commit-detail-view'; import CommitDetailItem from '../../lib/items/commit-detail-item'; @@ -34,6 +35,7 @@ describe('CommitDetailView', function() { config: atomEnv.config, destroy: () => {}, + toggleMessage: () => {}, ...override, }; @@ -91,12 +93,65 @@ describe('CommitDetailView', function() { }); describe('commit message collapsibility', function() { - it('renders the full message when messageCollapsible is false'); + let wrapper; + const commitMessageBody = dedent` + if every pork chop was perfect... - it('renders an abbreviated message when messageCollapsible is true and messageOpen is false'); - it('renders the full message when messageCollapsible is true and messageOpen is true'); - it('calls toggleMessage the "See More" or "See Less" buttons are clicked'); + we wouldn't have hot dogs! + 🌭🌭🌭🌭🌭🌭🌭 + `; + const commit = commitBuilder() + .authorEmail('greg@mruniverse.biz') + .messageBody(commitMessageBody) + .build(); + describe('when messageCollapsible is false', function() { + beforeEach(function() { + wrapper = shallow(buildApp({commit, messageCollapsible: false})); + }); + it('renders the full message body', function() { + assert.deepEqual(wrapper.find('.github-CommitDetailView-moreText').text(), commitMessageBody); + }); + it('does not render a button', function() { + + }); + }); + describe('when messageCollapsible is true and messageOpen is false', function() { + beforeEach(function() { + wrapper = shallow(buildApp({commit, messageCollapsible: true, messageOpen: false})); + }); + it('does not render commit message', function() { + assert.lengthOf(wrapper.find('.github-CommitDetailView-moreText'), 0); + }); + + it('renders button with the text `Show More`', function() { + const button = wrapper.find('.github-CommitDetailView-moreButton'); + assert.lengthOf(button, 1); + assert.deepEqual(button.text(), 'Show More'); + }); + }); + + describe('when messageCollapsible is true and messageOpen is true', function() { + let toggleMessage; + beforeEach(function() { + toggleMessage = sinon.spy(); + wrapper = shallow(buildApp({commit, messageCollapsible: true, messageOpen: true, toggleMessage})); + }); + it('renders the full message', function() { + assert.deepEqual(wrapper.find('.github-CommitDetailView-moreText').text(), commitMessageBody); + }); + it('renders a button with the text `Hide More`', function() { + const button = wrapper.find('.github-CommitDetailView-moreButton'); + assert.lengthOf(button, 1); + assert.deepEqual(button.text(), 'Hide More'); + }); + it('button calls `toggleMessage` prop when clicked', function() { + const button = wrapper.find('.github-CommitDetailView-moreButton'); + button.simulate('click'); + assert.ok(toggleMessage.called); + }); + + }); }); }); From 8e7561f6808e1ffd9f4584524d5a641e836dbb98 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 28 Nov 2018 16:57:28 -0800 Subject: [PATCH 2028/4847] :fire: unnecessary console logging --- lib/views/pr-commit-view.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/views/pr-commit-view.js b/lib/views/pr-commit-view.js index 1d31e5947d..88d879a3cb 100644 --- a/lib/views/pr-commit-view.js +++ b/lib/views/pr-commit-view.js @@ -38,7 +38,6 @@ export class PrCommitView extends React.Component { } render() { - console.log('zzz'); const {messageHeadline, messageBody, abbreviatedOid, url} = this.props.item; const {avatarUrl, name, date} = this.props.item.committer; return ( From 414390db1fe765fb12c2fdb3bb1547f3ddeae434 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 28 Nov 2018 17:16:51 -0800 Subject: [PATCH 2029/4847] don't render staging/unstaging buttons for mode and symlink changes --- lib/views/file-patch-meta-view.js | 28 +++++++++++++++++++++------- lib/views/multi-file-patch-view.js | 5 +++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/views/file-patch-meta-view.js b/lib/views/file-patch-meta-view.js index bbefd913f6..fadc45edd8 100644 --- a/lib/views/file-patch-meta-view.js +++ b/lib/views/file-patch-meta-view.js @@ -1,6 +1,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; +import CommitDetailItem from '../items/commit-detail-item'; +import ChangedFileItem from '../items/changed-file-item'; +import CommitPreviewItem from '../items/commit-preview-item'; export default class FilePatchMetaView extends React.Component { static propTypes = { @@ -11,21 +14,32 @@ export default class FilePatchMetaView extends React.Component { action: PropTypes.func.isRequired, children: PropTypes.element.isRequired, + itemType: PropTypes.oneOf([ChangedFileItem, CommitPreviewItem, CommitDetailItem]).isRequired, }; + renderMetaControls() { + console.log(this.props); + if (this.props.itemType === CommitDetailItem) { + return null; + } + return ( +
    + +
    + ); + } + render() { return (

    {this.props.title}

    -
    - -
    + {this.renderMetaControls()}
    {this.props.children} diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 5e35e5033b..61414c30a3 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -361,6 +361,7 @@ export default class MultiFilePatchView extends React.Component { title="Mode change" actionIcon={attrs.actionIcon} actionText={attrs.actionText} + itemType={this.props.itemType} action={() => this.props.toggleModeChange(filePatch)}> File changed mode @@ -444,6 +445,7 @@ export default class MultiFilePatchView extends React.Component { title={title} actionIcon={attrs.actionIcon} actionText={attrs.actionText} + itemType={this.props.itemType} action={() => this.props.toggleSymlinkChange(filePatch)}> {detail} @@ -453,6 +455,9 @@ export default class MultiFilePatchView extends React.Component { } renderHunkHeaders(filePatch) { + if (this.props.itemType === CommitDetailItem) { + return null; + } const toggleVerb = this.props.stagingStatus === 'unstaged' ? 'Stage' : 'Unstage'; const selectedHunks = new Set( Array.from(this.props.selectedRows, row => this.props.multiFilePatch.getHunkAt(row)), From 1467db2a5af9ece794d6d67767c8b8adfb1c6aab Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 29 Nov 2018 11:24:29 +0900 Subject: [PATCH 2030/4847] Wrap whitespace in commit body --- styles/commit-detail.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styles/commit-detail.less b/styles/commit-detail.less index 6f8c24f975..b3c3ef8c00 100644 --- a/styles/commit-detail.less +++ b/styles/commit-detail.less @@ -69,7 +69,7 @@ font-family: var(--editor-font-family); word-wrap: initial; word-break: break-word; - white-space: initial; + white-space: pre-wrap; background-color: transparent; &:empty { display: none; From e1de0771e7c6d9c267381d5f1cc27e9d884bbf32 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 29 Nov 2018 12:36:04 +0900 Subject: [PATCH 2031/4847] Move sha into CommitDetailView-meta --- lib/views/commit-detail-view.js | 38 ++++++++++++++++----------------- styles/commit-detail.less | 21 +++++++++--------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index 125be8778b..a3b924a3ad 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -31,28 +31,26 @@ export default class CommitDetailView extends React.Component { return (
    -
    -
    -

    - {emojify(commit.getMessageSubject())} - {this.renderShowMoreButton()} -

    - {this.renderCommitMessageBody(commit)} -
    - {/* TODO fix image src */} - {this.renderAuthors()} - - {commit.getAuthorEmail()} committed {this.humanizeTimeSince(commit.getAuthorDate())} - +
    +

    + {emojify(commit.getMessageSubject())} + {this.renderShowMoreButton()} +

    + {this.renderCommitMessageBody(commit)} +
    + {/* TODO fix image src */} + {this.renderAuthors()} + + {commit.getAuthorEmail()} committed {this.humanizeTimeSince(commit.getAuthorDate())} + +
    + {/* TODO fix href */} + + {commit.getSha()} +
    -
    - {/* TODO fix href */} - - {commit.getSha()} - -
    Date: Thu, 29 Nov 2018 14:10:34 +0900 Subject: [PATCH 2032/4847] Restyle header --- styles/commit-detail.less | 7 ++----- styles/file-patch-view.less | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/styles/commit-detail.less b/styles/commit-detail.less index bc5cddb509..e6cab0bf14 100644 --- a/styles/commit-detail.less +++ b/styles/commit-detail.less @@ -10,15 +10,12 @@ &-header { flex: 0; - padding: @default-padding; - padding-bottom: 0; + border-bottom: 1px solid @base-border-color; background-color: @syntax-background-color; } &-commit { - padding: @default-padding; - border: 1px solid @base-border-color; - border-radius: @component-border-radius; + padding: @default-padding*2; } &-title { diff --git a/styles/file-patch-view.less b/styles/file-patch-view.less index fcf9a7cb48..830fadc1e4 100644 --- a/styles/file-patch-view.less +++ b/styles/file-patch-view.less @@ -24,7 +24,7 @@ } .github-FilePatchView-controlBlock { - padding: @component-padding*2 @component-padding @component-padding 0; + padding: @component-padding*4 @component-padding @component-padding 0; background-color: @syntax-background-color; & + .github-FilePatchView-controlBlock { From 2cc14b1b17973cbd10d459fdd9ba18864e7f6c12 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 28 Nov 2018 23:38:05 +0100 Subject: [PATCH 2033/4847] add test to ensure buttons don't get rendered when inside a CommitDetailItem --- lib/views/hunk-header-view.js | 2 +- test/views/file-patch-header-view.test.js | 6 ++++++ test/views/hunk-header-view.test.js | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/views/hunk-header-view.js b/lib/views/hunk-header-view.js index 6fd986ee54..ab2a43ae1b 100644 --- a/lib/views/hunk-header-view.js +++ b/lib/views/hunk-header-view.js @@ -58,7 +58,7 @@ export default class HunkHeaderView extends React.Component { } renderButtons() { - if (this.props.itemType === CommitPreviewItem) { + if (this.props.itemType === CommitPreviewItem || this.props.itemType === CommitDetailItem) { return null; } else { return ( diff --git a/test/views/file-patch-header-view.test.js b/test/views/file-patch-header-view.test.js index 2d4e0acb65..cf778723cb 100644 --- a/test/views/file-patch-header-view.test.js +++ b/test/views/file-patch-header-view.test.js @@ -5,6 +5,7 @@ import path from 'path'; import FilePatchHeaderView from '../../lib/views/file-patch-header-view'; import ChangedFileItem from '../../lib/items/changed-file-item'; import CommitPreviewItem from '../../lib/items/commit-preview-item'; +import CommitDetailItem from '../../lib/items/commit-detail-item'; describe('FilePatchHeaderView', function() { const relPath = path.join('dir', 'a.txt'); @@ -178,5 +179,10 @@ describe('FilePatchHeaderView', function() { buttonClass: 'icon-move-up', oppositeButtonClass: 'icon-move-down', })); + + it('does not render buttons when in a CommitDetailItem', function() { + const wrapper = shallow(buildApp({itemType: CommitDetailItem})); + assert.isFalse(wrapper.find('.btn-group').exists()); + }); }); }); diff --git a/test/views/hunk-header-view.test.js b/test/views/hunk-header-view.test.js index ae1b80fefe..78c263ae81 100644 --- a/test/views/hunk-header-view.test.js +++ b/test/views/hunk-header-view.test.js @@ -4,6 +4,8 @@ import {shallow} from 'enzyme'; import HunkHeaderView from '../../lib/views/hunk-header-view'; import RefHolder from '../../lib/models/ref-holder'; import Hunk from '../../lib/models/patch/hunk'; +import CommitDetailItem from '../../lib/items/commit-detail-item'; +import CommitPreviewItem from '../../lib/items/commit-preview-item'; describe('HunkHeaderView', function() { let atomEnv, hunk; @@ -117,4 +119,14 @@ describe('HunkHeaderView', function() { assert.isFalse(mouseDown.called); assert.isTrue(evt.stopPropagation.called); }); + + it('does not render extra buttons when in a CommitPreviewItem or a CommitDetailItem', function() { + let wrapper = shallow(buildApp({itemType: CommitPreviewItem})); + assert.isFalse(wrapper.find('.github-HunkHeaderView-stageButton').exists()); + assert.isFalse(wrapper.find('.github-HunkHeaderView-discardButton').exists()); + + wrapper = shallow(buildApp({itemType: CommitDetailItem})); + assert.isFalse(wrapper.find('.github-HunkHeaderView-stageButton').exists()); + assert.isFalse(wrapper.find('.github-HunkHeaderView-discardButton').exists()); + }) }); From e0d97abd00e26b87a49f0bf9a752e5cafb7de458 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 29 Nov 2018 10:34:37 -0500 Subject: [PATCH 2034/4847] Fixed it all on the first go apparently That never happens --- lib/models/commit.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/models/commit.js b/lib/models/commit.js index fb6433ace5..3e7e65b3d4 100644 --- a/lib/models/commit.js +++ b/lib/models/commit.js @@ -65,28 +65,29 @@ export default class Commit { } const {LONG_MESSAGE_THRESHOLD, BOUNDARY_SEARCH_THRESHOLD} = this.constructor; - let elipsis = '...'; + let elipses = '...'; let lastParagraphIndex = Infinity; let lastWordIndex = Infinity; + const lastSubwordIndex = BOUNDARY_SEARCH_THRESHOLD - elipses.length; - const boundarySearch = this.getMessageBody() - .substring(LONG_MESSAGE_THRESHOLD - BOUNDARY_SEARCH_THRESHOLD, LONG_MESSAGE_THRESHOLD); + const baseIndex = LONG_MESSAGE_THRESHOLD - BOUNDARY_SEARCH_THRESHOLD; + const boundarySearch = this.getMessageBody().substring(baseIndex, LONG_MESSAGE_THRESHOLD); const boundaryRx = /\r?\n\r?\n|\s+/g; let result; while ((result = boundaryRx.exec(boundarySearch)) !== null) { if (/\r?\n\r?\n/.test(result[0])) { - // Paragraph boundary. Omit the elipsis + // Paragraph boundary. Omit the elipses lastParagraphIndex = result.index; - elipsis = ''; - } else if (result.index <= BOUNDARY_SEARCH_THRESHOLD - elipsis.length) { - // Word boundary. Only count if we have room for the elipsis under the cutoff. + elipses = ''; + } else if (result.index <= BOUNDARY_SEARCH_THRESHOLD - elipses.length) { + // Word boundary. Only count if we have room for the elipses under the cutoff. lastWordIndex = result.index; } } - const cutoffIndex = Math.min(lastParagraphIndex, lastWordIndex); - return this.getMessageBody().substring(0, cutoffIndex) + elipsis; + const cutoffIndex = baseIndex + Math.min(lastParagraphIndex, lastWordIndex, lastSubwordIndex); + return this.getMessageBody().substring(0, cutoffIndex) + elipses; } setMultiFileDiff(multiFileDiff) { From 94b5b960bd6018d3b6a38ab6989d8e49789013d6 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 29 Nov 2018 16:29:14 +0100 Subject: [PATCH 2035/4847] `getRemoteForBranch` now gets the remote from its remoteSet --- lib/models/repository.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/models/repository.js b/lib/models/repository.js index 68202d136e..dbb238faeb 100644 --- a/lib/models/repository.js +++ b/lib/models/repository.js @@ -214,11 +214,7 @@ export default class Repository { async getRemoteForBranch(branchName) { const name = await this.getConfig(`branch.${branchName}.remote`); - if (name === null) { - return nullRemote; - } else { - return new Remote(name); - } + return (await this.getRemotes()).withName(name); } async saveDiscardHistory() { From 6ee4dd4a6df3e340ce6f5a086045d4592769fb59 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 29 Nov 2018 16:38:02 +0100 Subject: [PATCH 2036/4847] remove unused improts --- lib/models/repository.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/models/repository.js b/lib/models/repository.js index dbb238faeb..81104895a9 100644 --- a/lib/models/repository.js +++ b/lib/models/repository.js @@ -5,7 +5,6 @@ import fs from 'fs-extra'; import {getNullActionPipelineManager} from '../action-pipeline'; import CompositeGitStrategy from '../composite-git-strategy'; -import Remote, {nullRemote} from './remote'; import Author, {nullAuthor} from './author'; import Branch from './branch'; import {Loading, Absent, LoadingGuess, AbsentGuess} from './repository-states'; From 4655dd303f756f5a5745383b3ab53510ad927c41 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 29 Nov 2018 16:53:56 +0100 Subject: [PATCH 2037/4847] [wip] render dotcom link --- lib/containers/commit-detail-container.js | 3 +++ lib/models/repository-states/present.js | 4 +++ lib/models/repository-states/state.js | 4 +++ lib/models/repository.js | 1 + lib/views/commit-detail-view.js | 30 +++++++++++++++++------ 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/lib/containers/commit-detail-container.js b/lib/containers/commit-detail-container.js index 911c73b5f8..275d82ce35 100644 --- a/lib/containers/commit-detail-container.js +++ b/lib/containers/commit-detail-container.js @@ -15,6 +15,9 @@ export default class CommitDetailContainer extends React.Component { fetchData = repository => { return yubikiri({ commit: repository.getCommit(this.props.sha), + currentBranch: repository.getCurrentBranch(), + currentRemote: async query => repository.getRemoteForBranch((await query.currentBranch).getName()), + isCommitPushed: repository.isCommitPushed(this.props.sha), }); } diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index bc28589081..6eb53323e6 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -741,6 +741,10 @@ export default class Present extends State { }); } + isCommitPushed({sha}) { + return true; + } + // Author information getAuthors(options) { diff --git a/lib/models/repository-states/state.js b/lib/models/repository-states/state.js index 92961a777a..82c443a255 100644 --- a/lib/models/repository-states/state.js +++ b/lib/models/repository-states/state.js @@ -306,6 +306,10 @@ export default class State { return Promise.resolve([]); } + isCommitPushed({sha}) { + return false; + } + // Author information getAuthors() { diff --git a/lib/models/repository.js b/lib/models/repository.js index 81104895a9..e4960aed2a 100644 --- a/lib/models/repository.js +++ b/lib/models/repository.js @@ -328,6 +328,7 @@ const delegates = [ 'getLastCommit', 'getCommit', 'getRecentCommits', + 'isCommitPushed', 'getAuthors', diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index a3b924a3ad..487ffa5c7b 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -23,6 +23,10 @@ export default class CommitDetailView extends React.Component { messageCollapsible: PropTypes.bool.isRequired, messageOpen: PropTypes.bool.isRequired, toggleMessage: PropTypes.func.isRequired, + + currentRemote: PropTypes.object.isRequired, + currentBranch: PropTypes.object.isRequired, + isCommitPushed: PropTypes.bool.isRequired, } render() { @@ -43,13 +47,7 @@ export default class CommitDetailView extends React.Component { {commit.getAuthorEmail()} committed {this.humanizeTimeSince(commit.getAuthorDate())} -
    - {/* TODO fix href */} - - {commit.getSha()} - -
    + {this.renderDotComLink()}
    @@ -87,6 +85,24 @@ export default class CommitDetailView extends React.Component { return moment(date * 1000).fromNow(); } + renderDotComLink() { + const remote = this.props.currentRemote; + const sha = this.props.commit.getSha(); + if (remote && remote.isGithubRepo() && this.props.isCommitPushed) { + const repoUrl = `https://www.github.com/${this.props.currentRemote.getOwner()}/${this.props.currentRemote.getRepo()}`; + return ( + + ); + } else { + return null; + } + } + getAuthorInfo() { const coAuthorCount = this.props.commit.getCoAuthors().length; return coAuthorCount ? this.props.commit.getAuthorEmail() : `${coAuthorCount + 1} people`; From da431290974773b1ccdede986aac2f0e6262ad6f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 29 Nov 2018 11:19:00 -0500 Subject: [PATCH 2038/4847] Toggle between an abbreviated commit message body and the full one. --- lib/views/commit-detail-view.js | 28 ++++++------ test/views/commit-detail-view.test.js | 61 +++++++++++++++++---------- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index 487ffa5c7b..9438c075c2 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -36,11 +36,9 @@ export default class CommitDetailView extends React.Component {
    -

    - {emojify(commit.getMessageSubject())} - {this.renderShowMoreButton()} -

    - {this.renderCommitMessageBody(commit)} +

    {emojify(commit.getMessageSubject())}

    + {this.renderCommitMessageBody()} + {this.renderShowMoreButton()}
    {/* TODO fix image src */} {this.renderAuthors()} @@ -60,22 +58,22 @@ export default class CommitDetailView extends React.Component { ); } - renderCommitMessageBody(commit) { - if (this.props.messageOpen || !this.props.messageCollapsible) { - return ( -
    -          {emojify(commit.getMessageBody())}
    - ); - } else { - return null; - } + renderCommitMessageBody() { + const collapsed = this.props.messageCollapsible && !this.props.messageOpen; + + return ( +
    +        {collapsed ? this.props.commit.abbreviatedBody() : this.props.commit.getMessageBody()}
    +      
    + ); } renderShowMoreButton() { if (!this.props.messageCollapsible) { return null; } - const buttonText = this.props.messageOpen ? 'Hide More' : 'Show More'; + + const buttonText = this.props.messageOpen ? 'Show Less' : 'Show More'; return ( ); diff --git a/test/views/commit-detail-view.test.js b/test/views/commit-detail-view.test.js index ee39d83e40..acca9a093d 100644 --- a/test/views/commit-detail-view.test.js +++ b/test/views/commit-detail-view.test.js @@ -5,6 +5,7 @@ import dedent from 'dedent-js'; import CommitDetailView from '../../lib/views/commit-detail-view'; import CommitDetailItem from '../../lib/items/commit-detail-item'; +import Commit from '../../lib/models/commit'; import {cloneRepository, buildRepository} from '../helpers'; import {commitBuilder} from '../builder/commit'; @@ -93,65 +94,81 @@ describe('CommitDetailView', function() { }); describe('commit message collapsibility', function() { - let wrapper; - const commitMessageBody = dedent` - if every pork chop was perfect... + let wrapper, shortMessage, longMessage; + beforeEach(function() { + shortMessage = dedent` + if every pork chop was perfect... + we wouldn't have hot dogs! + 🌭🌭🌭🌭🌭🌭🌭 + `; + + longMessage = 'this message is really really really\n'; + while (longMessage.length < Commit.LONG_MESSAGE_THRESHOLD) { + longMessage += 'really really really really really really\n'; + } + longMessage += 'really really long.'; + }); - we wouldn't have hot dogs! - 🌭🌭🌭🌭🌭🌭🌭 - `; - const commit = commitBuilder() - .authorEmail('greg@mruniverse.biz') - .messageBody(commitMessageBody) - .build(); describe('when messageCollapsible is false', function() { beforeEach(function() { + const commit = commitBuilder().messageBody(shortMessage).build(); wrapper = shallow(buildApp({commit, messageCollapsible: false})); }); + it('renders the full message body', function() { - assert.deepEqual(wrapper.find('.github-CommitDetailView-moreText').text(), commitMessageBody); + assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), shortMessage); }); - it('does not render a button', function() { + it('does not render a button', function() { + assert.isFalse(wrapper.find('.github-CommitDetailView-moreButton').exists()); }); }); + describe('when messageCollapsible is true and messageOpen is false', function() { beforeEach(function() { + const commit = commitBuilder().messageBody(longMessage).build(); wrapper = shallow(buildApp({commit, messageCollapsible: true, messageOpen: false})); }); - it('does not render commit message', function() { - assert.lengthOf(wrapper.find('.github-CommitDetailView-moreText'), 0); + + it('renders an abbreviated commit message', function() { + const messageText = wrapper.find('.github-CommitDetailView-moreText').text(); + assert.notStrictEqual(messageText, longMessage); + assert.isAtMost(messageText.length, Commit.LONG_MESSAGE_THRESHOLD); }); - it('renders button with the text `Show More`', function() { + it('renders a button to reveal the rest of the message', function() { const button = wrapper.find('.github-CommitDetailView-moreButton'); assert.lengthOf(button, 1); - assert.deepEqual(button.text(), 'Show More'); + assert.strictEqual(button.text(), 'Show More'); }); }); describe('when messageCollapsible is true and messageOpen is true', function() { let toggleMessage; + beforeEach(function() { toggleMessage = sinon.spy(); + const commit = commitBuilder().messageBody(longMessage).build(); wrapper = shallow(buildApp({commit, messageCollapsible: true, messageOpen: true, toggleMessage})); }); + it('renders the full message', function() { - assert.deepEqual(wrapper.find('.github-CommitDetailView-moreText').text(), commitMessageBody); + assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), longMessage); }); - it('renders a button with the text `Hide More`', function() { + + it('renders a button to collapse the message text', function() { const button = wrapper.find('.github-CommitDetailView-moreButton'); assert.lengthOf(button, 1); - assert.deepEqual(button.text(), 'Hide More'); + assert.strictEqual(button.text(), 'Show Less'); }); - it('button calls `toggleMessage` prop when clicked', function() { + + it('the button calls toggleMessage when clicked', function() { const button = wrapper.find('.github-CommitDetailView-moreButton'); button.simulate('click'); - assert.ok(toggleMessage.called); + assert.isTrue(toggleMessage.called); }); - }); }); }); From c58c54047d4ad44fd7b25f6fa2e8f556b9d31959 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 29 Nov 2018 17:24:26 +0100 Subject: [PATCH 2039/4847] fix: wrong conditional in hunk header --- lib/views/hunk-header-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/hunk-header-view.js b/lib/views/hunk-header-view.js index ab2a43ae1b..a2ed357015 100644 --- a/lib/views/hunk-header-view.js +++ b/lib/views/hunk-header-view.js @@ -58,7 +58,7 @@ export default class HunkHeaderView extends React.Component { } renderButtons() { - if (this.props.itemType === CommitPreviewItem || this.props.itemType === CommitDetailItem) { + if (this.props.itemType === CommitDetailItem) { return null; } else { return ( From e110282fa6fc206e771afa3bea539b0e16a1458d Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 29 Nov 2018 17:47:28 +0100 Subject: [PATCH 2040/4847] add `getBranchesWithCommit` method --- lib/git-shell-out-strategy.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 1addc791b3..5ea5d0ae56 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -934,6 +934,11 @@ export default class GitShellOutStrategy { }); } + async getBranchesWithCommit(sha, {remotesOnly} = {}) { + const args = ['branch', ...(remotesOnly ? ['--remotes'] : []), '--format=%(refname:short)', '--contains', sha]; + return (await this.exec(args)).trim().split(LINE_ENDING_REGEX); + } + checkoutFiles(paths, revision) { if (paths.length === 0) { return null; } const args = ['checkout']; From 2184380a7c5cfc6cf9275e247e87e18c7b08e26b Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 29 Nov 2018 17:57:41 +0100 Subject: [PATCH 2041/4847] add option to show local only or remote only or both --- lib/git-shell-out-strategy.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 5ea5d0ae56..38f5792480 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -934,8 +934,13 @@ export default class GitShellOutStrategy { }); } - async getBranchesWithCommit(sha, {remotesOnly} = {}) { - const args = ['branch', ...(remotesOnly ? ['--remotes'] : []), '--format=%(refname:short)', '--contains', sha]; + async getBranchesWithCommit(sha, option = {}) { + const args = ['branch', '--format=%(refname:short)', '--contains', sha]; + if (option.showLocal && option.showRemote) { + args.splice(1, 0, '--all'); + } else if (option.showRemote) { + args.splice(1, 0, '--remotes'); + } return (await this.exec(args)).trim().split(LINE_ENDING_REGEX); } From adef37cab40952bf0fd4c101cc59a0d76f8623e7 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 29 Nov 2018 18:10:38 +0100 Subject: [PATCH 2042/4847] don't use short ref --- lib/git-shell-out-strategy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 38f5792480..ea7bbad606 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -935,7 +935,7 @@ export default class GitShellOutStrategy { } async getBranchesWithCommit(sha, option = {}) { - const args = ['branch', '--format=%(refname:short)', '--contains', sha]; + const args = ['branch', '--format=%(refname)', '--contains', sha]; if (option.showLocal && option.showRemote) { args.splice(1, 0, '--all'); } else if (option.showRemote) { From ff235a5a4c84f01ed1ad608d18602a13408ab191 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 29 Nov 2018 18:11:24 +0100 Subject: [PATCH 2043/4847] `isCommitPushed` to find out if a commit exists on remote tracking branch --- lib/models/repository-states/present.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index 6eb53323e6..5e323fc4e2 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -741,8 +741,10 @@ export default class Present extends State { }); } - isCommitPushed({sha}) { - return true; + async isCommitPushed(sha) { + const remoteBranchesWithCommit = await this.git().getBranchesWithCommit(sha, {showLocal: false, showRemote: true}); + const currentRemote = (await this.repository.getCurrentBranch()).getUpstream(); + return remoteBranchesWithCommit.includes(currentRemote.getFullRef()); } // Author information From 011a3be72d0f435e850f66ce5677f119feb52604 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 29 Nov 2018 12:32:28 -0500 Subject: [PATCH 2044/4847] Enable hunk headers for CommitDetailItem --- lib/views/multi-file-patch-view.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 61414c30a3..5d1407e496 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -455,9 +455,6 @@ export default class MultiFilePatchView extends React.Component { } renderHunkHeaders(filePatch) { - if (this.props.itemType === CommitDetailItem) { - return null; - } const toggleVerb = this.props.stagingStatus === 'unstaged' ? 'Stage' : 'Unstage'; const selectedHunks = new Set( Array.from(this.props.selectedRows, row => this.props.multiFilePatch.getHunkAt(row)), From c54195aa4fe20ecec4ac99d0c7f70bf5dc9cb4d8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 29 Nov 2018 12:36:01 -0500 Subject: [PATCH 2045/4847] Let that CSS actually target the avatar element --- lib/views/commit-detail-view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index 9438c075c2..cdf82b45ff 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -117,7 +117,7 @@ export default class CommitDetailView extends React.Component { } return ( - + {authorEmails.map(this.renderAuthor)} ); From fb2ec268cd1f8f140b4739ddc3651dc2f4dd3af5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 29 Nov 2018 12:58:27 -0500 Subject: [PATCH 2046/4847] Fussing with button styles since I moved it --- styles/commit-detail.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/styles/commit-detail.less b/styles/commit-detail.less index e6cab0bf14..a4d27f89ec 100644 --- a/styles/commit-detail.less +++ b/styles/commit-detail.less @@ -47,8 +47,8 @@ &-moreButton { border: none; - margin-left: @default-padding/1.5; - padding: 0em .2em; + margin-bottom: @default-padding/1.5; + padding: 0em .4em; color: @text-color-subtle; font-style: italic; font-size: .8em; From 312eccc313db78682535566eeb44082c762f8396 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 29 Nov 2018 14:44:45 -0500 Subject: [PATCH 2047/4847] Move the "Show More" button back to the header. Move the meta information up there, too. --- lib/views/commit-detail-view.js | 8 +++++--- styles/commit-detail.less | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index cdf82b45ff..3d513cd671 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -36,9 +36,10 @@ export default class CommitDetailView extends React.Component {
    -

    {emojify(commit.getMessageSubject())}

    - {this.renderCommitMessageBody()} - {this.renderShowMoreButton()} +

    + {emojify(commit.getMessageSubject())} + {this.renderShowMoreButton()} +

    {/* TODO fix image src */} {this.renderAuthors()} @@ -47,6 +48,7 @@ export default class CommitDetailView extends React.Component { {this.renderDotComLink()}
    + {this.renderCommitMessageBody()}
    Date: Thu, 29 Nov 2018 20:50:12 +0100 Subject: [PATCH 2048/4847] still show sha when it cannot be linked --- lib/views/commit-detail-view.js | 16 ++++++++-------- styles/commit-detail.less | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index 3d513cd671..e3e8b6ad4f 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -46,7 +46,9 @@ export default class CommitDetailView extends React.Component { {commit.getAuthorEmail()} committed {this.humanizeTimeSince(commit.getAuthorDate())} - {this.renderDotComLink()} +
    + {this.renderDotComLink()} +
    {this.renderCommitMessageBody()}
    @@ -91,15 +93,13 @@ export default class CommitDetailView extends React.Component { if (remote && remote.isGithubRepo() && this.props.isCommitPushed) { const repoUrl = `https://www.github.com/${this.props.currentRemote.getOwner()}/${this.props.currentRemote.getRepo()}`; return ( - + + {sha} + ); } else { - return null; + return ({sha}); } } diff --git a/styles/commit-detail.less b/styles/commit-detail.less index e6cab0bf14..b349b8e296 100644 --- a/styles/commit-detail.less +++ b/styles/commit-detail.less @@ -47,8 +47,8 @@ &-moreButton { border: none; - margin-left: @default-padding/1.5; - padding: 0em .2em; + margin-bottom: @default-padding/1.5; + padding: 0em .4em; color: @text-color-subtle; font-style: italic; font-size: .8em; @@ -78,12 +78,12 @@ flex: 0 0 7ch; // Limit to 7 characters margin-left: @default-padding*2; line-height: @avatar-dimensions; - color: @text-color-info; + color: @text-color-subtle; font-family: var(--editor-font-family); white-space: nowrap; overflow: hidden; a { - color: inherit; + color: @text-color-info; } } } From aedb0761f84ee22e8d3c7a6dd8e2fdc418d2db61 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 29 Nov 2018 15:20:36 -0500 Subject: [PATCH 2049/4847] Turn that back to a left margin :art: --- styles/commit-detail.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styles/commit-detail.less b/styles/commit-detail.less index b349b8e296..a6d5584545 100644 --- a/styles/commit-detail.less +++ b/styles/commit-detail.less @@ -47,7 +47,7 @@ &-moreButton { border: none; - margin-bottom: @default-padding/1.5; + margin-left: @default-padding/1.5; padding: 0em .4em; color: @text-color-subtle; font-style: italic; From d007a3492f0c99b7052cdcabcb182924c5770f97 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 29 Nov 2018 15:21:48 -0500 Subject: [PATCH 2050/4847] Drop LONG_MESSAGE_THRESHOLD to 500 and prepare newline counting --- lib/models/commit.js | 45 +++++++++------- test/models/commit.test.js | 104 +++++++++++++++---------------------- 2 files changed, 67 insertions(+), 82 deletions(-) diff --git a/lib/models/commit.js b/lib/models/commit.js index 3e7e65b3d4..99cccfa531 100644 --- a/lib/models/commit.js +++ b/lib/models/commit.js @@ -1,9 +1,11 @@ const UNBORN = Symbol('unborn'); -export default class Commit { - static LONG_MESSAGE_THRESHOLD = 1000; +// Truncation elipsis styles +const WORD_ELIPSES = '...'; +const PARAGRAPH_ELIPSES = '\n\n...'; - static BOUNDARY_SEARCH_THRESHOLD = 100; +export default class Commit { + static LONG_MESSAGE_THRESHOLD = 500; static createUnborn() { return new Commit({unbornRef: UNBORN}); @@ -64,29 +66,32 @@ export default class Commit { return this.getMessageBody(); } - const {LONG_MESSAGE_THRESHOLD, BOUNDARY_SEARCH_THRESHOLD} = this.constructor; - let elipses = '...'; - let lastParagraphIndex = Infinity; - let lastWordIndex = Infinity; - const lastSubwordIndex = BOUNDARY_SEARCH_THRESHOLD - elipses.length; + const {LONG_MESSAGE_THRESHOLD} = this.constructor; - const baseIndex = LONG_MESSAGE_THRESHOLD - BOUNDARY_SEARCH_THRESHOLD; - const boundarySearch = this.getMessageBody().substring(baseIndex, LONG_MESSAGE_THRESHOLD); + let lastParagraphCutoff = null; + let lastWordCutoff = null; - const boundaryRx = /\r?\n\r?\n|\s+/g; + const searchText = this.getMessageBody().substring(0, LONG_MESSAGE_THRESHOLD); + const boundaryRx = /\s+/g; let result; - while ((result = boundaryRx.exec(boundarySearch)) !== null) { - if (/\r?\n\r?\n/.test(result[0])) { - // Paragraph boundary. Omit the elipses - lastParagraphIndex = result.index; - elipses = ''; - } else if (result.index <= BOUNDARY_SEARCH_THRESHOLD - elipses.length) { - // Word boundary. Only count if we have room for the elipses under the cutoff. - lastWordIndex = result.index; + while ((result = boundaryRx.exec(searchText)) !== null) { + const newlineCount = (result[0].match(/\r?\n/g) || []).length; + if (newlineCount < 2 && result.index <= LONG_MESSAGE_THRESHOLD - WORD_ELIPSES.length) { + lastWordCutoff = result.index; + } else if (result.index < LONG_MESSAGE_THRESHOLD - PARAGRAPH_ELIPSES.length) { + lastParagraphCutoff = result.index; } } - const cutoffIndex = baseIndex + Math.min(lastParagraphIndex, lastWordIndex, lastSubwordIndex); + let elipses = WORD_ELIPSES; + let cutoffIndex = LONG_MESSAGE_THRESHOLD - WORD_ELIPSES.length; + if (lastParagraphCutoff !== null) { + elipses = PARAGRAPH_ELIPSES; + cutoffIndex = lastParagraphCutoff; + } else if (lastWordCutoff !== null) { + cutoffIndex = lastWordCutoff; + } + return this.getMessageBody().substring(0, cutoffIndex) + elipses; } diff --git a/test/models/commit.test.js b/test/models/commit.test.js index 9e3e7664ea..ee9f28f43e 100644 --- a/test/models/commit.test.js +++ b/test/models/commit.test.js @@ -45,108 +45,88 @@ describe('Commit', function() { assert.strictEqual(commit.abbreviatedBody(), 'short'); }); - it('truncates the message body at the nearest paragraph boundary before the cutoff if one is nearby', function() { - // The | is at the 1000-character mark. + it('truncates the message body at the last paragraph boundary before the cutoff if one is present', function() { const body = dedent` Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. Mazim alterum sea ea, - essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore albucius te vis, eam - tantas nullam corrumpit ad, in oratio luptatum eleifend vim. + essent malorum persius ne mei. - Ea salutatus contentiones eos. Eam in veniam facete volutpat, solum appetere adversarium ut quo. Vel cu appetere - urbanitas, usu ut aperiri mediocritatem, alia molestie urbanitas cu qui. Velit antiopam erroribus no eum, - scripta iudicabit ne nam, in duis clita commodo sit. + Nam ea tempor qualisque, modus doming te has. Affert dolore albucius te vis, eam + tantas nullam corrumpit ad, in oratio luptatum eleifend vim. Ea salutatus contentiones eos. Eam in veniam facete + volutpat, solum appetere adversarium ut quo. Vel cu appetere urbanitas, usu ut aperiri mediocritatem, alia + molestie urbanitas cu qui. - Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat comprehensam ut his, et eum - voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei liber putant. Ad doctus + Velit antiopam erroribus no eu|m, scripta iudicabit ne nam, in duis clita commodo + sit. Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat comprehensam ut his, et + eum voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei liber putant. Ad doctus tractatos ius, duo ad civibus alienum, nominati voluptaria sed an. Libris essent philosophia et vix. Nusquam reprehendunt et mea. Ea eius omnes voluptua sit. - - No cum illud verear efficiantur. Id altera imperdiet nec. Noster aud|iam accusamus mei at, no zril libris nemore - duo, ius ne rebum doctus fuisset. Legimus epicurei in sit, esse purto suscipit eu qui, oporteat deserunt - delicatissimi sea in. Est id putent accusata convenire, no tibique molestie accommodare quo, cu est fuisset - offendit evertitur. `; const commit = commitBuilder().messageBody(body).build(); assert.strictEqual(commit.abbreviatedBody(), dedent` Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. Mazim alterum sea ea, - essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore albucius te vis, eam - tantas nullam corrumpit ad, in oratio luptatum eleifend vim. + essent malorum persius ne mei. - Ea salutatus contentiones eos. Eam in veniam facete volutpat, solum appetere adversarium ut quo. Vel cu appetere - urbanitas, usu ut aperiri mediocritatem, alia molestie urbanitas cu qui. Velit antiopam erroribus no eum, - scripta iudicabit ne nam, in duis clita commodo sit. + Nam ea tempor qualisque, modus doming te has. Affert dolore albucius te vis, eam + tantas nullam corrumpit ad, in oratio luptatum eleifend vim. Ea salutatus contentiones eos. Eam in veniam facete + volutpat, solum appetere adversarium ut quo. Vel cu appetere urbanitas, usu ut aperiri mediocritatem, alia + molestie urbanitas cu qui. - Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat comprehensam ut his, et eum - voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei liber putant. Ad doctus - tractatos ius, duo ad civibus alienum, nominati voluptaria sed an. Libris essent philosophia et vix. Nusquam - reprehendunt et mea. Ea eius omnes voluptua sit. + ... `); }); - it('truncates the message body at the nearest word boundary before the cutoff if one is nearby', function() { - // The | is at the 1000-character mark. + it('truncates the message body at the nearest word boundary before the cutoff if one is present', function() { + // The | is at the 500-character mark. const body = dedent` - Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. - - Mazim alterum sea ea, essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore - albucius te vis, eam tantas nullam corrumpit ad, in oratio luptatum eleifend vim. Ea salutatus contentiones eos. - Eam in veniam facete volutpat, solum appetere adversarium ut quo. Vel cu appetere urbanitas, usu ut aperiri - mediocritatem, alia molestie urbanitas cu qui. Velit antiopam erroribus no eum, scripta iudicabit ne nam, in - duis clita commodo sit. Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat - comprehensam ut his, et eum voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei - liber putant. Ad doctus tractatos ius, duo ad civibus alienum, nominati voluptaria sed an. Libris essent - philosophia et vix. Nusquam reprehendunt et mea. Ea eius omnes voluptua sit. No cum illud verear efficiantur. Id - altera imperdiet nec. Noster audia|m accusamus mei at, no zril libris nemore duo, ius ne rebum doctus fuisset. - Legimus epicurei in sit, esse purto suscipit eu qui, oporteat deserunt delicatissimi sea in. Est id putent - accusata convenire, no tibique molestie accommodare quo, cu est fuisset offendit evertitur. + Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. Mazim alterum sea ea, + essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore albucius te vis, eam + tantas nullam corrumpit ad, in oratio luptatum eleifend vim. Ea salutatus contentiones eos. Eam in veniam facete + volutpat, solum appetere adversarium ut quo. Vel cu appetere urbanitas, usu ut aperiri mediocritatem, alia + molestie urbanitas cu qui. Velit antiopam erroribus no eum,| scripta iudicabit ne nam, in duis clita commodo + sit. Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat comprehensam ut his, et + eum voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei liber putant. Ad doctus + tractatos ius, duo ad civibus alienum, nominati voluptaria sed an. Libris essent philosophia et vix. Nusquam + reprehendunt et mea. Ea eius omnes voluptua sit. No cum illud verear efficiantur. Id altera imperdiet nec. + Noster audia|m accusamus mei at, no zril libris nemore duo, ius ne rebum doctus fuisset. Legimus epicurei in + sit, esse purto suscipit eu qui, oporteat deserunt delicatissimi sea in. Est id putent accusata convenire, no + tibique molestie accommodare quo, cu est fuisset offendit evertitur. `; const commit = commitBuilder().messageBody(body).build(); assert.strictEqual(commit.abbreviatedBody(), dedent` - Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. - - Mazim alterum sea ea, essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore - albucius te vis, eam tantas nullam corrumpit ad, in oratio luptatum eleifend vim. Ea salutatus contentiones eos. - Eam in veniam facete volutpat, solum appetere adversarium ut quo. Vel cu appetere urbanitas, usu ut aperiri - mediocritatem, alia molestie urbanitas cu qui. Velit antiopam erroribus no eum, scripta iudicabit ne nam, in - duis clita commodo sit. Assum sensibus oportere te vel, vis semper evertitur definiebas in. Tamquam feugiat - comprehensam ut his, et eum voluptua ullamcorper, ex mei debitis inciderint. Sit discere pertinax te, an mei - liber putant. Ad doctus tractatos ius, duo ad civibus alienum, nominati voluptaria sed an. Libris essent - philosophia et vix. Nusquam reprehendunt et mea. Ea eius omnes voluptua sit. No cum illud verear efficiantur. Id - altera imperdiet nec. Noster... + Lorem ipsum dolor sit amet, et his justo deleniti, omnium fastidii adversarium at has. Mazim alterum sea ea, + essent malorum persius ne mei. Nam ea tempor qualisque, modus doming te has. Affert dolore albucius te vis, eam + tantas nullam corrumpit ad, in oratio luptatum eleifend vim. Ea salutatus contentiones eos. Eam in veniam facete + volutpat, solum appetere adversarium ut quo. Vel cu appetere urbanitas, usu ut aperiri mediocritatem, alia + molestie urbanitas cu qui. Velit antiopam erroribus no... `); }); it('truncates the message body at the character cutoff if no word or paragraph boundaries can be found', function() { - // The | is at the 1000-character mark. - const body = 'Loremipsumdolorsitamet,ethisjustodeleniti,omniumfastidiiadversariumathas.\n\n' + - 'Mazim alterumseaea,essentmalorumpersiusnemei.Nameatemporqualisque,modusdomingtehas.Affertdolore' + + // The | is at the 500-character mark. + const body = 'Loremipsumdolorsitamet,ethisjustodeleniti,omniumfastidiiadversariumathas.' + + 'Mazimalterumseaea,essentmalorumpersiusnemei.Nameatemporqualisque,modusdomingtehas.Affertdolore' + 'albuciustevis,eamtantasnullamcorrumpitad,inoratioluptatumeleifendvim.Easalutatuscontentioneseos.' + 'Eaminveniamfacetevolutpat,solumappetereadversariumutquo.Velcuappetereurbanitas,usuutaperiri' + 'mediocritatem,aliamolestieurbanitascuqui.Velitantiopamerroribusnoeum,scriptaiudicabitnenam,in' + - 'duisclitacommodosit.Assumsensibusoporteretevel,vissemperevertiturdefiniebasin.Tamquamfeugiat' + + 'duisclitacommodosit.Assumsensibusoporteretevel,vissem|perevertiturdefiniebasin.Tamquamfeugiat' + 'comprehensamuthis,eteumvoluptuaullamcorper,exmeidebitisinciderint.Sitdiscerepertinaxte,anmei' + 'liberputant.Addoctustractatosius,duoadcivibusalienum,nominativoluptariasedan.Librisessent' + 'philosophiaetvix.Nusquamreprehenduntetmea.Eaeiusomnesvoluptuasit.Nocumilludverearefficiantur.Id' + 'alteraimperdietnec.Nosteraudiamaccusamusmeiat,nozrillibrisnemoreduo,iusnerebumdoctusfuisset.' + 'Legimusepicureiinsit,essepurtosuscipiteuqui,oporteatdeseruntdelicatissimiseain.Estidputent' + - '|accusataconvenire,notibiquemolestieaccommodarequo,cuestfuissetoffenditevertitur.'; + 'accusataconvenire,notibiquemolestieaccommodarequo,cuestfuissetoffenditevertitur.'; const commit = commitBuilder().messageBody(body).build(); assert.strictEqual( commit.abbreviatedBody(), - 'Loremipsumdolorsitamet,ethisjustodeleniti,omniumfastidiiadversariumathas.\n\n' + - 'Mazim alterumseaea,essentmalorumpersiusnemei.Nameatemporqualisque,modusdomingtehas.Affertdolore' + + 'Loremipsumdolorsitamet,ethisjustodeleniti,omniumfastidiiadversariumathas.' + + 'Mazimalterumseaea,essentmalorumpersiusnemei.Nameatemporqualisque,modusdomingtehas.Affertdolore' + 'albuciustevis,eamtantasnullamcorrumpitad,inoratioluptatumeleifendvim.Easalutatuscontentioneseos.' + 'Eaminveniamfacetevolutpat,solumappetereadversariumutquo.Velcuappetereurbanitas,usuutaperiri' + 'mediocritatem,aliamolestieurbanitascuqui.Velitantiopamerroribusnoeum,scriptaiudicabitnenam,in' + - 'duisclitacommodosit.Assumsensibusoporteretevel,vissemperevertiturdefiniebasin.Tamquamfeugiat' + - 'comprehensamuthis,eteumvoluptuaullamcorper,exmeidebitisinciderint.Sitdiscerepertinaxte,anmei' + - 'liberputant.Addoctustractatosius,duoadcivibusalienum,nominativoluptariasedan.Librisessent' + - 'philosophiaetvix.Nusquamreprehenduntetmea.Eaeiusomnesvoluptuasit.Nocumilludverearefficiantur.Id' + - 'alteraimperdietnec.Nosteraudiamaccusamusmeiat,nozrillibrisnemoreduo,iusnerebumdoctusfuisset.' + - 'Legimusepicureiinsit,essepurtosuscipiteuqui,oporteatdeseruntdelicatissimiseain.Estidput...', + 'duisclitacommodosit.Assumsensibusoporteretevel,vis...', ); }); }); From 682503cc3fe0687b21c91df89299f47b2b0bec93 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 29 Nov 2018 15:33:42 -0500 Subject: [PATCH 2051/4847] Armor the abbreviation logic against messages with many short lines --- lib/models/commit.js | 29 ++++++++++++++++++++++++++--- test/models/commit.test.js | 18 ++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/lib/models/commit.js b/lib/models/commit.js index 99cccfa531..4f69679c19 100644 --- a/lib/models/commit.js +++ b/lib/models/commit.js @@ -2,11 +2,14 @@ const UNBORN = Symbol('unborn'); // Truncation elipsis styles const WORD_ELIPSES = '...'; +const NEWLINE_ELIPSES = '\n...'; const PARAGRAPH_ELIPSES = '\n\n...'; export default class Commit { static LONG_MESSAGE_THRESHOLD = 500; + static NEWLINE_THRESHOLD = 9; + static createUnborn() { return new Commit({unbornRef: UNBORN}); } @@ -47,7 +50,15 @@ export default class Commit { } isBodyLong() { - return this.getMessageBody().length > this.constructor.LONG_MESSAGE_THRESHOLD; + if (this.getMessageBody().length > this.constructor.LONG_MESSAGE_THRESHOLD) { + return true; + } + + if ((this.getMessageBody().match(/\r?\n/g) || []).length > this.constructor.NEWLINE_THRESHOLD) { + return true; + } + + return false; } getFullMessage() { @@ -66,16 +77,25 @@ export default class Commit { return this.getMessageBody(); } - const {LONG_MESSAGE_THRESHOLD} = this.constructor; + const {LONG_MESSAGE_THRESHOLD, NEWLINE_THRESHOLD} = this.constructor; + let lastNewlineCutoff = null; let lastParagraphCutoff = null; let lastWordCutoff = null; const searchText = this.getMessageBody().substring(0, LONG_MESSAGE_THRESHOLD); const boundaryRx = /\s+/g; let result; + let lineCount = 0; while ((result = boundaryRx.exec(searchText)) !== null) { const newlineCount = (result[0].match(/\r?\n/g) || []).length; + + lineCount += newlineCount; + if (lineCount > NEWLINE_THRESHOLD) { + lastNewlineCutoff = result.index; + break; + } + if (newlineCount < 2 && result.index <= LONG_MESSAGE_THRESHOLD - WORD_ELIPSES.length) { lastWordCutoff = result.index; } else if (result.index < LONG_MESSAGE_THRESHOLD - PARAGRAPH_ELIPSES.length) { @@ -85,7 +105,10 @@ export default class Commit { let elipses = WORD_ELIPSES; let cutoffIndex = LONG_MESSAGE_THRESHOLD - WORD_ELIPSES.length; - if (lastParagraphCutoff !== null) { + if (lastNewlineCutoff !== null) { + elipses = NEWLINE_ELIPSES; + cutoffIndex = lastNewlineCutoff; + } else if (lastParagraphCutoff !== null) { elipses = PARAGRAPH_ELIPSES; cutoffIndex = lastParagraphCutoff; } else if (lastWordCutoff !== null) { diff --git a/test/models/commit.test.js b/test/models/commit.test.js index ee9f28f43e..4b4d6aa08d 100644 --- a/test/models/commit.test.js +++ b/test/models/commit.test.js @@ -34,6 +34,15 @@ describe('Commit', function() { assert.isTrue(commit.isBodyLong()); }); + it('returns true if the commit message body contains too many newlines', function() { + let messageBody = 'a\n'; + for (let i = 0; i < 50; i++) { + messageBody += 'a\n'; + } + const commit = commitBuilder().messageBody(messageBody).build(); + assert.isTrue(commit.isBodyLong()); + }); + it('returns false for a null commit', function() { assert.isFalse(nullCommit.isBodyLong()); }); @@ -129,5 +138,14 @@ describe('Commit', function() { 'duisclitacommodosit.Assumsensibusoporteretevel,vis...', ); }); + + it('truncates the message body when it contains too many newlines', function() { + let messageBody = ''; + for (let i = 0; i < 50; i++) { + messageBody += `${i}\n`; + } + const commit = commitBuilder().messageBody(messageBody).build(); + assert.strictEqual(commit.abbreviatedBody(), '0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n...'); + }); }); }); From aff05e5c50e2d8a73e8a2e074a4ea1c12bc8e36b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 29 Nov 2018 15:46:42 -0500 Subject: [PATCH 2052/4847] Allow the CommitDetailView header to focus and use native bindings --- lib/views/commit-detail-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index e3e8b6ad4f..2684c7c28d 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -34,7 +34,7 @@ export default class CommitDetailView extends React.Component { return (
    -
    +

    {emojify(commit.getMessageSubject())} From 5b0c75a26577b62408c52978660c1ce2fb44f164 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 29 Nov 2018 13:14:53 -0800 Subject: [PATCH 2053/4847] set a max-height on the commit message body text. We want the content beneath to remain visible / scrollable. --- styles/commit-detail.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/styles/commit-detail.less b/styles/commit-detail.less index a6d5584545..5044469874 100644 --- a/styles/commit-detail.less +++ b/styles/commit-detail.less @@ -69,6 +69,9 @@ word-break: break-word; white-space: pre-wrap; background-color: transparent; + // in the case of loonnng commit message bodies, we want to cap the height so that + // the content beneath will remain visible / scrollable. + max-height: 55vh; &:empty { display: none; } From 5fa5e65775272af634cdfb4002ba471e701c6e48 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 29 Nov 2018 21:31:39 +0100 Subject: [PATCH 2054/4847] update function name in state --- lib/models/repository-states/state.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/repository-states/state.js b/lib/models/repository-states/state.js index 82c443a255..747b7b3ac5 100644 --- a/lib/models/repository-states/state.js +++ b/lib/models/repository-states/state.js @@ -306,7 +306,7 @@ export default class State { return Promise.resolve([]); } - isCommitPushed({sha}) { + isCommitPushed(sha) { return false; } From dfa6c6a619487add5da72447e893f8bb4f1865c5 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 29 Nov 2018 21:32:23 +0100 Subject: [PATCH 2055/4847] add isCommitPushed to default returns a null object test --- test/models/repository.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/repository.test.js b/test/models/repository.test.js index 2eaac205e5..99a3ec2746 100644 --- a/test/models/repository.test.js +++ b/test/models/repository.test.js @@ -64,7 +64,7 @@ describe('Repository', function() { for (const method of [ 'isLoadingGuess', 'isAbsentGuess', 'isAbsent', 'isLoading', 'isEmpty', 'isPresent', 'isTooLarge', 'isUndetermined', 'showGitTabInit', 'showGitTabInitInProgress', 'showGitTabLoading', 'showStatusBarTiles', - 'hasDiscardHistory', 'isMerging', 'isRebasing', + 'hasDiscardHistory', 'isMerging', 'isRebasing', 'isCommitPushed', ]) { assert.isFalse(await repository[method]()); } From b7ef5ed750cb44d5a0ccff1907e3a2de5a423aee Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 29 Nov 2018 22:21:15 +0100 Subject: [PATCH 2056/4847] after undoing a commit, close corresponding commit item pane, if opened. --- lib/controllers/git-tab-controller.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index 57087c7170..f3322f4c79 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -11,6 +11,7 @@ import { CommitPropType, BranchPropType, FilePatchItemPropType, MergeConflictItemPropType, RefHolderPropType, } from '../prop-types'; import {autobind} from '../helpers'; +import CommitDetailItem from '../items/commit-detail-item'; export default class GitTabController extends React.Component { static focus = { @@ -277,6 +278,16 @@ export default class GitTabController extends React.Component { new Author(author.email, author.name)); this.updateSelectedCoAuthors(coAuthors); + + // close corresponding commit item pane, if opened + const uri = CommitDetailItem.buildURI(this.props.repository.getWorkingDirectoryPath(), lastCommit.getSha()); + const pane = this.props.workspace.paneForURI(uri); + if (pane) { + const item = pane.itemForURI(uri); + if (item) { + await pane.destroyItem(item); + } + } return null; } From 9341c95edcca0eebb6adc05c45ab455c6a2d43e0 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 30 Nov 2018 13:03:13 +0900 Subject: [PATCH 2057/4847] Move "show more" button --- lib/views/commit-detail-view.js | 2 +- styles/commit-detail.less | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index 2684c7c28d..e76b70ec22 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -38,7 +38,6 @@ export default class CommitDetailView extends React.Component {

    {emojify(commit.getMessageSubject())} - {this.renderShowMoreButton()}

    {/* TODO fix image src */} @@ -50,6 +49,7 @@ export default class CommitDetailView extends React.Component { {this.renderDotComLink()}
    + {this.renderShowMoreButton()} {this.renderCommitMessageBody()}

    diff --git a/styles/commit-detail.less b/styles/commit-detail.less index 5044469874..9f9bcc4762 100644 --- a/styles/commit-detail.less +++ b/styles/commit-detail.less @@ -16,6 +16,7 @@ &-commit { padding: @default-padding*2; + padding-bottom: 0; } &-title { @@ -35,7 +36,7 @@ &-meta { display: flex; align-items: center; - margin-top: @default-padding/2; + margin: @default-padding/2 0 @default-padding*2 0; } &-metaText { @@ -46,12 +47,12 @@ } &-moreButton { - border: none; - margin-left: @default-padding/1.5; + position: absolute; + left: 50%; + transform: translate(-50%, -50%); padding: 0em .4em; color: @text-color-subtle; font-style: italic; - font-size: .8em; border: 1px solid @base-border-color; border-radius: @component-border-radius; background-color: @button-background-color; @@ -62,12 +63,13 @@ } &-moreText { - padding: @default-padding/2 0 @default-padding 0; + padding: @default-padding*2 0; font-size: inherit; font-family: var(--editor-font-family); word-wrap: initial; word-break: break-word; white-space: pre-wrap; + border-top: 1px solid @base-border-color; background-color: transparent; // in the case of loonnng commit message bodies, we want to cap the height so that // the content beneath will remain visible / scrollable. From 99ba3bc4cc2c0e512d9116e46b823b271416d035 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 29 Nov 2018 21:00:40 -0800 Subject: [PATCH 2058/4847] [wip] keyboard navigability in RecentCommitsView ...I feel like I'm doing this wrong. Feel free to revert and start over. --- keymaps/git.cson | 5 ++++ lib/controllers/recent-commits-controller.js | 2 ++ lib/views/git-tab-view.js | 7 +++++ lib/views/recent-commits-view.js | 29 ++++++++++++++++++++ test/views/git-tab-view.test.js | 9 ++++++ 5 files changed, 52 insertions(+) diff --git a/keymaps/git.cson b/keymaps/git.cson index 038e4d942c..f6236b9a07 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -32,6 +32,11 @@ 'tab': 'core:focus-next' 'shift-tab': 'core:focus-previous' +'.github-RecentCommitsView': + 'up': 'github:recent-commit-up' + 'down': 'github:recent-commit-down' + 'enter': 'github:open-recent-commit' + '.github-StagingView.unstaged-changes-focused': 'cmd-backspace': 'github:discard-changes-in-selected-files' 'ctrl-backspace': 'github:discard-changes-in-selected-files' diff --git a/lib/controllers/recent-commits-controller.js b/lib/controllers/recent-commits-controller.js index 2e72da64f9..e97b079192 100644 --- a/lib/controllers/recent-commits-controller.js +++ b/lib/controllers/recent-commits-controller.js @@ -15,6 +15,7 @@ export default class RecentCommitsController extends React.Component { undoLastCommit: PropTypes.func.isRequired, workspace: PropTypes.object.isRequired, repository: PropTypes.object.isRequired, + commandRegistry: PropTypes.object.isRequired, } constructor(props, context) { @@ -54,6 +55,7 @@ export default class RecentCommitsController extends React.Component { undoLastCommit={this.props.undoLastCommit} openCommit={this.openCommit} selectedCommitSha={this.state.selectedCommitSha} + commandRegistry={this.props.commandRegistry} /> ); } diff --git a/lib/views/git-tab-view.js b/lib/views/git-tab-view.js index fb7339869d..322cc3ad97 100644 --- a/lib/views/git-tab-view.js +++ b/lib/views/git-tab-view.js @@ -7,6 +7,7 @@ import StagingView from './staging-view'; import GitLogo from './git-logo'; import CommitController from '../controllers/commit-controller'; import RecentCommitsController from '../controllers/recent-commits-controller'; +import RecentCommitsView from '../views/recent-commits-view'; import RefHolder from '../models/ref-holder'; import {isValidWorkdir, autobind} from '../helpers'; import {AuthorPropType, UserStorePropType, RefHolderPropType} from '../prop-types'; @@ -16,6 +17,7 @@ export default class GitTabView extends React.Component { ...StagingView.focus, ...CommitController.focus, ...RecentCommitsController.focus, + ...RecentCommitsView.focus, }; static propTypes = { @@ -193,6 +195,7 @@ export default class GitTabView extends React.Component { updateSelectedCoAuthors={this.props.updateSelectedCoAuthors} /> view.setFocus(focus)).getOr(false); + } + + rememberFocus(event) { + return this.refRecentCommits.map(view => view.rememberFocus(event)).getOr(null); + } + + selectNextCommit() { + // okay, we should probably move the state of the selected commit into this component + // instead of using the sha, so we can more easily move to next / previous. + } + render() { return (
    + + + {this.renderCommits()}
    ); diff --git a/test/views/git-tab-view.test.js b/test/views/git-tab-view.test.js index c21f152e91..5164c65ecb 100644 --- a/test/views/git-tab-view.test.js +++ b/test/views/git-tab-view.test.js @@ -234,4 +234,13 @@ describe('GitTabView', function() { assert.isTrue(setFocus.called); assert.isTrue(setFocus.lastCall.returnValue); }); + + it('imperatively focuses the recent commits view', async function() { + const wrapper = mount(await buildApp()); + + const setFocus = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'setFocus'); + wrapper.instance().focusAndSelectRecentCommit(); + assert.isTrue(setFocus.called); + assert.isTrue(setFocus.lastCall.returnValue); + }); }); From 2bed5f1db9d939f6fde9553157796506a7b20971 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 29 Nov 2018 17:06:11 -0800 Subject: [PATCH 2059/4847] Display co-author information --- lib/views/commit-detail-view.js | 13 +++++++--- test/views/commit-detail-view.test.js | 35 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index e76b70ec22..40a5280618 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -43,7 +43,7 @@ export default class CommitDetailView extends React.Component { {/* TODO fix image src */} {this.renderAuthors()} - {commit.getAuthorEmail()} committed {this.humanizeTimeSince(commit.getAuthorDate())} + {this.getAuthorInfo()} committed {this.humanizeTimeSince(commit.getAuthorDate())}
    {this.renderDotComLink()} @@ -104,8 +104,15 @@ export default class CommitDetailView extends React.Component { } getAuthorInfo() { - const coAuthorCount = this.props.commit.getCoAuthors().length; - return coAuthorCount ? this.props.commit.getAuthorEmail() : `${coAuthorCount + 1} people`; + const commit = this.props.commit; + const coAuthorCount = commit.getCoAuthors().length; + if (coAuthorCount === 0) { + return commit.getAuthorEmail(); + } else if (coAuthorCount === 1) { + return `${commit.getAuthorEmail()} and ${commit.getCoAuthors()[0].email}`; + } else { + return `${commit.getAuthorEmail()} and ${coAuthorCount} others`; + } } renderAuthor(email) { diff --git a/test/views/commit-detail-view.test.js b/test/views/commit-detail-view.test.js index acca9a093d..e56c35a042 100644 --- a/test/views/commit-detail-view.test.js +++ b/test/views/commit-detail-view.test.js @@ -93,6 +93,41 @@ describe('CommitDetailView', function() { ); }); + describe('getAuthorInfo', function() { + describe('when there are no co-authors', function() { + it('returns only the author', function() { + const commit = commitBuilder() + .authorEmail('blaze@it.com') + .build(); + const wrapper = shallow(buildApp({commit})); + assert.strictEqual(wrapper.instance().getAuthorInfo(), 'blaze@it.com'); + }); + }); + + describe('when there is one co-author', function() { + it('returns author and the co-author', function() { + const commit = commitBuilder() + .authorEmail('blaze@it.com') + .addCoAuthor('two', 'two@coauthor.com') + .build(); + const wrapper = shallow(buildApp({commit})); + assert.strictEqual(wrapper.instance().getAuthorInfo(), 'blaze@it.com and two@coauthor.com'); + }); + }); + + describe('when there is more than one co-author', function() { + it('returns the author and number of co-authors', function() { + const commit = commitBuilder() + .authorEmail('blaze@it.com') + .addCoAuthor('two', 'two@coauthor.com') + .addCoAuthor('three', 'three@coauthor.com') + .build(); + const wrapper = shallow(buildApp({commit})); + assert.strictEqual(wrapper.instance().getAuthorInfo(), 'blaze@it.com and 2 others'); + }); + }); + }); + describe('commit message collapsibility', function() { let wrapper, shortMessage, longMessage; From d5efe90bd53e024e4deccf0c8ddf549a4ab7a7ec Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 29 Nov 2018 17:57:14 -0800 Subject: [PATCH 2060/4847] Add test for RecentCommitsController#openCommit, including event recording --- lib/controllers/recent-commits-controller.js | 2 +- .../recent-commits-controller.test.js | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/lib/controllers/recent-commits-controller.js b/lib/controllers/recent-commits-controller.js index e97b079192..a257cab1fc 100644 --- a/lib/controllers/recent-commits-controller.js +++ b/lib/controllers/recent-commits-controller.js @@ -64,7 +64,7 @@ export default class RecentCommitsController extends React.Component { const workdir = this.props.repository.getWorkingDirectoryPath(); const uri = CommitDetailItem.buildURI(workdir, sha); this.props.workspace.open(uri).then(() => { - addEvent('open-commit-in-pane', {package: 'github', from: 'recent commit'}); + addEvent('open-commit-in-pane', {package: 'github', from: this.constructor.name}); }); } } diff --git a/test/controllers/recent-commits-controller.test.js b/test/controllers/recent-commits-controller.test.js index 66151879b1..f69c33ae17 100644 --- a/test/controllers/recent-commits-controller.test.js +++ b/test/controllers/recent-commits-controller.test.js @@ -3,6 +3,8 @@ import {shallow} from 'enzyme'; import RecentCommitsController from '../../lib/controllers/recent-commits-controller'; import Commit from '../../lib/models/commit'; +import {cloneRepository, buildRepository} from '../helpers'; +import * as reporterProxy from '../../lib/reporter-proxy'; describe('RecentCommitsController', function() { let app; @@ -23,4 +25,46 @@ describe('RecentCommitsController', function() { const wrapper = shallow(app); assert.isTrue(wrapper.find('RecentCommitsView').prop('isLoading')); }); + + describe('openCommit({sha})', function() { + let atomEnv, workdirPath, repository; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + workdirPath = await cloneRepository(); + repository = await buildRepository(workdirPath); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + it('opens a commit detail item', function() { + sinon.stub(atomEnv.workspace, 'open').resolves(); + + const sha = 'asdf1234'; + const commits = [new Commit({sha})]; + app = React.cloneElement(app, {commits, workspace: atomEnv.workspace, repository}); + const wrapper = shallow(app); + wrapper.instance().openCommit({sha: 'asdf1234'}); + + assert.isTrue(atomEnv.workspace.open.calledWith( + `atom-github://commit-detail?workdir=${encodeURIComponent(workdirPath)}` + + `&sha=${encodeURIComponent(sha)}`, + )); + }); + + it('records an event', async function() { + sinon.stub(atomEnv.workspace, 'open').resolves(); + sinon.stub(reporterProxy, 'addEvent'); + + const sha = 'asdf1234'; + const commits = [new Commit({sha})]; + app = React.cloneElement(app, {commits, workspace: atomEnv.workspace, repository}); + const wrapper = shallow(app); + + await wrapper.instance().openCommit({sha: 'asdf1234'}); + assert.isTrue(reporterProxy.addEvent.calledWith('open-commit-in-pane', {package: 'github', from: RecentCommitsController.name})); + }); + }); }); From 8b3c56894fe3ed11e55cad0b97559bb2e5139233 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 29 Nov 2018 22:33:00 -0800 Subject: [PATCH 2061/4847] Add tests for OpenCommitDialog --- lib/controllers/root-controller.js | 2 +- test/controllers/root-controller.test.js | 57 ++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index c57c7a9d4f..ab6f9f588f 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -597,7 +597,7 @@ export default class RootController extends React.Component { const uri = CommitDetailItem.buildURI(workdir, sha); this.setState({openCommitDialogActive: false}); this.props.workspace.open(uri).then(() => { - addEvent('open-commit-in-pane', {package: 'github', from: 'dialog'}); + addEvent('open-commit-in-pane', {package: 'github', from: OpenCommitDialog.name}); }); } diff --git a/test/controllers/root-controller.test.js b/test/controllers/root-controller.test.js index 7edebaab67..8c7a4168dc 100644 --- a/test/controllers/root-controller.test.js +++ b/test/controllers/root-controller.test.js @@ -17,9 +17,11 @@ import GitHubTabItem from '../../lib/items/github-tab-item'; import ResolutionProgress from '../../lib/models/conflicts/resolution-progress'; import IssueishDetailItem from '../../lib/items/issueish-detail-item'; import CommitPreviewItem from '../../lib/items/commit-preview-item'; +import CommitDetailItem from '../../lib/items/commit-detail-item'; import * as reporterProxy from '../../lib/reporter-proxy'; import RootController from '../../lib/controllers/root-controller'; +import OpenCommitDialog from '../../lib/views/open-commit-dialog'; describe('RootController', function() { let atomEnv, app; @@ -323,6 +325,61 @@ describe('RootController', function() { }); }); + describe('github:open-commit', function() { + let workdirPath, wrapper, openCommitDetails, resolveOpenCommit; + + beforeEach(async function() { + openCommitDetails = sinon.stub(atomEnv.workspace, 'open').returns(new Promise(resolve => { + resolveOpenCommit = resolve; + })); + + workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + + app = React.cloneElement(app, {repository}); + wrapper = shallow(app); + }); + + it('renders the modal open-commit panel', function() { + wrapper.instance().showOpenCommitDialog(); + wrapper.update(); + + assert.lengthOf(wrapper.find('Panel').find({location: 'modal'}).find('OpenCommitDialog'), 1); + }); + + it('triggers the open callback on accept and fires `open-commit-in-pane` event', async function() { + sinon.stub(reporterProxy, 'addEvent'); + wrapper.instance().showOpenCommitDialog(); + wrapper.update(); + + const dialog = wrapper.find('OpenCommitDialog'); + const sha = 'asdf1234'; + + const promise = dialog.prop('didAccept')({sha}); + resolveOpenCommit(); + await promise; + + const uri = CommitDetailItem.buildURI(workdirPath, sha); + + assert.isTrue(openCommitDetails.calledWith(uri)); + + await assert.isTrue(reporterProxy.addEvent.calledWith('open-commit-in-pane', {package: 'github', from: OpenCommitDialog.name})); + }); + + it('dismisses the open-commit panel on cancel', function() { + wrapper.instance().showOpenCommitDialog(); + wrapper.update(); + + const dialog = wrapper.find('OpenCommitDialog'); + dialog.prop('didCancel')(); + + wrapper.update(); + assert.lengthOf(wrapper.find('OpenCommitDialog'), 0); + assert.isFalse(openCommitDetails.called); + assert.isFalse(wrapper.state('openCommitDialogActive')); + }); + }); + describe('github:clone', function() { let wrapper, cloneRepositoryForProjectPath, resolveClone, rejectClone; From 994525dbd328b5865eb9445243c2c0d907a89826 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 29 Nov 2018 22:42:24 -0800 Subject: [PATCH 2062/4847] Add tests for OpenIssuishDialog --- lib/controllers/root-controller.js | 1 + test/controllers/root-controller.test.js | 58 ++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index ab6f9f588f..282150c71d 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -582,6 +582,7 @@ export default class RootController extends React.Component { acceptOpenIssueish({repoOwner, repoName, issueishNumber}) { const uri = IssueishDetailItem.buildURI('https://api.github.com', repoOwner, repoName, issueishNumber); + console.warn(uri); this.setState({openIssueishDialogActive: false}); this.props.workspace.open(uri).then(() => { addEvent('open-issueish-in-pane', {package: 'github', from: 'dialog'}); diff --git a/test/controllers/root-controller.test.js b/test/controllers/root-controller.test.js index 8c7a4168dc..7769fd4fa5 100644 --- a/test/controllers/root-controller.test.js +++ b/test/controllers/root-controller.test.js @@ -22,6 +22,7 @@ import * as reporterProxy from '../../lib/reporter-proxy'; import RootController from '../../lib/controllers/root-controller'; import OpenCommitDialog from '../../lib/views/open-commit-dialog'; +import OpenIssueishDialog from '../../lib/views/open-issueish-dialog'; describe('RootController', function() { let atomEnv, app; @@ -380,6 +381,63 @@ describe('RootController', function() { }); }); + describe('github:open-issue-or-pull-request', function() { + let workdirPath, wrapper, openIssueishDetails, resolveOpenIssueish; + + beforeEach(async function() { + openIssueishDetails = sinon.stub(atomEnv.workspace, 'open').returns(new Promise(resolve => { + resolveOpenIssueish = resolve; + })); + + workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + + app = React.cloneElement(app, {repository}); + wrapper = shallow(app); + }); + + it('renders the modal open-commit panel', function() { + wrapper.instance().showOpenIssueishDialog(); + wrapper.update(); + + assert.lengthOf(wrapper.find('Panel').find({location: 'modal'}).find('OpenIssueishDialog'), 1); + }); + + it('triggers the open callback on accept and fires `open-commit-in-pane` event', async function() { + sinon.stub(reporterProxy, 'addEvent'); + wrapper.instance().showOpenIssueishDialog(); + wrapper.update(); + + const dialog = wrapper.find('OpenIssueishDialog'); + const repoOwner = 'owner'; + const repoName = 'name'; + const issueishNumber = 1234; + + const promise = dialog.prop('didAccept')({repoOwner, repoName, issueishNumber}); + resolveOpenIssueish(); + await promise; + + const uri = IssueishDetailItem.buildURI('https://api.github.com', repoOwner, repoName, issueishNumber); + + assert.isTrue(openIssueishDetails.calledWith(uri)); + + await assert.isTrue(reporterProxy.addEvent.calledWith('open-issueish-in-pane', {package: 'github', from: 'dialog'})); + }); + + it('dismisses the open-commit panel on cancel', function() { + wrapper.instance().showOpenIssueishDialog(); + wrapper.update(); + + const dialog = wrapper.find('OpenIssueishDialog'); + dialog.prop('didCancel')(); + + wrapper.update(); + assert.lengthOf(wrapper.find('OpenIssueishDialog'), 0); + assert.isFalse(openIssueishDetails.called); + assert.isFalse(wrapper.state('openIssueishDialogActive')); + }); + }); + describe('github:clone', function() { let wrapper, cloneRepositoryForProjectPath, resolveClone, rejectClone; From 664b7a94df8a9615846aafcebefdd39e1235057e Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 29 Nov 2018 22:45:35 -0800 Subject: [PATCH 2063/4847] Open CommitDetailItem from RecentCommitView as pending item --- lib/controllers/recent-commits-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controllers/recent-commits-controller.js b/lib/controllers/recent-commits-controller.js index a257cab1fc..45eeea4764 100644 --- a/lib/controllers/recent-commits-controller.js +++ b/lib/controllers/recent-commits-controller.js @@ -63,7 +63,7 @@ export default class RecentCommitsController extends React.Component { openCommit({sha}) { const workdir = this.props.repository.getWorkingDirectoryPath(); const uri = CommitDetailItem.buildURI(workdir, sha); - this.props.workspace.open(uri).then(() => { + this.props.workspace.open(uri, {pending: true}).then(() => { addEvent('open-commit-in-pane', {package: 'github', from: this.constructor.name}); }); } From 02034767f22d8b0a7a0e9772e168e9ce5c13cc70 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 00:40:50 -0800 Subject: [PATCH 2064/4847] Open CommitDetailItem from PrCommitView --- lib/containers/issueish-detail-container.js | 2 ++ lib/controllers/issueish-detail-controller.js | 15 ++++++++++++++- lib/controllers/root-controller.js | 2 ++ lib/items/issueish-detail-item.js | 3 +++ lib/views/issueish-detail-view.js | 6 +++++- lib/views/pr-commit-view.js | 12 +++++++++++- lib/views/pr-commits-view.js | 2 ++ 7 files changed, 39 insertions(+), 3 deletions(-) diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index b7022358e2..b253eae9aa 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -169,6 +169,8 @@ export default class IssueishDetailContainer extends React.Component { addRemote={repository.addRemote.bind(repository)} onTitleChange={this.props.onTitleChange} switchToIssueish={this.props.switchToIssueish} + workdirPath={repository.getWorkingDirectoryPath()} + workspace={this.props.workspace} /> ); } diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index 2db4fba498..4267f3b46f 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -6,7 +6,8 @@ import {BranchSetPropType, RemoteSetPropType} from '../prop-types'; import {GitError} from '../git-shell-out-strategy'; import EnableableOperation from '../models/enableable-operation'; import IssueishDetailView, {checkoutStates} from '../views/issueish-detail-view'; -import {incrementCounter} from '../reporter-proxy'; +import CommitDetailItem from '../items/commit-detail-item'; +import {incrementCounter, addEvent} from '../reporter-proxy'; export class BareIssueishDetailController extends React.Component { static propTypes = { @@ -16,6 +17,7 @@ export class BareIssueishDetailController extends React.Component { login: PropTypes.string.isRequired, }).isRequired, issueish: PropTypes.any, // FIXME from IssueishPaneItemContainer.propTypes + getWorkingDirectoryPath: PropTypes.func.isRequired, }), issueishNumber: PropTypes.number.isRequired, @@ -33,6 +35,9 @@ export class BareIssueishDetailController extends React.Component { addRemote: PropTypes.func.isRequired, onTitleChange: PropTypes.func.isRequired, switchToIssueish: PropTypes.func.isRequired, + + workspace: PropTypes.object.isRequired, + workdirPath: PropTypes.string.isRequired, } constructor(props) { @@ -85,6 +90,7 @@ export class BareIssueishDetailController extends React.Component { issueish={repository.issueish} checkoutOp={this.checkoutOp} switchToIssueish={this.props.switchToIssueish} + openCommit={this.openCommit} /> ); } @@ -201,6 +207,13 @@ export class BareIssueishDetailController extends React.Component { incrementCounter('checkout-pr'); } + + openCommit = ({sha}) => { + const uri = CommitDetailItem.buildURI(this.props.workdirPath, sha); + this.props.workspace.open(uri, {pending: true}).then(() => { + addEvent('open-commit-in-pane', {package: 'github', from: this.constructor.name}); + }); + } } export default createFragmentContainer(BareIssueishDetailController, { diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 282150c71d..0977f7c5ad 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -415,6 +415,8 @@ export default class RootController extends React.Component { workingDirectory={params.workingDirectory} workdirContextPool={this.props.workdirContextPool} loginModel={this.props.loginModel} + + workspace={this.props.workspace} /> )} diff --git a/lib/items/issueish-detail-item.js b/lib/items/issueish-detail-item.js index 88b8242b71..88c0bd78d3 100644 --- a/lib/items/issueish-detail-item.js +++ b/lib/items/issueish-detail-item.js @@ -18,6 +18,8 @@ export default class IssueishDetailItem extends Component { workingDirectory: PropTypes.string.isRequired, workdirContextPool: WorkdirContextPoolPropType.isRequired, loginModel: GithubLoginModelPropType.isRequired, + + workspace: PropTypes.object.isRequired, } static uriPattern = 'atom-github://issueish/{host}/{owner}/{repo}/{issueishNumber}?workdir={workingDirectory}' @@ -66,6 +68,7 @@ export default class IssueishDetailItem extends Component { issueishNumber={this.state.issueishNumber} repository={this.state.repository} + workspace={this.props.workspace} loginModel={this.props.loginModel} onTitleChange={this.handleTitleChanged} diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index 55d5a148e7..940cabd3be 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -143,6 +143,10 @@ export class BareIssueishDetailView extends React.Component { } renderPullRequestBody(issueish, childProps) { + const {checkoutOp} = this.props; + const reason = checkoutOp.why(); + const onBranch = reason && !reason({hidden: true, default: false}); // is there a more direct way than this? + return ( @@ -184,7 +188,7 @@ export class BareIssueishDetailView extends React.Component { {/* commits */} - + ); diff --git a/lib/views/pr-commit-view.js b/lib/views/pr-commit-view.js index 88d879a3cb..3e6d2a036f 100644 --- a/lib/views/pr-commit-view.js +++ b/lib/views/pr-commit-view.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import {emojify} from 'node-emoji'; import moment from 'moment'; import {graphql, createFragmentContainer} from 'react-relay'; +import cx from 'classnames'; import {autobind} from '../helpers'; @@ -37,6 +38,12 @@ export class PrCommitView extends React.Component { return moment(date).fromNow(); } + openCommitDetailItem = () => { + if (this.props.onBranch) { + return this.props.openCommit({sha: this.props.item.abbreviatedOid}); + } + } + render() { const {messageHeadline, messageBody, abbreviatedOid, url} = this.props.item; const {avatarUrl, name, date} = this.props.item.committer; @@ -44,7 +51,10 @@ export class PrCommitView extends React.Component {

    - {emojify(messageHeadline)} + + {emojify(messageHeadline)} + {messageBody ?

    ); } else if (this.props.repository.hasDirectory() && - !isValidWorkdir(this.props.repository.getWorkingDirectoryPath())) { + !isValidWorkdir(this.props.repository.getWorkingDirectoryPath())) { return (
    @@ -295,7 +293,7 @@ export default class GitTabView extends React.Component { } focusAndSelectRecentCommit() { - this.setFocus(RecentCommitsView.focus.RECENT_COMMIT); + this.setFocus(RecentCommitsController.focus.RECENT_COMMIT); } focusAndSelectCommitPreviewButton() { From 6fd2eb59b71ae8b9e7dd54c0babb4ef41e22c299 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 09:57:17 -0500 Subject: [PATCH 2070/4847] Touch up PropTypes in CommitDetail components --- lib/containers/commit-detail-container.js | 1 + lib/controllers/commit-detail-controller.js | 2 +- lib/views/commit-detail-view.js | 16 +++++++++------- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/containers/commit-detail-container.js b/lib/containers/commit-detail-container.js index 275d82ce35..c624d127f7 100644 --- a/lib/containers/commit-detail-container.js +++ b/lib/containers/commit-detail-container.js @@ -10,6 +10,7 @@ export default class CommitDetailContainer extends React.Component { static propTypes = { repository: PropTypes.object.isRequired, sha: PropTypes.string.isRequired, + itemType: PropTypes.func.isRequired, } fetchData = repository => { diff --git a/lib/controllers/commit-detail-controller.js b/lib/controllers/commit-detail-controller.js index 6e0df0c146..3f6014b9c7 100644 --- a/lib/controllers/commit-detail-controller.js +++ b/lib/controllers/commit-detail-controller.js @@ -5,7 +5,7 @@ import CommitDetailView from '../views/commit-detail-view'; export default class CommitDetailController extends React.Component { static propTypes = { - ...CommitDetailView.propTypes, + ...CommitDetailView.drilledPropTypes, commit: PropTypes.object.isRequired, } diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index 40a5280618..cdd383e616 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -4,13 +4,15 @@ import {emojify} from 'node-emoji'; import moment from 'moment'; import MultiFilePatchController from '../controllers/multi-file-patch-controller'; -import CommitDetailItem from '../items/commit-detail-item'; export default class CommitDetailView extends React.Component { - static propTypes = { + static drilledPropTypes = { repository: PropTypes.object.isRequired, commit: PropTypes.object.isRequired, - itemType: PropTypes.oneOf([CommitDetailItem]).isRequired, + currentRemote: PropTypes.object.isRequired, + currentBranch: PropTypes.object.isRequired, + isCommitPushed: PropTypes.bool.isRequired, + itemType: PropTypes.func.isRequired, workspace: PropTypes.object.isRequired, commands: PropTypes.object.isRequired, @@ -19,14 +21,14 @@ export default class CommitDetailView extends React.Component { config: PropTypes.object.isRequired, destroy: PropTypes.func.isRequired, + } + + static propTypes = { + ...CommitDetailView.drilledPropTypes, messageCollapsible: PropTypes.bool.isRequired, messageOpen: PropTypes.bool.isRequired, toggleMessage: PropTypes.func.isRequired, - - currentRemote: PropTypes.object.isRequired, - currentBranch: PropTypes.object.isRequired, - isCommitPushed: PropTypes.bool.isRequired, } render() { From 5c1389c6c4e27fed55a0feba1f3dac90cbd0a7f2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 10:13:47 -0500 Subject: [PATCH 2071/4847] Forward focus management from RecentCommitsController to its view --- lib/controllers/recent-commits-controller.js | 15 ++++++++++++++- .../controllers/recent-commits-controller.test.js | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/controllers/recent-commits-controller.js b/lib/controllers/recent-commits-controller.js index cd846ca89e..041cfb8ad7 100644 --- a/lib/controllers/recent-commits-controller.js +++ b/lib/controllers/recent-commits-controller.js @@ -1,11 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; import {addEvent} from '../reporter-proxy'; +import {CompositeDisposable} from 'event-kit'; import CommitDetailItem from '../items/commit-detail-item'; import URIPattern from '../atom/uri-pattern'; import RecentCommitsView from '../views/recent-commits-view'; -import {CompositeDisposable} from 'event-kit'; +import RefHolder from '../models/ref-holder'; export default class RecentCommitsController extends React.Component { static propTypes = { @@ -25,6 +26,9 @@ export default class RecentCommitsController extends React.Component { this.subscriptions = new CompositeDisposable( this.props.workspace.onDidChangeActivePaneItem(this.updateSelectedCommit), ); + + this.refView = new RefHolder(); + this.state = {selectedCommitSha: ''}; } @@ -50,6 +54,7 @@ export default class RecentCommitsController extends React.Component { render() { return ( view.rememberFocus(event)).getOr(null); + } + + setFocus(focus) { + return this.refView.map(view => view.setFocus(focus)).getOr(false); + } } diff --git a/test/controllers/recent-commits-controller.test.js b/test/controllers/recent-commits-controller.test.js index d67d1985cb..c566b7865c 100644 --- a/test/controllers/recent-commits-controller.test.js +++ b/test/controllers/recent-commits-controller.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import {shallow} from 'enzyme'; +import {shallow, mount} from 'enzyme'; import RecentCommitsController from '../../lib/controllers/recent-commits-controller'; import {commitBuilder} from '../builder/commit'; @@ -127,4 +127,17 @@ describe('RecentCommitsController', function() { }); }); }); + + it('forwards focus management methods to its view', function() { + const wrapper = mount(app); + + const setFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'setFocus'); + const rememberFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'rememberFocus'); + + wrapper.instance().setFocus(RecentCommitsController.focus.RECENT_COMMIT); + assert.isTrue(setFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT)); + + wrapper.instance().rememberFocus({target: null}); + assert.isTrue(rememberFocusSpy.calledWith({target: null})); + }); }); From 333958b30a2c54d25fbf3286873563e8a4c0024c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 10:14:25 -0500 Subject: [PATCH 2072/4847] Optionally preserve keyboard focus when opening commit details --- lib/controllers/recent-commits-controller.js | 5 ++++- .../recent-commits-controller.test.js | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/controllers/recent-commits-controller.js b/lib/controllers/recent-commits-controller.js index 041cfb8ad7..ac4b6d9743 100644 --- a/lib/controllers/recent-commits-controller.js +++ b/lib/controllers/recent-commits-controller.js @@ -67,10 +67,13 @@ export default class RecentCommitsController extends React.Component { ); } - openCommit = async ({sha}) => { + openCommit = async ({sha, preserveFocus}) => { const workdir = this.props.repository.getWorkingDirectoryPath(); const uri = CommitDetailItem.buildURI(workdir, sha); await this.props.workspace.open(uri, {pending: true}); + if (preserveFocus) { + this.setFocus(this.constructor.focus.RECENT_COMMIT); + } addEvent('open-commit-in-pane', {package: 'github', from: this.constructor.name}); } diff --git a/test/controllers/recent-commits-controller.test.js b/test/controllers/recent-commits-controller.test.js index c566b7865c..3875daf6d2 100644 --- a/test/controllers/recent-commits-controller.test.js +++ b/test/controllers/recent-commits-controller.test.js @@ -44,7 +44,7 @@ describe('RecentCommitsController', function() { assert.isTrue(wrapper.find('RecentCommitsView').prop('isLoading')); }); - describe('openCommit({sha})', function() { + describe('openCommit({sha, preserveFocus})', function() { it('opens a commit detail item', async function() { sinon.stub(atomEnv.workspace, 'open').resolves(); @@ -53,7 +53,7 @@ describe('RecentCommitsController', function() { app = React.cloneElement(app, {commits}); const wrapper = shallow(app); - await wrapper.find('RecentCommitsView').prop('openCommit')({sha: 'asdf1234'}); + await wrapper.find('RecentCommitsView').prop('openCommit')({sha: 'asdf1234', preserveFocus: false}); assert.isTrue(atomEnv.workspace.open.calledWith( `atom-github://commit-detail?workdir=${encodeURIComponent(workdirPath)}` + @@ -61,6 +61,20 @@ describe('RecentCommitsController', function() { )); }); + it('preserves keyboard focus within the RecentCommitsView when requested', async function() { + sinon.stub(atomEnv.workspace, 'open').resolves(); + + const sha = 'asdf1234'; + const commits = [commitBuilder().sha(sha).build()]; + app = React.cloneElement(app, {commits}); + + const wrapper = mount(app); + const focusSpy = sinon.stub(wrapper.find('RecentCommitsView').instance(), 'setFocus').returns(true); + + await wrapper.find('RecentCommitsView').prop('openCommit')({sha: 'asdf1234', preserveFocus: true}); + assert.isTrue(focusSpy.called); + }); + it('records an event', async function() { sinon.stub(atomEnv.workspace, 'open').resolves(); sinon.stub(reporterProxy, 'addEvent'); From d1be87da8a204b34f026b518512ed9ce2dccaf43 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 10:26:41 -0500 Subject: [PATCH 2073/4847] Use the CommitBuilder in RecentCommitView tests --- test/views/recent-commits-view.test.js | 84 +++++++++++++------------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/test/views/recent-commits-view.test.js b/test/views/recent-commits-view.test.js index 99ae103ddf..19a1ca9907 100644 --- a/test/views/recent-commits-view.test.js +++ b/test/views/recent-commits-view.test.js @@ -2,13 +2,30 @@ import React from 'react'; import {shallow, mount} from 'enzyme'; import RecentCommitsView from '../../lib/views/recent-commits-view'; -import Commit from '../../lib/models/commit'; +import {commitBuilder} from '../builder/commit'; describe('RecentCommitsView', function() { - let app; + let atomEnv, app; beforeEach(function() { - app = {}} isLoading={false} />; + atomEnv = global.buildAtomEnvironment(); + + app = ( + { }} + openCommit={() => { }} + selectNextCommit={() => { }} + selectPreviousCommit={() => { }} + /> + ); + }); + + afterEach(function() { + atomEnv.destroy(); }); it('shows a placeholder while commits are empty and loading', function() { @@ -28,11 +45,7 @@ describe('RecentCommitsView', function() { }); it('renders a RecentCommitView for each commit', function() { - const commits = ['1', '2', '3'].map(sha => { - return { - getSha() { return sha; }, - }; - }); + const commits = ['1', '2', '3'].map(sha => commitBuilder().sha(sha).build()); app = React.cloneElement(app, {commits}); const wrapper = shallow(app); @@ -41,20 +54,19 @@ describe('RecentCommitsView', function() { }); it('renders emojis in the commit subject', function() { - const commits = [new Commit({ - sha: '1111111111', - authorEmail: 'pizza@unicorn.com', - authorDate: 0, - messageSubject: ':heart: :shirt: :smile:', - })]; + const commits = [commitBuilder().messageSubject(':heart: :shirt: :smile:').build()]; + app = React.cloneElement(app, {commits}); const wrapper = mount(app); - assert.deepEqual(wrapper.find('.github-RecentCommit-message').text(), '❤️ 👕 😄'); + assert.strictEqual(wrapper.find('.github-RecentCommit-message').text(), '❤️ 👕 😄'); }); it('renders an avatar corresponding to the GitHub user who authored the commit', function() { const commits = ['thr&ee@z.com', 'two@y.com', 'one@x.com'].map((authorEmail, i) => { - return new Commit({sha: '1111111111' + i, authorEmail, authorDate: 0, message: 'x'}); + return commitBuilder() + .sha(`1111111111${i}`) + .authorEmail(authorEmail) + .build(); }); app = React.cloneElement(app, {commits}); @@ -70,13 +82,13 @@ describe('RecentCommitsView', function() { }); it('renders multiple avatars for co-authored commits', function() { - const commits = [new Commit({ - sha: '1111111111', - authorEmail: 'thr&ee@z.com', - authorDate: 0, - message: 'x', - coAuthors: [{name: 'One', email: 'two@y.com'}, {name: 'Two', email: 'one@x.com'}], - })]; + const commits = [ + commitBuilder() + .authorEmail('thr&ee@z.com') + .addCoAuthor('One', 'two@y.com') + .addCoAuthor('Two', 'one@x.com') + .build(), + ]; app = React.cloneElement(app, {commits}); const wrapper = mount(app); @@ -91,12 +103,7 @@ describe('RecentCommitsView', function() { }); it("renders the commit's relative age", function() { - const commit = new Commit({ - sha: '1111111111', - authorEmail: 'me@hooray.party', - authorDate: 1519848555, - message: 'x', - }); + const commit = commitBuilder().authorDate(1519848555).build(); app = React.cloneElement(app, {commits: [commit]}); const wrapper = mount(app); @@ -104,13 +111,7 @@ describe('RecentCommitsView', function() { }); it('renders emoji in the title attribute', function() { - const commit = new Commit({ - sha: '1111111111', - authorEmail: 'me@hooray.horse', - authorDate: 0, - messageSubject: ':heart:', - messageBody: 'and a commit body', - }); + const commit = commitBuilder().messageSubject(':heart:').messageBody('and a commit body').build(); app = React.cloneElement(app, {commits: [commit]}); const wrapper = mount(app); @@ -122,13 +123,10 @@ describe('RecentCommitsView', function() { }); it('renders the full commit message in a title attribute', function() { - const commit = new Commit({ - sha: '1111111111', - authorEmail: 'me@hooray.horse', - authorDate: 0, - messageSubject: 'really really really really really really really long', - messageBody: 'and a commit body', - }); + const commit = commitBuilder() + .messageSubject('really really really really really really really long') + .messageBody('and a commit body') + .build(); app = React.cloneElement(app, {commits: [commit]}); const wrapper = mount(app); From 1cea7a5c1621226ae18643c3f62c1075855b4322 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 10:44:02 -0500 Subject: [PATCH 2074/4847] RecentCommitView keyboard navigation --- lib/views/recent-commits-view.js | 41 +++++++++++++++--------- test/views/recent-commits-view.test.js | 43 ++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/lib/views/recent-commits-view.js b/lib/views/recent-commits-view.js index 9faffd716d..f07f9b21e7 100644 --- a/lib/views/recent-commits-view.js +++ b/lib/views/recent-commits-view.js @@ -92,12 +92,19 @@ class RecentCommitView extends React.Component { export default class RecentCommitsView extends React.Component { static propTypes = { + // Model state commits: PropTypes.arrayOf(PropTypes.object).isRequired, isLoading: PropTypes.bool.isRequired, - undoLastCommit: PropTypes.func.isRequired, - openCommit: PropTypes.func.isRequired, selectedCommitSha: PropTypes.string.isRequired, + + // Atom environment commandRegistry: PropTypes.object.isRequired, + + // Action methods + undoLastCommit: PropTypes.func.isRequired, + openCommit: PropTypes.func.isRequired, + selectNextCommit: PropTypes.func.isRequired, + selectPreviousCommit: PropTypes.func.isRequired, }; static focus = { @@ -106,27 +113,30 @@ export default class RecentCommitsView extends React.Component { constructor(props) { super(props); - this.refRecentCommits = new RefHolder(); + this.refRoot = new RefHolder(); } setFocus(focus) { - return this.refRecentCommits.map(view => view.setFocus(focus)).getOr(false); - } + if (focus === this.constructor.focus.RECENT_COMMIT) { + return this.refRoot.map(element => element.focus()).getOr(false); + } - rememberFocus(event) { - return this.refRecentCommits.map(view => view.rememberFocus(event)).getOr(null); + return false; } - selectNextCommit() { - // okay, we should probably move the state of the selected commit into this component - // instead of using the sha, so we can more easily move to next / previous. + rememberFocus(event) { + return this.refRoot.map(element => element.contains(event.target)).getOr(false) + ? this.constructor.focus.RECENT_COMMIT + : null; } render() { return ( -
    - - +
    + + + + {this.renderCommits()}
    @@ -158,7 +168,7 @@ export default class RecentCommitsView extends React.Component { isMostRecent={i === 0} commit={commit} undoLastCommit={this.props.undoLastCommit} - openCommit={() => this.props.openCommit({sha: commit.getSha()})} + openCommit={() => this.props.openCommit({sha: commit.getSha(), preserveFocus: true})} isSelected={this.props.selectedCommitSha === commit.getSha()} /> ); @@ -166,6 +176,7 @@ export default class RecentCommitsView extends React.Component { ); } - } + + openSelectedCommit = () => this.props.openCommit({sha: this.props.selectedCommitSha, preserveFocus: false}) } diff --git a/test/views/recent-commits-view.test.js b/test/views/recent-commits-view.test.js index 19a1ca9907..81e01ad562 100644 --- a/test/views/recent-commits-view.test.js +++ b/test/views/recent-commits-view.test.js @@ -137,4 +137,47 @@ describe('RecentCommitsView', function() { 'and a commit body', ); }); + + it('opens a commit on click, preserving keyboard focus', function() { + const openCommit = sinon.spy(); + const commits = [ + commitBuilder().sha('0').build(), + commitBuilder().sha('1').build(), + commitBuilder().sha('2').build(), + ]; + const wrapper = mount(React.cloneElement(app, {commits, openCommit, selectedCommitSha: '2'})); + + wrapper.find('RecentCommitView').at(1).simulate('click'); + + assert.isTrue(openCommit.calledWith({sha: '1', preserveFocus: true})); + }); + + describe('keybindings', function() { + it('advances to the next commit on core:move-down', function() { + const selectNextCommit = sinon.spy(); + const wrapper = mount(React.cloneElement(app, {selectNextCommit})); + + atomEnv.commands.dispatch(wrapper.getDOMNode(), 'core:move-down'); + + assert.isTrue(selectNextCommit.called); + }); + + it('retreats to the previous commit on core:move-up', function() { + const selectPreviousCommit = sinon.spy(); + const wrapper = mount(React.cloneElement(app, {selectPreviousCommit})); + + atomEnv.commands.dispatch(wrapper.getDOMNode(), 'core:move-up'); + + assert.isTrue(selectPreviousCommit.called); + }); + + it('opens the currently selected commit and does not preserve focus on core:confirm', function() { + const openCommit = sinon.spy(); + const wrapper = mount(React.cloneElement(app, {openCommit, selectedCommitSha: '1234'})); + + atomEnv.commands.dispatch(wrapper.getDOMNode(), 'core:confirm'); + + assert.isTrue(openCommit.calledWith({sha: '1234', preserveFocus: false})); + }); + }); }); From 3cafdc1968bed5448ef12e20740a9993b68bf954 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 10:44:13 -0500 Subject: [PATCH 2075/4847] Forgot to commit part of this test, whoops --- test/controllers/recent-commits-controller.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/controllers/recent-commits-controller.test.js b/test/controllers/recent-commits-controller.test.js index 3875daf6d2..89b4c13578 100644 --- a/test/controllers/recent-commits-controller.test.js +++ b/test/controllers/recent-commits-controller.test.js @@ -84,7 +84,7 @@ describe('RecentCommitsController', function() { app = React.cloneElement(app, {commits}); const wrapper = shallow(app); - await wrapper.instance().openCommit({sha: 'asdf1234'}); + await wrapper.instance().openCommit({sha: 'asdf1234', preserveFocus: true}); assert.isTrue(reporterProxy.addEvent.calledWith('open-commit-in-pane', { package: 'github', from: RecentCommitsController.name, From c90e2a56d10375d54f86fee1413078ddc7c4d6eb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 10:54:31 -0500 Subject: [PATCH 2076/4847] Scroll commits into view as you select them --- lib/views/recent-commits-view.js | 19 +++++++++++++++++++ test/views/recent-commits-view.test.js | 12 ++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/views/recent-commits-view.js b/lib/views/recent-commits-view.js index f07f9b21e7..99d84a7f0b 100644 --- a/lib/views/recent-commits-view.js +++ b/lib/views/recent-commits-view.js @@ -18,12 +18,31 @@ class RecentCommitView extends React.Component { isSelected: PropTypes.bool.isRequired, }; + constructor(props) { + super(props); + + this.refRoot = new RefHolder(); + } + + componentDidMount() { + if (this.props.isSelected) { + this.refRoot.map(root => root.scrollIntoViewIfNeeded(false)); + } + } + + componentDidUpdate(prevProps) { + if (this.props.isSelected && !prevProps.isSelected) { + this.refRoot.map(root => root.scrollIntoViewIfNeeded(false)); + } + } + render() { const authorMoment = moment(this.props.commit.getAuthorDate() * 1000); const fullMessage = this.props.commit.getFullMessage(); return (
  • w.prop('commit')), commits); }); + it('scrolls the selected RecentCommitView into visibility', function() { + const commits = ['0', '1', '2', '3'].map(sha => commitBuilder().sha(sha).build()); + + app = React.cloneElement(app, {commits, selectedCommitSha: '1'}); + const wrapper = mount(app); + const scrollSpy = sinon.spy(wrapper.find('RecentCommitView').at(3).getDOMNode(), 'scrollIntoViewIfNeeded'); + + wrapper.setProps({selectedCommitSha: '3'}); + + assert.isTrue(scrollSpy.calledWith(false)); + }); + it('renders emojis in the commit subject', function() { const commits = [commitBuilder().messageSubject(':heart: :shirt: :smile:').build()]; From a37a3c861bd27cb4bb238c587f64090952577f6f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 10:56:37 -0500 Subject: [PATCH 2077/4847] Keymap entries for diving and surfacing from commits --- keymaps/git.cson | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/keymaps/git.cson b/keymaps/git.cson index f6236b9a07..16f31c82d6 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -32,11 +32,6 @@ 'tab': 'core:focus-next' 'shift-tab': 'core:focus-previous' -'.github-RecentCommitsView': - 'up': 'github:recent-commit-up' - 'down': 'github:recent-commit-down' - 'enter': 'github:open-recent-commit' - '.github-StagingView.unstaged-changes-focused': 'cmd-backspace': 'github:discard-changes-in-selected-files' 'ctrl-backspace': 'github:discard-changes-in-selected-files' @@ -51,6 +46,15 @@ 'ctrl-left': 'github:dive' 'enter': 'native!' +'.github-RecentCommits': + 'enter': 'github:dive' + 'cmd-left': 'github:dive' + 'ctrl-left': 'github:dive' + +'.github-CommitDetailView': + 'cmd-right': 'github:surface' + 'ctrl-right': 'github:surface' + '.github-FilePatchView atom-text-editor:not([mini])': 'cmd-/': 'github:toggle-patch-selection-mode' 'ctrl-/': 'github:toggle-patch-selection-mode' From 643c7fda79061ffd33abe80eddacb83043dd849d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 11:00:40 -0500 Subject: [PATCH 2078/4847] Use github:dive instead of core:confirm for consistency --- lib/views/recent-commits-view.js | 2 +- test/views/recent-commits-view.test.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/views/recent-commits-view.js b/lib/views/recent-commits-view.js index 99d84a7f0b..dfd60105fc 100644 --- a/lib/views/recent-commits-view.js +++ b/lib/views/recent-commits-view.js @@ -155,7 +155,7 @@ export default class RecentCommitsView extends React.Component { - + {this.renderCommits()}
  • diff --git a/test/views/recent-commits-view.test.js b/test/views/recent-commits-view.test.js index 540ef46b3c..31c6625703 100644 --- a/test/views/recent-commits-view.test.js +++ b/test/views/recent-commits-view.test.js @@ -183,11 +183,11 @@ describe('RecentCommitsView', function() { assert.isTrue(selectPreviousCommit.called); }); - it('opens the currently selected commit and does not preserve focus on core:confirm', function() { + it('opens the currently selected commit and does not preserve focus on github:dive', function() { const openCommit = sinon.spy(); const wrapper = mount(React.cloneElement(app, {openCommit, selectedCommitSha: '1234'})); - atomEnv.commands.dispatch(wrapper.getDOMNode(), 'core:confirm'); + atomEnv.commands.dispatch(wrapper.getDOMNode(), 'github:dive'); assert.isTrue(openCommit.calledWith({sha: '1234', preserveFocus: false})); }); From 4852d709ce42708eea9033fa94f53feee15ddc25 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 11:46:30 -0500 Subject: [PATCH 2079/4847] Focus and select the current recent commit --- lib/controllers/git-tab-controller.js | 4 +++ lib/controllers/root-controller.js | 8 +++++- lib/items/git-tab-item.js | 4 +++ lib/views/commit-detail-view.js | 27 ++++++++++++++++++- test/controllers/git-tab-controller.test.js | 9 +++++++ test/controllers/root-controller.test.js | 22 ++++++++++++++++ test/items/git-tab-item.test.js | 1 + test/views/commit-detail-view.test.js | 29 ++++++++++++++++++--- 8 files changed, 98 insertions(+), 6 deletions(-) diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index f3322f4c79..c1d732df4f 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -363,6 +363,10 @@ export default class GitTabController extends React.Component { return this.refView.map(view => view.focusAndSelectCommitPreviewButton()); } + focusAndSelectRecentCommit() { + return this.refView.map(view => view.focusAndSelectRecentCommit()); + } + quietlySelectItem(filePath, stagingStatus) { return this.refView.map(view => view.quietlySelectItem(filePath, stagingStatus)).getOr(null); } diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 2b5bc84e0c..350c25d76f 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -100,7 +100,7 @@ export default class RootController extends React.Component { this.props.commandRegistry.onDidDispatch(event => { if (event.type && event.type.startsWith('github:') - && event.detail && event.detail[0] && event.detail[0].contextCommand) { + && event.detail && event.detail[0] && event.detail[0].contextCommand) { addEvent('context-menu-action', { package: 'github', command: event.type, @@ -399,6 +399,7 @@ export default class RootController extends React.Component { config={this.props.config} sha={params.sha} + surfaceCommit={this.surfaceToRecentCommit} /> )} @@ -617,6 +618,11 @@ export default class RootController extends React.Component { return gitTab && gitTab.focusAndSelectCommitPreviewButton(); } + surfaceToRecentCommit = () => { + const gitTab = this.gitTabTracker.getComponent(); + return gitTab && gitTab.focusAndSelectRecentCommit(); + } + destroyFilePatchPaneItems() { destroyFilePatchPaneItems({onlyStaged: false}, this.props.workspace); } diff --git a/lib/items/git-tab-item.js b/lib/items/git-tab-item.js index 254c9d717a..e8de6d7cca 100644 --- a/lib/items/git-tab-item.js +++ b/lib/items/git-tab-item.js @@ -90,4 +90,8 @@ export default class GitTabItem extends React.Component { quietlySelectItem(...args) { return this.refController.map(c => c.quietlySelectItem(...args)); } + + focusAndSelectRecentCommit() { + return this.refController.map(c => c.focusAndSelectRecentCommit()); + } } diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index cdd383e616..af819f9442 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -4,9 +4,12 @@ import {emojify} from 'node-emoji'; import moment from 'moment'; import MultiFilePatchController from '../controllers/multi-file-patch-controller'; +import Commands, {Command} from '../atom/commands'; +import RefHolder from '../models/ref-holder'; export default class CommitDetailView extends React.Component { static drilledPropTypes = { + // Model properties repository: PropTypes.object.isRequired, commit: PropTypes.object.isRequired, currentRemote: PropTypes.object.isRequired, @@ -14,28 +17,41 @@ export default class CommitDetailView extends React.Component { isCommitPushed: PropTypes.bool.isRequired, itemType: PropTypes.func.isRequired, + // Atom environment workspace: PropTypes.object.isRequired, commands: PropTypes.object.isRequired, keymaps: PropTypes.object.isRequired, tooltips: PropTypes.object.isRequired, config: PropTypes.object.isRequired, + // Action functions destroy: PropTypes.func.isRequired, + surfaceCommit: PropTypes.func.isRequired, } static propTypes = { ...CommitDetailView.drilledPropTypes, + // Controller state messageCollapsible: PropTypes.bool.isRequired, messageOpen: PropTypes.bool.isRequired, + + // Action functions toggleMessage: PropTypes.func.isRequired, } + constructor(props) { + super(props); + + this.refRoot = new RefHolder(); + } + render() { const commit = this.props.commit; return ( -
    +
    + {this.renderCommands()}

    @@ -58,12 +74,21 @@ export default class CommitDetailView extends React.Component {

    ); } + renderCommands() { + return ( + + + + ); + } + renderCommitMessageBody() { const collapsed = this.props.messageCollapsible && !this.props.messageOpen; diff --git a/test/controllers/git-tab-controller.test.js b/test/controllers/git-tab-controller.test.js index facd99b14b..68791712fb 100644 --- a/test/controllers/git-tab-controller.test.js +++ b/test/controllers/git-tab-controller.test.js @@ -221,6 +221,15 @@ describe('GitTabController', function() { assert.isTrue(focusMethod.called); }); + it('imperatively selects the recent commit', async function() { + const repository = await buildRepository(await cloneRepository('three-files')); + const wrapper = mount(await buildApp(repository)); + + const focusMethod = sinon.spy(wrapper.find('GitTabView').instance(), 'focusAndSelectRecentCommit'); + wrapper.instance().focusAndSelectRecentCommit(); + assert.isTrue(focusMethod.called); + }); + describe('focus management', function() { it('remembers the last focus reported by the view', async function() { const repository = await buildRepository(await cloneRepository()); diff --git a/test/controllers/root-controller.test.js b/test/controllers/root-controller.test.js index e5203adadc..6796317781 100644 --- a/test/controllers/root-controller.test.js +++ b/test/controllers/root-controller.test.js @@ -1314,4 +1314,26 @@ describe('RootController', function() { }); }); + describe('surfaceToRecentCommit', function() { + it('focuses and selects the recent commit', async function() { + const repository = await buildRepository(await cloneRepository('multiple-commits')); + app = React.cloneElement(app, { + repository, + startOpen: true, + startRevealed: true, + }); + const wrapper = mount(app); + + const gitTabTracker = wrapper.instance().gitTabTracker; + + const gitTab = { + focusAndSelectRecentCommit: sinon.spy(), + }; + sinon.stub(gitTabTracker, 'getComponent').returns(gitTab); + + wrapper.instance().surfaceToRecentCommit(); + assert.isTrue(gitTab.focusAndSelectRecentCommit.called); + }); + }); + }); diff --git a/test/items/git-tab-item.test.js b/test/items/git-tab-item.test.js index 09be4becd0..4bd740b459 100644 --- a/test/items/git-tab-item.test.js +++ b/test/items/git-tab-item.test.js @@ -61,6 +61,7 @@ describe('GitTabItem', function() { const focusMethods = [ 'focusAndSelectStagingItem', 'focusAndSelectCommitPreviewButton', + 'focusAndSelectRecentCommit', ]; const spies = focusMethods.reduce((map, focusMethod) => { diff --git a/test/views/commit-detail-view.test.js b/test/views/commit-detail-view.test.js index e56c35a042..ce64003698 100644 --- a/test/views/commit-detail-view.test.js +++ b/test/views/commit-detail-view.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import {shallow} from 'enzyme'; +import {shallow, mount} from 'enzyme'; import moment from 'moment'; import dedent from 'dedent-js'; @@ -24,7 +24,7 @@ describe('CommitDetailView', function() { function buildApp(override = {}) { const props = { repository, - commit: commitBuilder().build(), + commit: commitBuilder().setMultiFileDiff().build(), messageCollapsible: false, messageOpen: true, itemType: CommitDetailItem, @@ -35,8 +35,9 @@ describe('CommitDetailView', function() { tooltips: atomEnv.tooltips, config: atomEnv.config, - destroy: () => {}, - toggleMessage: () => {}, + destroy: () => { }, + toggleMessage: () => { }, + surfaceCommit: () => { }, ...override, }; @@ -206,4 +207,24 @@ describe('CommitDetailView', function() { }); }); }); + + describe('keyboard bindings', function() { + it('surfaces the recent commit on github:surface', function() { + const surfaceCommit = sinon.spy(); + const wrapper = mount(buildApp({surfaceCommit})); + + atomEnv.commands.dispatch(wrapper.getDOMNode(), 'github:surface'); + + assert.isTrue(surfaceCommit.called); + }); + + it('surfaces from the embedded MultiFilePatchView', function() { + const surfaceCommit = sinon.spy(); + const wrapper = mount(buildApp({surfaceCommit})); + + atomEnv.commands.dispatch(wrapper.find('.github-FilePatchView').getDOMNode(), 'github:surface'); + + assert.isTrue(surfaceCommit.called); + }); + }); }); From 2a2b9b0f83dcc98bb9fe608855733e23c6a66cde Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 11:46:45 -0500 Subject: [PATCH 2080/4847] Set and remember focus on the RecentCommitView --- lib/views/git-tab-view.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/views/git-tab-view.js b/lib/views/git-tab-view.js index a2da551840..1330e299c0 100644 --- a/lib/views/git-tab-view.js +++ b/lib/views/git-tab-view.js @@ -70,6 +70,7 @@ export default class GitTabView extends React.Component { this.subscriptions = new CompositeDisposable(); this.refCommitController = new RefHolder(); + this.refRecentCommitsController = new RefHolder(); } componentDidMount() { @@ -193,6 +194,7 @@ export default class GitTabView extends React.Component { updateSelectedCoAuthors={this.props.updateSelectedCoAuthors} /> controller.rememberFocus(event)).getOr(null); } + if (!currentFocus) { + currentFocus = this.refRecentCommitsController.map(controller => controller.rememberFocus(event)).getOr(null); + } + return currentFocus; } @@ -243,6 +249,10 @@ export default class GitTabView extends React.Component { return true; } + if (this.refRecentCommitsController.map(controller => controller.setFocus(focus)).getOr(false)) { + return true; + } + return false; } From 74ef8a8eb6a6f617364d77333a915a97f9500b9f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 11:48:48 -0500 Subject: [PATCH 2081/4847] Focus refInitialFocus even if it isn't available right away --- lib/items/commit-detail-item.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/items/commit-detail-item.js b/lib/items/commit-detail-item.js index fdfc39e638..a7331b3cde 100644 --- a/lib/items/commit-detail-item.js +++ b/lib/items/commit-detail-item.js @@ -89,6 +89,6 @@ export default class CommitDetailItem extends React.Component { } focus() { - this.refInitialFocus.map(focusable => focusable.focus()); + this.refInitialFocus.getPromise().then(focusable => focusable.focus()); } } From 3e65b6e9ed0b6e0f54e24d70fb6ba8de4ef537a8 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 30 Nov 2018 18:43:27 +0100 Subject: [PATCH 2082/4847] slight styling for title of commit in PR to look clickable --- styles/pr-commit-view.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/styles/pr-commit-view.less b/styles/pr-commit-view.less index 8a6d4e49bb..0863199eec 100644 --- a/styles/pr-commit-view.less +++ b/styles/pr-commit-view.less @@ -42,6 +42,10 @@ margin: 0 0 .25em 0; font-size: 1.2em; line-height: 1.4; + &:hover { + cursor: pointer; + text-decoration: underline; + } } &-avatar { From 51bd40d4fd6b42efde81462c645183570b1dc7d8 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 30 Nov 2018 20:09:38 +0100 Subject: [PATCH 2083/4847] add oid field to pr commit query & rename abbreviatedOid to shortSha for clarity --- .../issueishDetailContainerQuery.graphql.js | 16 ++++++++++++---- .../issueishDetailViewRefetchQuery.graphql.js | 16 ++++++++++++---- .../__generated__/prCommitView_item.graphql.js | 14 +++++++++++--- .../__generated__/prCommitsViewQuery.graphql.js | 16 ++++++++++++---- lib/views/pr-commit-view.js | 14 ++++++++------ 5 files changed, 55 insertions(+), 21 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 73d262cf8c..8e537f3d56 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash fe501fb51956752e2d45ff061c36622e + * @relayHash d760438e6f0650bc4ba45ae430d56116 */ /* eslint-disable */ @@ -476,7 +476,8 @@ fragment prCommitView_item on Commit { } messageHeadline messageBody - abbreviatedOid + shortSha: abbreviatedOid + sha: oid url } */ @@ -997,7 +998,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_1mXVvq\n id\n }\n}\n\nfragment issueishDetailController_repository_1mXVvq on Repository {\n ...issueishDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishDetailView_issueish_4cAEh0\n }\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...issueishDetailView_issueish_4cAEh0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_4cAEh0 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n abbreviatedOid\n url\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_1mXVvq\n id\n }\n}\n\nfragment issueishDetailController_repository_1mXVvq on Repository {\n ...issueishDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueishDetailView_issueish_4cAEh0\n }\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...issueishDetailView_issueish_4cAEh0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_4cAEh0 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1169,11 +1170,18 @@ return { }, { "kind": "ScalarField", - "alias": null, + "alias": "shortSha", "name": "abbreviatedOid", "args": null, "storageKey": null }, + { + "kind": "ScalarField", + "alias": "sha", + "name": "oid", + "args": null, + "storageKey": null + }, v12 ] }, diff --git a/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js index 3b5eeaf1e0..d300687d26 100644 --- a/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/issueishDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 2918a11cbaa8f9b4f358a3913dab315c + * @relayHash 7a789201c89c0ffa32e9490d1bf7c181 */ /* eslint-disable */ @@ -446,7 +446,8 @@ fragment prCommitView_item on Commit { } messageHeadline messageBody - abbreviatedOid + shortSha: abbreviatedOid + sha: oid url } */ @@ -947,7 +948,7 @@ return { "operationKind": "query", "name": "issueishDetailViewRefetchQuery", "id": null, - "text": "query issueishDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishDetailView_repository_3D8CP9\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishDetailView_issueish_4cAEh0\n id\n }\n}\n\nfragment issueishDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_4cAEh0 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n abbreviatedOid\n url\n}\n", + "text": "query issueishDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueishDetailView_repository_3D8CP9\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueishDetailView_issueish_4cAEh0\n id\n }\n}\n\nfragment issueishDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueishDetailView_issueish_4cAEh0 on IssueOrPullRequest {\n __typename\n ... on Node {\n id\n }\n ... on Issue {\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n }\n ... on PullRequest {\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1155,11 +1156,18 @@ return { }, { "kind": "ScalarField", - "alias": null, + "alias": "shortSha", "name": "abbreviatedOid", "args": null, "storageKey": null }, + { + "kind": "ScalarField", + "alias": "sha", + "name": "oid", + "args": null, + "storageKey": null + }, v11 ] }, diff --git a/lib/views/__generated__/prCommitView_item.graphql.js b/lib/views/__generated__/prCommitView_item.graphql.js index c5d7709a26..2d1203207c 100644 --- a/lib/views/__generated__/prCommitView_item.graphql.js +++ b/lib/views/__generated__/prCommitView_item.graphql.js @@ -18,7 +18,8 @@ export type prCommitView_item = {| |}, +messageHeadline: string, +messageBody: string, - +abbreviatedOid: string, + +shortSha: string, + +sha: any, +url: any, +$refType: prCommitView_item$ref, |}; @@ -80,11 +81,18 @@ const node/*: ConcreteFragment*/ = { }, { "kind": "ScalarField", - "alias": null, + "alias": "shortSha", "name": "abbreviatedOid", "args": null, "storageKey": null }, + { + "kind": "ScalarField", + "alias": "sha", + "name": "oid", + "args": null, + "storageKey": null + }, { "kind": "ScalarField", "alias": null, @@ -95,5 +103,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = 'c7c00b19a2fd2a18e4c1bab7f5f252ff'; +(node/*: any*/).hash = '2bd193bec5d758f465d9428ff3cd8a09'; module.exports = node; diff --git a/lib/views/__generated__/prCommitsViewQuery.graphql.js b/lib/views/__generated__/prCommitsViewQuery.graphql.js index f3c5e4ff13..7d20b34ac5 100644 --- a/lib/views/__generated__/prCommitsViewQuery.graphql.js +++ b/lib/views/__generated__/prCommitsViewQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 9ee1d26899a0ab5d2eeeee7dbd86fb3d + * @relayHash 86632ba0fe5f43bd343d798b397ad81b */ /* eslint-disable */ @@ -73,7 +73,8 @@ fragment prCommitView_item on Commit { } messageHeadline messageBody - abbreviatedOid + shortSha: abbreviatedOid + sha: oid url } */ @@ -147,7 +148,7 @@ return { "operationKind": "query", "name": "prCommitsViewQuery", "id": null, - "text": "query prCommitsViewQuery(\n $commitCount: Int!\n $commitCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prCommitsView_pullRequest_38TpXw\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n abbreviatedOid\n url\n}\n", + "text": "query prCommitsViewQuery(\n $commitCount: Int!\n $commitCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prCommitsView_pullRequest_38TpXw\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -331,11 +332,18 @@ return { }, { "kind": "ScalarField", - "alias": null, + "alias": "shortSha", "name": "abbreviatedOid", "args": null, "storageKey": null }, + { + "kind": "ScalarField", + "alias": "sha", + "name": "oid", + "args": null, + "storageKey": null + }, v4 ] }, diff --git a/lib/views/pr-commit-view.js b/lib/views/pr-commit-view.js index 3f2b3157bf..ed7d865fc6 100644 --- a/lib/views/pr-commit-view.js +++ b/lib/views/pr-commit-view.js @@ -19,7 +19,8 @@ export class PrCommitView extends React.Component { }).isRequired, messageBody: PropTypes.string, messageHeadline: PropTypes.string.isRequired, - abbreviatedOid: PropTypes.string.isRequired, + shortSha: PropTypes.string.isRequired, + sha: PropTypes.string.isRequired, url: PropTypes.string.isRequired, }).isRequired, onBranch: PropTypes.bool.isRequired, @@ -41,11 +42,11 @@ export class PrCommitView extends React.Component { } openCommitDetailItem = () => { - return this.props.onBranch ? this.props.openCommit({sha: this.props.item.abbreviatedOid}) : null; + return this.props.onBranch ? this.props.openCommit({sha: this.props.item.shortSha}) : null; } render() { - const {messageHeadline, messageBody, abbreviatedOid, url} = this.props.item; + const {messageHeadline, messageBody, shortSha, url} = this.props.item; const {avatarUrl, name, date} = this.props.item.committer; return (
    @@ -77,8 +78,8 @@ export class PrCommitView extends React.Component {
    @@ -96,7 +97,8 @@ export default createFragmentContainer(PrCommitView, { } messageHeadline messageBody - abbreviatedOid + shortSha: abbreviatedOid + sha: oid url }`, }); From 0bed1f6c77b2fb1a4b6b4093e2d8140457aa4b26 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 30 Nov 2018 20:12:04 +0100 Subject: [PATCH 2084/4847] fix test --- test/views/pr-commits-view.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/views/pr-commits-view.test.js b/test/views/pr-commits-view.test.js index 0d6e226d6c..5b0cbf705e 100644 --- a/test/views/pr-commits-view.test.js +++ b/test/views/pr-commits-view.test.js @@ -11,7 +11,8 @@ const commitSpec = { date: '2018-05-16T21:54:24.500Z', }, messageHeadline: 'This one weird trick for getting to the moon will blow your mind 🚀', - abbreviatedOid: 'bad1dea', + shortSha: 'bad1dea', + sha: 'bad1deaea3d816383721478fc631b5edd0c2b370', url: 'https://github.com/atom/github/pull/1684/commits/bad1deaea3d816383721478fc631b5edd0c2b370', }; From 7b8e564fdd763dca103548297badde0bebf3ae58 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 30 Nov 2018 20:12:17 +0100 Subject: [PATCH 2085/4847] use the long sha for opening commit item --- lib/views/pr-commit-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/pr-commit-view.js b/lib/views/pr-commit-view.js index ed7d865fc6..e1fa730279 100644 --- a/lib/views/pr-commit-view.js +++ b/lib/views/pr-commit-view.js @@ -42,7 +42,7 @@ export class PrCommitView extends React.Component { } openCommitDetailItem = () => { - return this.props.onBranch ? this.props.openCommit({sha: this.props.item.shortSha}) : null; + return this.props.onBranch ? this.props.openCommit({sha: this.props.item.sha}) : null; } render() { From d868567c4326071af6d0431e2cc528b7b9f25852 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 30 Nov 2018 20:42:03 +0100 Subject: [PATCH 2086/4847] clickable styling should only apply to clickable nodes! DUH! --- styles/pr-commit-view.less | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/styles/pr-commit-view.less b/styles/pr-commit-view.less index 0863199eec..5847837599 100644 --- a/styles/pr-commit-view.less +++ b/styles/pr-commit-view.less @@ -42,10 +42,11 @@ margin: 0 0 .25em 0; font-size: 1.2em; line-height: 1.4; - &:hover { - cursor: pointer; - text-decoration: underline; - } + } + + &-messageHeadline.clickable:hover { + cursor: pointer; + text-decoration: underline; } &-avatar { From 4cf2d295c0c508c259d73772795abafe09a8981e Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 30 Nov 2018 20:52:01 +0100 Subject: [PATCH 2087/4847] add tests for opening commits from PR view --- test/views/pr-commit-view.test.js | 34 ++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/test/views/pr-commit-view.test.js b/test/views/pr-commit-view.test.js index db9c453c95..c98e88b4e5 100644 --- a/test/views/pr-commit-view.test.js +++ b/test/views/pr-commit-view.test.js @@ -11,21 +11,25 @@ const defaultProps = { date: '2018-05-16T21:54:24.500Z', }, messageHeadline: 'This one weird trick for getting to the moon will blow your mind 🚀', - abbreviatedOid: 'bad1dea', + shortSha: 'bad1dea', + sha: 'bad1deaea3d816383721478fc631b5edd0c2b370', url: 'https://github.com/atom/github/pull/1684/commits/bad1deaea3d816383721478fc631b5edd0c2b370', }; -const getProps = function(overrides = {}) { +const getProps = function(itemOverrides = {}, overrides = {}) { return { item: { ...defaultProps, - ...overrides, + ...itemOverrides, }, + onBranch: true, + openCommit: () => {}, + ...overrides, }; }; describe('PrCommitView', function() { - function buildApp(overrideProps = {}) { - return ; + function buildApp(itemOverrides = {}, overrides = {}) { + return ; } it('renders the commit view for commits without message body', function() { const wrapper = shallow(buildApp({})); @@ -70,4 +74,24 @@ describe('PrCommitView', function() { assert.lengthOf(wrapper.find('.github-PrCommitView-moreText'), 0); assert.deepEqual(wrapper.find('.github-PrCommitView-moreButton').text(), 'show more...'); }); + + describe('if PR is checked out', function() { + it('shows message headlines as clickable', function() { + const wrapper = shallow(buildApp({})); + assert.isTrue(wrapper.find('.github-PrCommitView-messageHeadline').at(0).hasClass('clickable')); + }); + + it('opens a commit with the full sha when title is clicked', function() { + const openCommit = sinon.spy(); + const wrapper = shallow(buildApp({sha: 'longsha123'}, {openCommit})); + wrapper.find('.github-PrCommitView-messageHeadline').at(0).simulate('click'); + assert.isTrue(openCommit.calledWith({sha: 'longsha123'})); + }); + }); + + it('does not show message headlines as clickable if PR is not checked out', function() { + const wrapper = shallow(buildApp({}, {onBranch: false})); + assert.isFalse(wrapper.find('.github-PrCommitView-messageHeadline').at(0).hasClass('clickable')); + }); + }); From b720c7da8374d70ff239256d1b6877bb9e129594 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Nov 2018 15:39:32 -0500 Subject: [PATCH 2088/4847] Incremental improvement to GitTab focus I've done a pass through the GitTab components and improved the focus management code somewhat. It's still ref soup, imperative, and pretty verbose, but at least now it's a bit more internally consistent. GitTab components that may receive focus implement four methods: * `getFocus(element)` returns the logical focus symbol corresponding to a DOM element, or null if the element is unrecognized. * `setFocus(symbol)` brings focus to the DOM element corresponding to a logical focus symbol. It returns true if an element was found and focused successfully and false otherwise. * `advanceFocusFrom(lastFocus)` returns a Promise that resolves to the logical focus symbol after a given symbol. * `retreatFocusFrom(lastFocus)` returns a Promise that resolves to the logical focus symbol before a given symbol. --- keymaps/git.cson | 1 + lib/controllers/commit-controller.js | 18 +- lib/controllers/git-tab-controller.js | 2 +- lib/controllers/recent-commits-controller.js | 12 +- lib/views/commit-view.js | 84 +++---- lib/views/git-tab-view.js | 80 +++---- lib/views/recent-commits-view.js | 25 +- lib/views/staging-view.js | 45 +++- test/controllers/commit-controller.test.js | 27 +-- .../recent-commits-controller.test.js | 16 +- test/views/commit-view.test.js | 215 ++++++++---------- test/views/git-tab-view.test.js | 99 +++++--- test/views/recent-commits-view.test.js | 28 +++ test/views/staging-view.test.js | 130 +++++++---- 14 files changed, 441 insertions(+), 341 deletions(-) diff --git a/keymaps/git.cson b/keymaps/git.cson index 16f31c82d6..d7b6d2c1d8 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -39,6 +39,7 @@ '.github-CommitView-editor atom-text-editor:not([mini])': 'cmd-enter': 'github:commit' 'ctrl-enter': 'github:commit' + 'tab': 'core:focus-next' 'shift-tab': 'core:focus-previous' '.github-CommitView-commitPreview': diff --git a/lib/controllers/commit-controller.js b/lib/controllers/commit-controller.js index b07be5d280..7183eeb31a 100644 --- a/lib/controllers/commit-controller.js +++ b/lib/controllers/commit-controller.js @@ -76,7 +76,7 @@ export default class CommitController extends React.Component { }), this.props.workspace.onDidDestroyPaneItem(async ({item}) => { if (this.props.repository.isPresent() && item.getPath && item.getPath() === this.getCommitMessagePath() && - this.getCommitMessageEditors().length === 0) { + this.getCommitMessageEditors().length === 0) { // we closed the last editor pointing to the commit message file try { this.commitMessageBuffer.setText(await fs.readFile(this.getCommitMessagePath(), {encoding: 'utf8'})); @@ -252,24 +252,20 @@ export default class CommitController extends React.Component { this.grammarSubscription.dispose(); } - rememberFocus(event) { - return this.refCommitView.map(view => view.rememberFocus(event)).getOr(null); + getFocus(element) { + return this.refCommitView.map(view => view.getFocus(element)).getOr(null); } setFocus(focus) { return this.refCommitView.map(view => view.setFocus(focus)).getOr(false); } - advanceFocus(...args) { - return this.refCommitView.map(view => view.advanceFocus(...args)).getOr(false); + advanceFocusFrom(...args) { + return this.refCommitView.map(view => view.advanceFocusFrom(...args)).getOr(false); } - retreatFocus(...args) { - return this.refCommitView.map(view => view.retreatFocus(...args)).getOr(false); - } - - hasFocusAtBeginning() { - return this.refCommitView.map(view => view.hasFocusAtBeginning()).getOr(false); + retreatFocusFrom(...args) { + return this.refCommitView.map(view => view.retreatFocusFrom(...args)).getOr(false); } toggleCommitPreview() { diff --git a/lib/controllers/git-tab-controller.js b/lib/controllers/git-tab-controller.js index c1d732df4f..f70da000dc 100644 --- a/lib/controllers/git-tab-controller.js +++ b/lib/controllers/git-tab-controller.js @@ -338,7 +338,7 @@ export default class GitTabController extends React.Component { } rememberLastFocus(event) { - this.lastFocus = this.refView.map(view => view.rememberFocus(event)).getOr(null) || GitTabView.focus.STAGING; + this.lastFocus = this.refView.map(view => view.getFocus(event.target)).getOr(null) || GitTabView.focus.STAGING; } restoreFocus() { diff --git a/lib/controllers/recent-commits-controller.js b/lib/controllers/recent-commits-controller.js index ac4b6d9743..2967983062 100644 --- a/lib/controllers/recent-commits-controller.js +++ b/lib/controllers/recent-commits-controller.js @@ -94,11 +94,19 @@ export default class RecentCommitsController extends React.Component { } } - rememberFocus(event) { - return this.refView.map(view => view.rememberFocus(event)).getOr(null); + getFocus(element) { + return this.refView.map(view => view.getFocus(element)).getOr(null); } setFocus(focus) { return this.refView.map(view => view.setFocus(focus)).getOr(false); } + + advanceFocusFrom(focus) { + return this.refView.map(view => view.advanceFocusFrom(focus)).getOr(Promise.resolve(false)); + } + + retreatFocusFrom(focus) { + return this.refView.map(view => view.retreatFocusFrom(focus)).getOr(Promise.resolve(false)); + } } diff --git a/lib/views/commit-view.js b/lib/views/commit-view.js index 6013162cfa..fc35d53704 100644 --- a/lib/views/commit-view.js +++ b/lib/views/commit-view.js @@ -7,6 +7,8 @@ import Select from 'react-select'; import Tooltip from '../atom/tooltip'; import AtomTextEditor from '../atom/atom-text-editor'; import CoAuthorForm from './co-author-form'; +import RecentCommitsView from './recent-commits-view'; +import StagingView from './staging-view'; import Commands, {Command} from '../atom/commands'; import RefHolder from '../models/ref-holder'; import Author from '../models/author'; @@ -30,6 +32,10 @@ export default class CommitView extends React.Component { COMMIT_BUTTON: Symbol('commit-button'), }; + static firstFocus = CommitView.focus.COMMIT_PREVIEW_BUTTON; + + static lastFocus = CommitView.focus.COMMIT_BUTTON; + static propTypes = { workspace: PropTypes.object.isRequired, config: PropTypes.object.isRequired, @@ -569,15 +575,7 @@ export default class CommitView extends React.Component { return this.refRoot.map(element => element.contains(document.activeElement)).getOr(false); } - hasFocusEditor() { - return this.refEditorComponent.map(editor => editor.contains(document.activeElement)).getOr(false); - } - - hasFocusAtBeginning() { - return this.refCommitPreviewButton.map(button => button.contains(document.activeElement)).getOr(false); - } - - getFocus(element = document.activeElement) { + getFocus(element) { if (this.refCommitPreviewButton.map(button => button.contains(element)).getOr(false)) { return CommitView.focus.COMMIT_PREVIEW_BUTTON; } @@ -601,10 +599,6 @@ export default class CommitView extends React.Component { return null; } - rememberFocus(event) { - return this.getFocus(event.target); - } - setFocus(focus) { let fallback = false; const focusElement = element => { @@ -657,19 +651,23 @@ export default class CommitView extends React.Component { return false; } - advanceFocus(event) { + advanceFocusFrom(focus) { const f = this.constructor.focus; - const current = this.getFocus(); - if (current === f.EDITOR) { - // Let the editor handle it - return true; - } let next = null; - switch (current) { + switch (focus) { case f.COMMIT_PREVIEW_BUTTON: next = f.EDITOR; break; + case f.EDITOR: + if (this.state.showCoAuthorInput) { + next = f.COAUTHOR_INPUT; + } else if (this.props.isMerging) { + next = f.ABORT_MERGE_BUTTON; + } else { + next = f.COMMIT_BUTTON; + } + break; case f.COAUTHOR_INPUT: next = this.props.isMerging ? f.ABORT_MERGE_BUTTON : f.COMMIT_BUTTON; break; @@ -677,57 +675,41 @@ export default class CommitView extends React.Component { next = f.COMMIT_BUTTON; break; case f.COMMIT_BUTTON: - // End of tab navigation. Prevent cycling. - event.stopPropagation(); - return true; + next = RecentCommitsView.firstFocus; + break; } - if (next !== null) { - this.setFocus(next); - event.stopPropagation(); - - return true; - } else { - return false; - } + return Promise.resolve(next); } - retreatFocus(event) { + retreatFocusFrom(focus) { const f = this.constructor.focus; - const current = this.getFocus(); - let next = null; - switch (current) { + let previous = null; + switch (focus) { case f.COMMIT_BUTTON: if (this.props.isMerging) { - next = f.ABORT_MERGE_BUTTON; + previous = f.ABORT_MERGE_BUTTON; } else if (this.state.showCoAuthorInput) { - next = f.COAUTHOR_INPUT; + previous = f.COAUTHOR_INPUT; } else { - next = f.EDITOR; + previous = f.EDITOR; } break; case f.ABORT_MERGE_BUTTON: - next = this.state.showCoAuthorInput ? f.COAUTHOR_INPUT : f.EDITOR; + previous = this.state.showCoAuthorInput ? f.COAUTHOR_INPUT : f.EDITOR; break; case f.COAUTHOR_INPUT: - next = f.EDITOR; + previous = f.EDITOR; break; case f.EDITOR: - next = f.COMMIT_PREVIEW_BUTTON; + previous = f.COMMIT_PREVIEW_BUTTON; break; case f.COMMIT_PREVIEW_BUTTON: - // Allow the GitTabView to retreat focus back to the last StagingView list. - return false; + previous = StagingView.lastFocus; + break; } - if (next !== null) { - this.setFocus(next); - event.stopPropagation(); - - return true; - } else { - return false; - } + return Promise.resolve(previous); } } diff --git a/lib/views/git-tab-view.js b/lib/views/git-tab-view.js index 1330e299c0..4ec74fde66 100644 --- a/lib/views/git-tab-view.js +++ b/lib/views/git-tab-view.js @@ -224,35 +224,22 @@ export default class GitTabView extends React.Component { this.props.initializeRepo(initPath); } - rememberFocus(event) { - let currentFocus = null; - - currentFocus = this.props.refStagingView.map(view => view.rememberFocus(event)).getOr(null); - - if (!currentFocus) { - currentFocus = this.refCommitController.map(controller => controller.rememberFocus(event)).getOr(null); - } - - if (!currentFocus) { - currentFocus = this.refRecentCommitsController.map(controller => controller.rememberFocus(event)).getOr(null); + getFocus(element) { + for (const ref of [this.props.refStagingView, this.refCommitController, this.refRecentCommitsController]) { + const focus = ref.map(sub => sub.getFocus(element)).getOr(null); + if (focus !== null) { + return focus; + } } - - return currentFocus; + return null; } setFocus(focus) { - if (this.props.refStagingView.map(view => view.setFocus(focus)).getOr(false)) { - return true; - } - - if (this.refCommitController.map(controller => controller.setFocus(focus)).getOr(false)) { - return true; - } - - if (this.refRecentCommitsController.map(controller => controller.setFocus(focus)).getOr(false)) { - return true; + for (const ref of [this.props.refStagingView, this.refCommitController, this.refRecentCommitsController]) { + if (ref.map(sub => sub.setFocus(focus)).getOr(false)) { + return true; + } } - return false; } @@ -261,39 +248,34 @@ export default class GitTabView extends React.Component { } async advanceFocus(evt) { - // Advance focus within the CommitView if it's there - if (this.refCommitController.map(c => c.advanceFocus(evt)).getOr(false)) { - return; - } + const currentFocus = this.getFocus(document.activeElement); + let nextSeen = false; - // Advance focus to the next staging view list, if it's there - if (await this.props.refStagingView.map(view => view.activateNextList()).getOr(false)) { - evt.stopPropagation(); - return; - } - - // Advance focus from the staging view lists to the CommitView - if (this.refCommitController.map(c => c.setFocus(GitTabView.focus.COMMIT_PREVIEW_BUTTON)).getOr(false)) { - evt.stopPropagation(); + for (const subHolder of [this.props.refStagingView, this.refCommitController, this.refRecentCommitsController]) { + const next = await subHolder.map(sub => sub.advanceFocusFrom(currentFocus)).getOr(null); + if (next !== null && !nextSeen) { + nextSeen = true; + evt.stopPropagation(); + if (next !== currentFocus) { + this.setFocus(next); + } + } } } async retreatFocus(evt) { - // Retreat focus within the CommitView if it's there - if (this.refCommitController.map(c => c.retreatFocus(evt)).getOr(false)) { - return; - } + const currentFocus = this.getFocus(document.activeElement); + let previousSeen = false; - if (this.refCommitController.map(c => c.hasFocusAtBeginning()).getOr(false)) { - // Retreat focus from the beginning of the CommitView to the end of the StagingView - if (await this.props.refStagingView.map(view => view.activateLastList()).getOr(null)) { - this.setFocus(GitTabView.focus.STAGING); + for (const subHolder of [this.refRecentCommitsController, this.refCommitController, this.props.refStagingView]) { + const previous = await subHolder.map(sub => sub.retreatFocusFrom(currentFocus)).getOr(null); + if (previous !== null && !previousSeen) { + previousSeen = true; evt.stopPropagation(); + if (previous !== currentFocus) { + this.setFocus(previous); + } } - } else if (await this.props.refStagingView.map(c => c.activatePreviousList()).getOr(null)) { - // Retreat focus within the StagingView - this.setFocus(GitTabView.focus.STAGING); - evt.stopPropagation(); } } diff --git a/lib/views/recent-commits-view.js b/lib/views/recent-commits-view.js index dfd60105fc..ac64db3d40 100644 --- a/lib/views/recent-commits-view.js +++ b/lib/views/recent-commits-view.js @@ -7,6 +7,7 @@ import {emojify} from 'node-emoji'; import Commands, {Command} from '../atom/commands'; import RefHolder from '../models/ref-holder'; +import CommitView from './commit-view'; import Timeago from './timeago'; class RecentCommitView extends React.Component { @@ -130,6 +131,10 @@ export default class RecentCommitsView extends React.Component { RECENT_COMMIT: Symbol('recent_commit'), }; + static firstFocus = RecentCommitsView.focus.RECENT_COMMIT; + + static lastFocus = RecentCommitsView.focus.RECENT_COMMIT; + constructor(props) { super(props); this.refRoot = new RefHolder(); @@ -143,8 +148,8 @@ export default class RecentCommitsView extends React.Component { return false; } - rememberFocus(event) { - return this.refRoot.map(element => element.contains(event.target)).getOr(false) + getFocus(element) { + return this.refRoot.map(e => e.contains(element)).getOr(false) ? this.constructor.focus.RECENT_COMMIT : null; } @@ -198,4 +203,20 @@ export default class RecentCommitsView extends React.Component { } openSelectedCommit = () => this.props.openCommit({sha: this.props.selectedCommitSha, preserveFocus: false}) + + advanceFocusFrom(focus) { + if (focus === this.constructor.focus.RECENT_COMMIT) { + return Promise.resolve(this.constructor.focus.RECENT_COMMIT); + } + + return Promise.resolve(null); + } + + retreatFocusFrom(focus) { + if (focus === this.constructor.focus.RECENT_COMMIT) { + return Promise.resolve(CommitView.lastFocus); + } + + return Promise.resolve(null); + } } diff --git a/lib/views/staging-view.js b/lib/views/staging-view.js index 8629ff8953..474db1aaa0 100644 --- a/lib/views/staging-view.js +++ b/lib/views/staging-view.js @@ -12,6 +12,7 @@ import ObserveModel from './observe-model'; import MergeConflictListItemView from './merge-conflict-list-item-view'; import CompositeListSelection from '../models/composite-list-selection'; import ResolutionProgress from '../models/conflicts/resolution-progress'; +import CommitView from './commit-view'; import RefHolder from '../models/ref-holder'; import ChangedFileItem from '../items/changed-file-item'; import Commands, {Command} from '../atom/commands'; @@ -43,7 +44,7 @@ function calculateTruncatedLists(lists) { }, {source: {}}); } -const noop = () => {}; +const noop = () => { }; const MAXIMUM_LISTED_ENTRIES = 1000; @@ -76,6 +77,10 @@ export default class StagingView extends React.Component { STAGING: Symbol('staging'), }; + static firstFocus = StagingView.focus.STAGING; + + static lastFocus = StagingView.focus.STAGING; + constructor(props) { super(props); autobind( @@ -226,12 +231,12 @@ export default class StagingView extends React.Component {
    {this.renderTruncatedMessage(this.props.unstagedChanges)}
    - { this.renderMergeConflicts() } + {this.renderMergeConflicts()}
    - Staged Changes + Staged Changes
    ); } @@ -81,7 +81,7 @@ export default createFragmentContainer(BareCommitView, { } } authoredByCommitter - oid message messageHeadlineHTML commitUrl + sha:oid message messageHeadlineHTML commitUrl } `, }); From f8d1341342171fa670dd93e4907bdaef65fb6819 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 30 Nov 2018 22:11:30 +0100 Subject: [PATCH 2097/4847] drill em props! --- lib/views/issueish-detail-view.js | 2 ++ lib/views/issueish-timeline-view.js | 7 +++++++ lib/views/timeline-items/commit-view.js | 2 ++ lib/views/timeline-items/commits-view.js | 4 +++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index 2b63163849..27312dff45 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -175,6 +175,8 @@ export class BareIssueishDetailView extends React.Component { {this.renderEmojiReactions(issueish)} diff --git a/lib/views/issueish-timeline-view.js b/lib/views/issueish-timeline-view.js index 0d376d958a..6523173807 100644 --- a/lib/views/issueish-timeline-view.js +++ b/lib/views/issueish-timeline-view.js @@ -77,6 +77,8 @@ export default class IssueishTimelineView extends React.Component { pullRequest: PropTypes.shape({ timeline: TimelineConnectionPropType, }), + onBranch: PropTypes.bool.isRequired, + openCommit: PropTypes.func.isRequired, } constructor(props) { @@ -98,6 +100,10 @@ export default class IssueishTimelineView extends React.Component {
    {groupedEdges.map(({type, edges}) => { const Component = timelineItems[type]; + const propsForCommits = { + onBranch: this.props.onBranch, + openCommit: this.props.openCommit, + }; if (Component) { return ( e.node)} issueish={issueish} switchToIssueish={this.props.switchToIssueish} + {...(Component === CommitsView && propsForCommits)} /> ); } else { diff --git a/lib/views/timeline-items/commit-view.js b/lib/views/timeline-items/commit-view.js index 988435f73f..6c902bc2ff 100644 --- a/lib/views/timeline-items/commit-view.js +++ b/lib/views/timeline-items/commit-view.js @@ -7,6 +7,8 @@ import Octicon from '../../atom/octicon'; export class BareCommitView extends React.Component { static propTypes = { item: PropTypes.object.isRequired, + onBranch: PropTypes.bool.isRequired, + openCommit: PropTypes.func.isRequired, } authoredByCommitter(commit) { diff --git a/lib/views/timeline-items/commits-view.js b/lib/views/timeline-items/commits-view.js index 7d296507cc..9118646abd 100644 --- a/lib/views/timeline-items/commits-view.js +++ b/lib/views/timeline-items/commits-view.js @@ -17,6 +17,8 @@ export class BareCommitsView extends React.Component { }).isRequired, }).isRequired, ).isRequired, + onBranch: PropTypes.bool.isRequired, + openCommit: PropTypes.func.isRequired, } render() { @@ -46,7 +48,7 @@ export class BareCommitsView extends React.Component { renderCommits() { return this.props.nodes.map(node => { - return ; + return ; }); } From e5d4317deb8d603da15ab30e195124411f3e6396 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 30 Nov 2018 22:20:44 +0100 Subject: [PATCH 2098/4847] open commit detail item when commit header is clicked from PR timeline. --- lib/views/timeline-items/commit-view.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/views/timeline-items/commit-view.js b/lib/views/timeline-items/commit-view.js index 6c902bc2ff..2b62988a01 100644 --- a/lib/views/timeline-items/commit-view.js +++ b/lib/views/timeline-items/commit-view.js @@ -1,6 +1,7 @@ import React from 'react'; import {graphql, createFragmentContainer} from 'react-relay'; import PropTypes from 'prop-types'; +import cx from 'classnames'; import Octicon from '../../atom/octicon'; @@ -31,6 +32,10 @@ export class BareCommitView extends React.Component { return false; } + openCommitDetailItem = () => { + return this.props.onBranch ? this.props.openCommit({sha: this.props.item.sha}) : null; + } + renderCommitter(commit) { if (!this.authoredByCommitter(commit)) { return ( @@ -57,9 +62,10 @@ export class BareCommitView extends React.Component { {this.renderCommitter(commit)} {commit.sha.slice(0, 8)}
    From a2babbb058f5706a61a0fadc77521b235c552f1a Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 30 Nov 2018 22:23:00 +0100 Subject: [PATCH 2099/4847] add some clickable styling --- styles/pr-timeline.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/styles/pr-timeline.less b/styles/pr-timeline.less index 72a07dbcc9..fcd9324095 100644 --- a/styles/pr-timeline.less +++ b/styles/pr-timeline.less @@ -104,6 +104,10 @@ overflow: hidden; max-width: 0; // this makes sure the ellipsis work in table-cell width: 100%; + &.clickable:hover { + cursor: pointer; + text-decoration: underline; + } } .commit-sha { From 97c42ad56cafc626a12a54a4c024f46fc2e16954 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 30 Nov 2018 14:29:49 -0800 Subject: [PATCH 2100/4847] tilde 1, relay 0. For now at least. I was afraid to rename the props from `issueish` to `pullRequest` because I thought it would fuck up Relay, but actually it wasn't too bad. --- .../issueishDetailContainerQuery.graphql.js | 498 +++++++++--------- ...eishDetailController_repository.graphql.js | 93 ++-- lib/controllers/issueish-detail-controller.js | 7 +- .../prDetailViewRefetchQuery.graphql.js | 24 +- ...js => prDetailView_pullRequest.graphql.js} | 10 +- lib/views/pr-detail-view.js | 44 +- 6 files changed, 360 insertions(+), 316 deletions(-) rename lib/views/__generated__/{prDetailView_issueish.graphql.js => prDetailView_pullRequest.graphql.js} (95%) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index f187ce54f6..f5ec6b4c46 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 6d9cf8ec92db318e118f5f32a23c5af4 + * @relayHash 76d06aecf543e593ddcbc07aca4e478a */ /* eslint-disable */ @@ -63,6 +63,12 @@ fragment issueishDetailController_repository_1mXVvq on Repository { number ...issueDetailView_issueish_4cAEh0 } + ... on Node { + id + } + } + pullRequest: issueOrPullRequest(number: $issueishNumber) { + __typename ... on PullRequest { title number @@ -78,7 +84,7 @@ fragment issueishDetailController_repository_1mXVvq on Repository { sshUrl id } - ...prDetailView_issueish_4cAEh0 + ...prDetailView_pullRequest_4cAEh0 } ... on Node { id @@ -143,7 +149,7 @@ fragment issueDetailView_issueish_4cAEh0 on Issue { } } -fragment prDetailView_issueish_4cAEh0 on PullRequest { +fragment prDetailView_pullRequest_4cAEh0 on PullRequest { __typename ... on Node { id @@ -610,11 +616,10 @@ v7 = { }, v8 = [ { - "kind": "ScalarField", - "alias": null, - "name": "totalCount", - "args": null, - "storageKey": null + "kind": "Variable", + "name": "number", + "variableName": "issueishNumber", + "type": "Int!" } ], v9 = { @@ -627,95 +632,42 @@ v9 = { v10 = { "kind": "ScalarField", "alias": null, - "name": "url", + "name": "number", "args": null, "storageKey": null }, v11 = { "kind": "ScalarField", "alias": null, - "name": "isCrossRepository", + "name": "state", "args": null, "storageKey": null }, -v12 = [ - { - "kind": "Variable", - "name": "after", - "variableName": "commitCursor", - "type": "String" - }, - { - "kind": "Variable", - "name": "first", - "variableName": "commitCount", - "type": "Int" - } -], -v13 = { - "kind": "LinkedField", - "alias": null, - "name": "pageInfo", - "storageKey": null, - "args": null, - "concreteType": "PageInfo", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "endCursor", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "hasNextPage", - "args": null, - "storageKey": null - } - ] -}, -v14 = { +v12 = { "kind": "ScalarField", "alias": null, - "name": "cursor", + "name": "bodyHTML", "args": null, "storageKey": null }, -v15 = { +v13 = { "kind": "ScalarField", "alias": null, "name": "avatarUrl", "args": null, "storageKey": null }, -v16 = { - "kind": "ScalarField", - "alias": null, - "name": "number", - "args": null, - "storageKey": null -}, -v17 = { - "kind": "ScalarField", - "alias": null, - "name": "state", - "args": null, - "storageKey": null -}, -v18 = { +v14 = { "kind": "ScalarField", "alias": null, - "name": "bodyHTML", + "name": "url", "args": null, "storageKey": null }, -v19 = [ - v10 +v15 = [ + v14 ], -v20 = { +v16 = { "kind": "LinkedField", "alias": null, "name": "author", @@ -726,21 +678,21 @@ v20 = { "selections": [ v4, v5, - v15, + v13, v2, { "kind": "InlineFragment", "type": "Bot", - "selections": v19 + "selections": v15 }, { "kind": "InlineFragment", "type": "User", - "selections": v19 + "selections": v15 } ] }, -v21 = [ +v17 = [ { "kind": "Variable", "name": "after", @@ -754,13 +706,52 @@ v21 = [ "type": "Int" } ], -v22 = [ +v18 = { + "kind": "LinkedField", + "alias": null, + "name": "pageInfo", + "storageKey": null, + "args": null, + "concreteType": "PageInfo", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "endCursor", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "hasNextPage", + "args": null, + "storageKey": null + } + ] +}, +v19 = { + "kind": "ScalarField", + "alias": null, + "name": "cursor", + "args": null, + "storageKey": null +}, +v20 = { + "kind": "ScalarField", + "alias": null, + "name": "isCrossRepository", + "args": null, + "storageKey": null +}, +v21 = [ v4, v5, - v15, + v13, v2 ], -v23 = { +v22 = { "kind": "InlineFragment", "type": "CrossReferencedEvent", "selections": [ @@ -771,7 +762,7 @@ v23 = { "args": null, "storageKey": null }, - v11, + v20, { "kind": "LinkedField", "alias": null, @@ -780,7 +771,7 @@ v23 = { "args": null, "concreteType": null, "plural": false, - "selections": v22 + "selections": v21 }, { "kind": "LinkedField", @@ -818,9 +809,9 @@ v23 = { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v16, - v9, v10, + v9, + v14, { "kind": "ScalarField", "alias": "prState", @@ -834,9 +825,9 @@ v23 = { "kind": "InlineFragment", "type": "Issue", "selections": [ - v16, - v9, v10, + v9, + v14, { "kind": "ScalarField", "alias": "issueState", @@ -850,51 +841,20 @@ v23 = { } ] }, -v24 = { - "kind": "ScalarField", - "alias": null, - "name": "oid", - "args": null, - "storageKey": null -}, -v25 = [ - v24, +v23 = [ + v4, + v13, + v5, v2 ], -v26 = { - "kind": "LinkedField", - "alias": null, - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v25 -}, -v27 = { +v24 = { "kind": "ScalarField", "alias": null, "name": "createdAt", "args": null, "storageKey": null }, -v28 = [ - v4, - v15, - v5, - v2 -], -v29 = { - "kind": "LinkedField", - "alias": null, - "name": "actor", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": v28 -}, -v30 = { +v25 = { "kind": "InlineFragment", "type": "IssueComment", "selections": [ @@ -906,14 +866,14 @@ v30 = { "args": null, "concreteType": null, "plural": false, - "selections": v28 + "selections": v23 }, - v18, - v27, - v10 + v12, + v24, + v14 ] }, -v31 = { +v26 = { "kind": "LinkedField", "alias": null, "name": "user", @@ -926,7 +886,14 @@ v31 = { v2 ] }, -v32 = { +v27 = { + "kind": "ScalarField", + "alias": null, + "name": "oid", + "args": null, + "storageKey": null +}, +v28 = { "kind": "InlineFragment", "type": "Commit", "selections": [ @@ -940,8 +907,8 @@ v32 = { "plural": false, "selections": [ v3, - v31, - v15 + v26, + v13 ] }, { @@ -954,8 +921,8 @@ v32 = { "plural": false, "selections": [ v3, - v15, - v31 + v13, + v26 ] }, { @@ -965,7 +932,7 @@ v32 = { "args": null, "storageKey": null }, - v24, + v27, { "kind": "ScalarField", "alias": null, @@ -989,7 +956,16 @@ v32 = { } ] }, -v33 = { +v29 = [ + { + "kind": "ScalarField", + "alias": null, + "name": "totalCount", + "args": null, + "storageKey": null + } +], +v30 = { "kind": "LinkedField", "alias": null, "name": "reactionGroups", @@ -1013,16 +989,54 @@ v33 = { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v8 + "selections": v29 } ] +}, +v31 = [ + { + "kind": "Variable", + "name": "after", + "variableName": "commitCursor", + "type": "String" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "commitCount", + "type": "Int" + } +], +v32 = [ + v27, + v2 +], +v33 = { + "kind": "LinkedField", + "alias": null, + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v32 +}, +v34 = { + "kind": "LinkedField", + "alias": null, + "name": "actor", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": v23 }; return { "kind": "Request", "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_1mXVvq\n id\n }\n}\n\nfragment issueishDetailController_repository_1mXVvq on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issueish_4cAEh0\n }\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_issueish_4cAEh0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issueish_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_issueish_4cAEh0 on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n abbreviatedOid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_1mXVvq\n id\n }\n}\n\nfragment issueishDetailController_repository_1mXVvq on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issueish_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_4cAEh0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issueish_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_4cAEh0 on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n abbreviatedOid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1102,14 +1116,82 @@ return { "alias": "issueish", "name": "issueOrPullRequest", "storageKey": null, - "args": [ + "args": v8, + "concreteType": null, + "plural": false, + "selections": [ + v4, + v2, { - "kind": "Variable", - "name": "number", - "variableName": "issueishNumber", - "type": "Int!" + "kind": "InlineFragment", + "type": "Issue", + "selections": [ + v9, + v10, + v11, + v12, + v16, + v14, + { + "kind": "LinkedField", + "alias": null, + "name": "timeline", + "storageKey": null, + "args": v17, + "concreteType": "IssueTimelineConnection", + "plural": false, + "selections": [ + v18, + { + "kind": "LinkedField", + "alias": null, + "name": "edges", + "storageKey": null, + "args": null, + "concreteType": "IssueTimelineItemEdge", + "plural": true, + "selections": [ + v19, + { + "kind": "LinkedField", + "alias": null, + "name": "node", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v4, + v2, + v22, + v25, + v28 + ] + } + ] + } + ] + }, + { + "kind": "LinkedHandle", + "alias": null, + "name": "timeline", + "args": v17, + "handle": "connection", + "key": "IssueTimelineController_timeline", + "filters": null + }, + v30 + ] } - ], + ] + }, + { + "kind": "LinkedField", + "alias": "pullRequest", + "name": "issueOrPullRequest", + "storageKey": null, + "args": v8, "concreteType": null, "plural": false, "selections": [ @@ -1127,7 +1209,7 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v8 + "selections": v29 }, v9, { @@ -1148,7 +1230,7 @@ return { "selections": [ v3, v7, - v10, + v14, { "kind": "ScalarField", "alias": null, @@ -1159,7 +1241,7 @@ return { v2 ] }, - v11, + v20, { "kind": "ScalarField", "alias": null, @@ -1167,17 +1249,17 @@ return { "args": null, "storageKey": null }, - v10, + v14, { "kind": "LinkedField", "alias": null, "name": "commits", "storageKey": null, - "args": v12, + "args": v31, "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ - v13, + v18, { "kind": "LinkedField", "alias": null, @@ -1187,7 +1269,7 @@ return { "concreteType": "PullRequestCommitEdge", "plural": true, "selections": [ - v14, + v19, { "kind": "LinkedField", "alias": null, @@ -1216,7 +1298,7 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v15, + v13, v3, { "kind": "ScalarField", @@ -1248,7 +1330,7 @@ return { "args": null, "storageKey": null }, - v10 + v14 ] }, v2, @@ -1263,12 +1345,12 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v12, + "args": v31, "handle": "connection", "key": "prCommitsView_commits", "filters": null }, - v16, + v10, { "kind": "LinkedField", "alias": "recentCommits", @@ -1321,7 +1403,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v17, + v11, { "kind": "LinkedField", "alias": null, @@ -1332,7 +1414,7 @@ return { "plural": true, "selections": [ v2, - v17, + v11, { "kind": "ScalarField", "alias": null, @@ -1369,8 +1451,8 @@ return { } ] }, - v17, - v18, + v11, + v12, { "kind": "ScalarField", "alias": null, @@ -1378,7 +1460,7 @@ return { "args": null, "storageKey": null }, - v20, + v16, { "kind": "LinkedField", "alias": null, @@ -1407,11 +1489,11 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": v21, + "args": v17, "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v13, + v18, { "kind": "LinkedField", "alias": null, @@ -1421,7 +1503,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v14, + v19, { "kind": "LinkedField", "alias": null, @@ -1433,12 +1515,12 @@ return { "selections": [ v4, v2, - v23, + v22, { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v26, + v33, { "kind": "LinkedField", "alias": null, @@ -1482,11 +1564,11 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v22 + "selections": v21 }, - v26, - v18, - v27, + v33, + v12, + v24, { "kind": "ScalarField", "alias": null, @@ -1513,7 +1595,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v29, + v34, { "kind": "LinkedField", "alias": null, @@ -1522,7 +1604,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v25 + "selections": v32 }, { "kind": "LinkedField", @@ -1532,17 +1614,17 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v25 + "selections": v32 }, - v27 + v24 ] }, { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v29, - v26, + v34, + v33, { "kind": "ScalarField", "alias": null, @@ -1550,11 +1632,11 @@ return { "args": null, "storageKey": null }, - v27 + v24 ] }, - v30, - v32 + v25, + v28 ] } ] @@ -1565,74 +1647,12 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v21, + "args": v17, "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null }, - v33 - ] - }, - { - "kind": "InlineFragment", - "type": "Issue", - "selections": [ - v9, - v16, - v17, - v18, - v20, - v10, - { - "kind": "LinkedField", - "alias": null, - "name": "timeline", - "storageKey": null, - "args": v21, - "concreteType": "IssueTimelineConnection", - "plural": false, - "selections": [ - v13, - { - "kind": "LinkedField", - "alias": null, - "name": "edges", - "storageKey": null, - "args": null, - "concreteType": "IssueTimelineItemEdge", - "plural": true, - "selections": [ - v14, - { - "kind": "LinkedField", - "alias": null, - "name": "node", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v4, - v2, - v23, - v30, - v32 - ] - } - ] - } - ] - }, - { - "kind": "LinkedHandle", - "alias": null, - "name": "timeline", - "args": v21, - "handle": "connection", - "key": "IssueTimelineController_timeline", - "filters": null - }, - v33 + v30 ] } ] diff --git a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js index 560e15de5e..92a8971f02 100644 --- a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js +++ b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js @@ -10,7 +10,7 @@ import type { ConcreteFragment } from 'relay-runtime'; type issueDetailView_issueish$ref = any; type issueDetailView_repository$ref = any; -type prDetailView_issueish$ref = any; +type prDetailView_pullRequest$ref = any; type prDetailView_repository$ref = any; import type { FragmentReference } from "relay-runtime"; declare export opaque type issueishDetailController_repository$ref: FragmentReference; @@ -25,7 +25,14 @@ export type issueishDetailController_repository = {| +number: number, +$fragmentRefs: issueDetailView_issueish$ref, |} | {| + // This will never be '%other', but we need some + // value in case none of the concrete values match. + +__typename: "%other" + |}), + +pullRequest: ?({| +__typename: "PullRequest", + +title: string, + +number: number, +headRefName: string, +headRepository: ?{| +name: string, @@ -35,7 +42,7 @@ export type issueishDetailController_repository = {| +url: any, +sshUrl: any, |}, - +$fragmentRefs: prDetailView_issueish$ref, + +$fragmentRefs: prDetailView_pullRequest$ref, |} | {| // This will never be '%other', but we need some // value in case none of the concrete values match. @@ -73,21 +80,36 @@ v1 = { } ] }, -v2 = { +v2 = [ + { + "kind": "Variable", + "name": "number", + "variableName": "issueishNumber", + "type": "Int!" + } +], +v3 = { + "kind": "ScalarField", + "alias": null, + "name": "__typename", + "args": null, + "storageKey": null +}, +v4 = { "kind": "ScalarField", "alias": null, "name": "title", "args": null, "storageKey": null }, -v3 = { +v5 = { "kind": "ScalarField", "alias": null, "name": "number", "args": null, "storageKey": null }, -v4 = [ +v6 = [ { "kind": "Variable", "name": "commitCount", @@ -168,30 +190,42 @@ return { "alias": "issueish", "name": "issueOrPullRequest", "storageKey": null, - "args": [ + "args": v2, + "concreteType": null, + "plural": false, + "selections": [ + v3, { - "kind": "Variable", - "name": "number", - "variableName": "issueishNumber", - "type": "Int!" + "kind": "InlineFragment", + "type": "Issue", + "selections": [ + v4, + v5, + { + "kind": "FragmentSpread", + "name": "issueDetailView_issueish", + "args": v6 + } + ] } - ], + ] + }, + { + "kind": "LinkedField", + "alias": "pullRequest", + "name": "issueOrPullRequest", + "storageKey": null, + "args": v2, "concreteType": null, "plural": false, "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "__typename", - "args": null, - "storageKey": null - }, + v3, { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v2, - v3, + v4, + v5, { "kind": "ScalarField", "alias": null, @@ -228,21 +262,8 @@ return { }, { "kind": "FragmentSpread", - "name": "prDetailView_issueish", - "args": v4 - } - ] - }, - { - "kind": "InlineFragment", - "type": "Issue", - "selections": [ - v2, - v3, - { - "kind": "FragmentSpread", - "name": "issueDetailView_issueish", - "args": v4 + "name": "prDetailView_pullRequest", + "args": v6 } ] } @@ -252,5 +273,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '23d8c284628ab45da2d636dcfbbd8239'; +(node/*: any*/).hash = '7b81a0a36c9be005da2a5bb6a876972c'; module.exports = node; diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index 8be5ea548a..ca4cd6c7f7 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -84,7 +84,7 @@ export class BareIssueishDetailController extends React.Component { return ( @@ -242,6 +242,9 @@ export default createFragmentContainer(BareIssueishDetailController, { commitCursor: $commitCursor, ) } + } + pullRequest: issueOrPullRequest(number: $issueishNumber) { + __typename ... on PullRequest { title number @@ -254,7 +257,7 @@ export default createFragmentContainer(BareIssueishDetailController, { url sshUrl } - ...prDetailView_issueish @arguments( + ...prDetailView_pullRequest @arguments( timelineCount: $timelineCount, timelineCursor: $timelineCursor, commitCount: $commitCount, diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index 64d60f0047..314a5a0bf2 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash fd414a0501fa54acfda074aee07b1aa4 + * @relayHash de4a33fffa471708fdc3fd0ec577e16b */ /* eslint-disable */ @@ -9,7 +9,7 @@ /*:: import type { ConcreteRequest } from 'relay-runtime'; -type prDetailView_issueish$ref = any; +type prDetailView_pullRequest$ref = any; type prDetailView_repository$ref = any; export type prDetailViewRefetchQueryVariables = {| repoId: string, @@ -23,8 +23,8 @@ export type prDetailViewRefetchQueryResponse = {| +repository: ?{| +$fragmentRefs: prDetailView_repository$ref |}, - +issueish: ?{| - +$fragmentRefs: prDetailView_issueish$ref + +pullRequest: ?{| + +$fragmentRefs: prDetailView_pullRequest$ref |}, |}; export type prDetailViewRefetchQuery = {| @@ -48,9 +48,9 @@ query prDetailViewRefetchQuery( ...prDetailView_repository_3D8CP9 id } - issueish: node(id: $issueishId) { + pullRequest: node(id: $issueishId) { __typename - ...prDetailView_issueish_4cAEh0 + ...prDetailView_pullRequest_4cAEh0 id } } @@ -65,7 +65,7 @@ fragment prDetailView_repository_3D8CP9 on Repository { } } -fragment prDetailView_issueish_4cAEh0 on PullRequest { +fragment prDetailView_pullRequest_4cAEh0 on PullRequest { __typename ... on Node { id @@ -705,7 +705,7 @@ return { "operationKind": "query", "name": "prDetailViewRefetchQuery", "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...prDetailView_issueish_4cAEh0\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_issueish_4cAEh0 on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n abbreviatedOid\n url\n}\n", + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_4cAEh0\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_4cAEh0 on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n abbreviatedOid\n url\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -735,7 +735,7 @@ return { }, { "kind": "LinkedField", - "alias": "issueish", + "alias": "pullRequest", "name": "node", "storageKey": null, "args": v4, @@ -744,7 +744,7 @@ return { "selections": [ { "kind": "FragmentSpread", - "name": "prDetailView_issueish", + "name": "prDetailView_pullRequest", "args": [ { "kind": "Variable", @@ -794,7 +794,7 @@ return { }, { "kind": "LinkedField", - "alias": "issueish", + "alias": "pullRequest", "name": "node", "storageKey": null, "args": v4, @@ -1467,5 +1467,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'ba6fcfcda973b63cbdd79918fb888605'; +(node/*: any*/).hash = '04dad90234c09010553beb02cf90cbb1'; module.exports = node; diff --git a/lib/views/__generated__/prDetailView_issueish.graphql.js b/lib/views/__generated__/prDetailView_pullRequest.graphql.js similarity index 95% rename from lib/views/__generated__/prDetailView_issueish.graphql.js rename to lib/views/__generated__/prDetailView_pullRequest.graphql.js index fe77fc3798..ae06b6754a 100644 --- a/lib/views/__generated__/prDetailView_issueish.graphql.js +++ b/lib/views/__generated__/prDetailView_pullRequest.graphql.js @@ -14,8 +14,8 @@ type prTimelineController_pullRequest$ref = any; export type PullRequestState = "CLOSED" | "MERGED" | "OPEN" | "%future added value"; export type ReactionContent = "CONFUSED" | "HEART" | "HOORAY" | "LAUGH" | "THUMBS_DOWN" | "THUMBS_UP" | "%future added value"; import type { FragmentReference } from "relay-runtime"; -declare export opaque type prDetailView_issueish$ref: FragmentReference; -export type prDetailView_issueish = {| +declare export opaque type prDetailView_pullRequest$ref: FragmentReference; +export type prDetailView_pullRequest = {| +id?: string, +isCrossRepository: boolean, +changedFiles: number, @@ -42,7 +42,7 @@ export type prDetailView_issueish = {| |}>, +__typename: "PullRequest", +$fragmentRefs: prCommitsView_pullRequest$ref & prStatusesView_pullRequest$ref & prTimelineController_pullRequest$ref, - +$refType: prDetailView_issueish$ref, + +$refType: prDetailView_pullRequest$ref, |}; */ @@ -69,7 +69,7 @@ v2 = [ ]; return { "kind": "Fragment", - "name": "prDetailView_issueish", + "name": "prDetailView_pullRequest", "type": "PullRequest", "metadata": null, "argumentDefinitions": [ @@ -288,5 +288,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '3f707e83b01af99f75dfc844ef0f32d6'; +(node/*: any*/).hash = '2b7cc9778a3440738f809f76fcd3fd25'; module.exports = node; diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index e524be50cc..2e0cb13a26 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -43,7 +43,7 @@ export class BarePullRequestDetailView extends React.Component { login: PropTypes.string, }), }), - issueish: PropTypes.shape({ + pullRequest: PropTypes.shape({ __typename: PropTypes.string.isRequired, id: PropTypes.string.isRequired, title: PropTypes.string, @@ -86,7 +86,7 @@ export class BarePullRequestDetailView extends React.Component { componentDidMount() { this.refresher = new PeriodicRefresher(BarePullRequestDetailView, { interval: () => 5 * 60 * 1000, - getCurrentId: () => this.props.issueish.id, + getCurrentId: () => this.props.pullRequest.id, refresh: this.refresh, minimumIntervalPerId: 2 * 60 * 1000, }); @@ -98,26 +98,26 @@ export class BarePullRequestDetailView extends React.Component { this.refresher.destroy(); } - renderPrMetadata(issueish, repo) { + renderPrMetadata(pullRequest, repo) { return (
    {issueish.author.login} wants to merge{' '} + href={pullRequest.author.url}>{pullRequest.author.login} wants to merge{' '} {issueish.countedCommits.totalCount} commits and{' '} + href={pullRequest.url + '/commits'}>{pullRequest.countedCommits.totalCount} commits and{' '} {issueish.changedFiles} changed files into{' '} - {issueish.isCrossRepository ? - `${repo.owner.login}/${issueish.baseRefName}` : issueish.baseRefName} from{' '} - {issueish.isCrossRepository ? - `${issueish.author.login}/${issueish.headRefName}` : issueish.headRefName} + href={pullRequest.url + '/files'}>{pullRequest.changedFiles} changed files into{' '} + {pullRequest.isCrossRepository ? + `${repo.owner.login}/${pullRequest.baseRefName}` : pullRequest.baseRefName} from{' '} + {pullRequest.isCrossRepository ? + `${pullRequest.author.login}/${pullRequest.headRefName}` : pullRequest.headRefName}
    ); } - renderPullRequestBody(issueish, childProps) { + renderPullRequestBody(pullRequest, childProps) { return ( @@ -139,10 +139,10 @@ export class BarePullRequestDetailView extends React.Component { {/* overview */} No description provided.'} + html={pullRequest.bodyHTML || 'No description provided.'} switchToIssueish={this.props.switchToIssueish} /> - +
    - +
    {/* commits */} - +
    ); @@ -167,10 +167,10 @@ export class BarePullRequestDetailView extends React.Component { render() { const repo = this.props.repository; - const issueish = this.props.issueish; + const pullRequest = this.props.pullRequest; const childProps = { - issue: issueish.__typename === 'Issue' ? issueish : null, - pullRequest: issueish.__typename === 'PullRequest' ? issueish : null, + issue: pullRequest.__typename === 'Issue' ? pullRequest : null, + pullRequest: pullRequest.__typename === 'PullRequest' ? pullRequest : null, }; return ( @@ -307,8 +307,8 @@ export default createRefetchContainer(BarePullRequestDetailView, { } `, - issueish: graphql` - fragment prDetailView_issueish on PullRequest + pullRequest: graphql` + fragment prDetailView_pullRequest on PullRequest @argumentDefinitions( timelineCount: {type: "Int!"}, timelineCursor: {type: "String"}, @@ -365,8 +365,8 @@ export default createRefetchContainer(BarePullRequestDetailView, { ) } - issueish:node(id: $issueishId) { - ...prDetailView_issueish @arguments( + pullRequest:node(id: $issueishId) { + ...prDetailView_pullRequest @arguments( timelineCount: $timelineCount, timelineCursor: $timelineCursor, commitCount: $commitCount, From 9638361e0a3e16ecb90c683e278afcb19c34496a Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 30 Nov 2018 15:04:51 -0800 Subject: [PATCH 2101/4847] ok I think this shit actually works now? - Wasn't passing the right props into the PullRequestDetailView -Clean up some more issueish code --- lib/controllers/issueish-detail-controller.js | 16 ++++------ lib/views/pr-detail-view.js | 31 ++++++++++--------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index ca4cd6c7f7..bbaa3b32d4 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -84,7 +84,7 @@ export class BareIssueishDetailController extends React.Component { return ( @@ -102,11 +102,7 @@ export class BareIssueishDetailController extends React.Component { nextCheckoutOp() { const {repository} = this.props; - const {issueish} = repository; - - if (issueish.__typename !== 'PullRequest') { - return this.checkoutOp.disable(checkoutStates.HIDDEN, 'Cannot check out an issue'); - } + const {pullRequest} = repository; if (this.props.isAbsent) { return this.checkoutOp.disable(checkoutStates.HIDDEN, 'No repository found'); @@ -141,13 +137,13 @@ export class BareIssueishDetailController extends React.Component { const fromPullRefspec = headRemote.getOwner() === repository.owner.login && headRemote.getRepo() === repository.name && - headPush.getShortRemoteRef() === `pull/${issueish.number}/head`; + headPush.getShortRemoteRef() === `pull/${pullRequest.number}/head`; // (detect checkout from head repository) const fromHeadRepo = - headRemote.getOwner() === issueish.headRepository.owner.login && - headRemote.getRepo() === issueish.headRepository.name && - headPush.getShortRemoteRef() === issueish.headRefName; + headRemote.getOwner() === pullRequest.headRepository.owner.login && + headRemote.getRepo() === pullRequest.headRepository.name && + headPush.getShortRemoteRef() === pullRequest.headRefName; if (fromPullRefspec || fromHeadRepo) { return this.checkoutOp.disable(checkoutStates.CURRENT, 'Current'); diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index 2e0cb13a26..01b7286215 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -166,6 +166,7 @@ export class BarePullRequestDetailView extends React.Component { } render() { + console.log(this.props); const repo = this.props.repository; const pullRequest = this.props.pullRequest; const childProps = { @@ -180,14 +181,14 @@ export class BarePullRequestDetailView extends React.Component {
    - {this.renderPrMetadata(issueish, repo)} + {this.renderPrMetadata(pullRequest, repo)}
    - {this.renderPullRequestBody(issueish, childProps)} + {this.renderPullRequestBody(pullRequest, childProps)} @@ -274,7 +275,7 @@ export class BarePullRequestDetailView extends React.Component { } recordOpenInBrowserEvent() { - addEvent('open-issueish-in-browser', {package: 'github', component: this.constructor.name}); + addEvent('open-pull-request-in-browser', {package: 'github', component: this.constructor.name}); } refresh() { @@ -285,7 +286,7 @@ export class BarePullRequestDetailView extends React.Component { this.setState({refreshing: true}); this.props.relay.refetch({ repoId: this.props.repository.id, - issueishId: this.props.issueish.id, + issueishId: this.props.pullRequest.id, timelineCount: 100, timelineCursor: null, commitCount: 100, From a8fe2e6a8b4d2ccb5afd00ddb29232768f3e74c0 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 30 Nov 2018 15:53:50 -0800 Subject: [PATCH 2102/4847] rename `issueish` to `issue` --- .../issueishDetailContainerQuery.graphql.js | 12 ++--- ...eishDetailController_repository.graphql.js | 12 ++--- lib/controllers/issueish-detail-controller.js | 27 ++++++---- .../issueDetailViewRefetchQuery.graphql.js | 24 ++++----- ...ql.js => issueDetailView_issue.graphql.js} | 10 ++-- lib/views/issue-detail-view.js | 50 +++++++++---------- 6 files changed, 70 insertions(+), 65 deletions(-) rename lib/views/__generated__/{issueDetailView_issueish.graphql.js => issueDetailView_issue.graphql.js} (94%) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index f5ec6b4c46..b0930609aa 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 76d06aecf543e593ddcbc07aca4e478a + * @relayHash 08475467ae7fd142f34c5eefed3103b1 */ /* eslint-disable */ @@ -56,12 +56,12 @@ fragment issueishDetailController_repository_1mXVvq on Repository { login id } - issueish: issueOrPullRequest(number: $issueishNumber) { + issue: issueOrPullRequest(number: $issueishNumber) { __typename ... on Issue { title number - ...issueDetailView_issueish_4cAEh0 + ...issueDetailView_issue_4cAEh0 } ... on Node { id @@ -112,7 +112,7 @@ fragment prDetailView_repository on Repository { } } -fragment issueDetailView_issueish_4cAEh0 on Issue { +fragment issueDetailView_issue_4cAEh0 on Issue { __typename ... on Node { id @@ -1036,7 +1036,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_1mXVvq\n id\n }\n}\n\nfragment issueishDetailController_repository_1mXVvq on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issueish: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issueish_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_4cAEh0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issueish_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_4cAEh0 on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n abbreviatedOid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_1mXVvq\n id\n }\n}\n\nfragment issueishDetailController_repository_1mXVvq on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_4cAEh0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_4cAEh0 on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n abbreviatedOid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1113,7 +1113,7 @@ return { v7, { "kind": "LinkedField", - "alias": "issueish", + "alias": "issue", "name": "issueOrPullRequest", "storageKey": null, "args": v8, diff --git a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js index 92a8971f02..e36d6c2e87 100644 --- a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js +++ b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js @@ -8,7 +8,7 @@ /*:: import type { ConcreteFragment } from 'relay-runtime'; -type issueDetailView_issueish$ref = any; +type issueDetailView_issue$ref = any; type issueDetailView_repository$ref = any; type prDetailView_pullRequest$ref = any; type prDetailView_repository$ref = any; @@ -19,11 +19,11 @@ export type issueishDetailController_repository = {| +owner: {| +login: string |}, - +issueish: ?({| + +issue: ?({| +__typename: "Issue", +title: string, +number: number, - +$fragmentRefs: issueDetailView_issueish$ref, + +$fragmentRefs: issueDetailView_issue$ref, |} | {| // This will never be '%other', but we need some // value in case none of the concrete values match. @@ -187,7 +187,7 @@ return { v1, { "kind": "LinkedField", - "alias": "issueish", + "alias": "issue", "name": "issueOrPullRequest", "storageKey": null, "args": v2, @@ -203,7 +203,7 @@ return { v5, { "kind": "FragmentSpread", - "name": "issueDetailView_issueish", + "name": "issueDetailView_issue", "args": v6 } ] @@ -273,5 +273,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '7b81a0a36c9be005da2a5bb6a876972c'; +(node/*: any*/).hash = '616ab785cf6824cb91ed3002553abb70'; module.exports = node; diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index bbaa3b32d4..a433145ae5 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -16,7 +16,8 @@ export class BareIssueishDetailController extends React.Component { owner: PropTypes.shape({ login: PropTypes.string.isRequired, }).isRequired, - issueish: PropTypes.any, // FIXME from IssueishPaneItemContainer.propTypes + pullRequest: PropTypes.any, // FIXME + issue: PropTypes.any, // FIXME from IssueishPaneItemContainer.propTypes }), issueishNumber: PropTypes.number.isRequired, @@ -74,12 +75,12 @@ export class BareIssueishDetailController extends React.Component { render() { const {repository} = this.props; - if (!repository || !repository.issueish) { + if (!repository || !repository.issue || !repository.pullRequest) { return
    Issue/PR #{this.props.issueishNumber} not found
    ; // TODO: no PRs } this.checkoutOp = this.nextCheckoutOp(); - const isPr = repository.issueish.__typename === 'PullRequest'; + const isPr = repository.pullRequest.__typename === 'PullRequest'; if (isPr) { return ( ); @@ -104,6 +105,10 @@ export class BareIssueishDetailController extends React.Component { const {repository} = this.props; const {pullRequest} = repository; + if (pullRequest.__typename !== 'PullRequest') { + return this.checkoutOp.disable(checkoutStates.HIDDEN, 'Cannot check out an issue'); + } + if (this.props.isAbsent) { return this.checkoutOp.disable(checkoutStates.HIDDEN, 'No repository found'); } @@ -154,10 +159,10 @@ export class BareIssueishDetailController extends React.Component { async checkout() { const {repository} = this.props; - const {issueish} = repository; - const {headRepository} = issueish; + const {pullRequest} = repository; + const {headRepository} = pullRequest; - const fullHeadRef = `refs/heads/${issueish.headRefName}`; + const fullHeadRef = `refs/heads/${pullRequest.headRefName}`; let sourceRemoteName, localRefName; @@ -200,10 +205,10 @@ export class BareIssueishDetailController extends React.Component { await this.props.fetch(fullHeadRef, {remoteName: sourceRemoteName}); // Check out the local ref and set it up to track the head ref. - await this.props.checkout(`pr-${issueish.number}/${headRepository.owner.login}/${issueish.headRefName}`, { + await this.props.checkout(`pr-${pullRequest.number}/${headRepository.owner.login}/${pullRequest.headRefName}`, { createNew: true, track: true, - startPoint: `refs/remotes/${sourceRemoteName}/${issueish.headRefName}`, + startPoint: `refs/remotes/${sourceRemoteName}/${pullRequest.headRefName}`, }); incrementCounter('checkout-pr'); @@ -226,12 +231,12 @@ export default createFragmentContainer(BareIssueishDetailController, { owner { login } - issueish: issueOrPullRequest(number: $issueishNumber) { + issue: issueOrPullRequest(number: $issueishNumber) { __typename ... on Issue { title number - ...issueDetailView_issueish @arguments( + ...issueDetailView_issue @arguments( timelineCount: $timelineCount, timelineCursor: $timelineCursor, commitCount: $commitCount, diff --git a/lib/views/__generated__/issueDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/issueDetailViewRefetchQuery.graphql.js index 6bb9113ca0..4264033230 100644 --- a/lib/views/__generated__/issueDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/issueDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 02f94074fbd53cdf8b87c5e9896a53b7 + * @relayHash 99b7f4f56ff728971b2c5939dc9ef2b5 */ /* eslint-disable */ @@ -9,7 +9,7 @@ /*:: import type { ConcreteRequest } from 'relay-runtime'; -type issueDetailView_issueish$ref = any; +type issueDetailView_issue$ref = any; type issueDetailView_repository$ref = any; export type issueDetailViewRefetchQueryVariables = {| repoId: string, @@ -21,8 +21,8 @@ export type issueDetailViewRefetchQueryResponse = {| +repository: ?{| +$fragmentRefs: issueDetailView_repository$ref |}, - +issueish: ?{| - +$fragmentRefs: issueDetailView_issueish$ref + +issue: ?{| + +$fragmentRefs: issueDetailView_issue$ref |}, |}; export type issueDetailViewRefetchQuery = {| @@ -44,9 +44,9 @@ query issueDetailViewRefetchQuery( ...issueDetailView_repository_3D8CP9 id } - issueish: node(id: $issueishId) { + issue: node(id: $issueishId) { __typename - ...issueDetailView_issueish_3D8CP9 + ...issueDetailView_issue_3D8CP9 id } } @@ -61,7 +61,7 @@ fragment issueDetailView_repository_3D8CP9 on Repository { } } -fragment issueDetailView_issueish_3D8CP9 on Issue { +fragment issueDetailView_issue_3D8CP9 on Issue { __typename ... on Node { id @@ -407,7 +407,7 @@ return { "operationKind": "query", "name": "issueDetailViewRefetchQuery", "id": null, - "text": "query issueDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueDetailView_repository_3D8CP9\n id\n }\n issueish: node(id: $issueishId) {\n __typename\n ...issueDetailView_issueish_3D8CP9\n id\n }\n}\n\nfragment issueDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issueish_3D8CP9 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", + "text": "query issueDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueDetailView_repository_3D8CP9\n id\n }\n issue: node(id: $issueishId) {\n __typename\n ...issueDetailView_issue_3D8CP9\n id\n }\n}\n\nfragment issueDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_3D8CP9 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_item\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitView_item on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -434,7 +434,7 @@ return { }, { "kind": "LinkedField", - "alias": "issueish", + "alias": "issue", "name": "node", "storageKey": null, "args": v3, @@ -443,7 +443,7 @@ return { "selections": [ { "kind": "FragmentSpread", - "name": "issueDetailView_issueish", + "name": "issueDetailView_issue", "args": v2 } ] @@ -478,7 +478,7 @@ return { }, { "kind": "LinkedField", - "alias": "issueish", + "alias": "issue", "name": "node", "storageKey": null, "args": v3, @@ -849,5 +849,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'ae08e0a6982589986e579be429b2a460'; +(node/*: any*/).hash = '82666b2748036545eb131b3e34f48e72'; module.exports = node; diff --git a/lib/views/__generated__/issueDetailView_issueish.graphql.js b/lib/views/__generated__/issueDetailView_issue.graphql.js similarity index 94% rename from lib/views/__generated__/issueDetailView_issueish.graphql.js rename to lib/views/__generated__/issueDetailView_issue.graphql.js index 0bd4f26326..3ccf457baf 100644 --- a/lib/views/__generated__/issueDetailView_issueish.graphql.js +++ b/lib/views/__generated__/issueDetailView_issue.graphql.js @@ -12,8 +12,8 @@ type issueTimelineController_issue$ref = any; export type IssueState = "CLOSED" | "OPEN" | "%future added value"; export type ReactionContent = "CONFUSED" | "HEART" | "HOORAY" | "LAUGH" | "THUMBS_DOWN" | "THUMBS_UP" | "%future added value"; import type { FragmentReference } from "relay-runtime"; -declare export opaque type issueDetailView_issueish$ref: FragmentReference; -export type issueDetailView_issueish = {| +declare export opaque type issueDetailView_issue$ref: FragmentReference; +export type issueDetailView_issue = {| +id?: string, +state: IssueState, +number: number, @@ -33,7 +33,7 @@ export type issueDetailView_issueish = {| |}>, +__typename: "Issue", +$fragmentRefs: issueTimelineController_issue$ref, - +$refType: issueDetailView_issueish$ref, + +$refType: issueDetailView_issue$ref, |}; */ @@ -51,7 +51,7 @@ v1 = [ ]; return { "kind": "Fragment", - "name": "issueDetailView_issueish", + "name": "issueDetailView_issue", "type": "Issue", "metadata": null, "argumentDefinitions": [ @@ -205,5 +205,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '4fbcc89822253448caa73ca5f5871c06'; +(node/*: any*/).hash = 'e1cf4b71a99cbade6149738c70451892'; module.exports = node; diff --git a/lib/views/issue-detail-view.js b/lib/views/issue-detail-view.js index 6b40dbc2cf..c57547287b 100644 --- a/lib/views/issue-detail-view.js +++ b/lib/views/issue-detail-view.js @@ -25,7 +25,7 @@ export class BareIssueDetailView extends React.Component { login: PropTypes.string, }), }), - issueish: PropTypes.shape({ + issue: PropTypes.shape({ __typename: PropTypes.string.isRequired, id: PropTypes.string.isRequired, title: PropTypes.string, @@ -63,7 +63,7 @@ export class BareIssueDetailView extends React.Component { componentDidMount() { this.refresher = new PeriodicRefresher(BareIssueDetailView, { interval: () => 5 * 60 * 1000, - getCurrentId: () => this.props.issueish.id, + getCurrentId: () => this.props.issue.id, refresh: this.refresh, minimumIntervalPerId: 2 * 60 * 1000, }); @@ -75,14 +75,14 @@ export class BareIssueDetailView extends React.Component { this.refresher.destroy(); } - renderIssueBody(issueish, childProps) { + renderIssueBody(issue, childProps) { return ( No description provided.'} + html={issue.bodyHTML || 'No description provided.'} switchToIssueish={this.props.switchToIssueish} /> - + @@ -105,14 +105,14 @@ export class BareIssueDetailView extends React.Component {
    - {this.renderIssueBody(issueish, childProps)} + {this.renderIssueBody(issue, childProps)} @@ -155,7 +155,7 @@ export class BareIssueDetailView extends React.Component { } recordOpenInBrowserEvent() { - addEvent('open-issueish-in-browser', {package: 'github', component: this.constructor.name}); + addEvent('open-issue-in-browser', {package: 'github', component: this.constructor.name}); } refresh() { @@ -166,7 +166,7 @@ export class BareIssueDetailView extends React.Component { this.setState({refreshing: true}); this.props.relay.refetch({ repoId: this.props.repository.id, - issueishId: this.props.issueish.id, + issueishId: this.props.issue.id, timelineCount: 100, timelineCursor: null, }, null, () => { @@ -186,8 +186,8 @@ export default createRefetchContainer(BareIssueDetailView, { } `, - issueish: graphql` - fragment issueDetailView_issueish on Issue + issue: graphql` + fragment issueDetailView_issue on Issue @argumentDefinitions( timelineCount: {type: "Int!"}, timelineCursor: {type: "String"}, @@ -233,8 +233,8 @@ export default createRefetchContainer(BareIssueDetailView, { ) } - issueish:node(id: $issueishId) { - ...issueDetailView_issueish @arguments( + issue:node(id: $issueishId) { + ...issueDetailView_issue @arguments( timelineCount: $timelineCount, timelineCursor: $timelineCursor, ) From 2aea51bbefcca13890909db6f72292ae413f9767 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 15:59:58 -0800 Subject: [PATCH 2103/4847] Fix CommitView tests --- lib/views/timeline-items/commit-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/timeline-items/commit-view.js b/lib/views/timeline-items/commit-view.js index 2b62988a01..6a0f9c4584 100644 --- a/lib/views/timeline-items/commit-view.js +++ b/lib/views/timeline-items/commit-view.js @@ -67,7 +67,7 @@ export class BareCommitView extends React.Component { dangerouslySetInnerHTML={{__html: commit.messageHeadlineHTML}} onClick={this.openCommitDetailItem} /> - {commit.sha.slice(0, 8)} + {commit.oid.slice(0, 8)}
    ); } From 2b8696aa885053129b6fe77200af721588afaf6a Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 16:27:49 -0800 Subject: [PATCH 2104/4847] Fix CommitDetailContainer test --- test/containers/commit-detail-container.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/containers/commit-detail-container.test.js b/test/containers/commit-detail-container.test.js index e4dff8718f..ac31fe34d5 100644 --- a/test/containers/commit-detail-container.test.js +++ b/test/containers/commit-detail-container.test.js @@ -35,6 +35,7 @@ describe('CommitDetailContainer', function() { config: atomEnv.config, destroy: () => {}, + surfaceCommit: () => {}, ...override, }; From 109c4d1045a89bd41fbd0ede0133067d94d72cc8 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 16:29:26 -0800 Subject: [PATCH 2105/4847] Fix GitStrategies test --- test/git-strategies.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 574dceadd4..39f909f891 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -163,7 +163,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; const workingDirPath = await cloneRepository('multiple-commits'); const git = createTestStrategy(workingDirPath); - const diffs = await git.getDiffForCommit('18920c90'); + const diffs = await git.getDiffsForCommit('18920c90'); assertDeepPropertyVals(diffs, [{ oldPath: 'file.txt', From 05845671b22ba368942560a037a44b86c853eae7 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 16:30:23 -0800 Subject: [PATCH 2106/4847] :fire: unnecessary focus test --- test/items/commit-detail-item.test.js | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/test/items/commit-detail-item.test.js b/test/items/commit-detail-item.test.js index eecbc66cf6..f86aab86e3 100644 --- a/test/items/commit-detail-item.test.js +++ b/test/items/commit-detail-item.test.js @@ -151,18 +151,4 @@ describe('CommitDetailItem', function() { assert.strictEqual(item.getWorkingDirectory(), '/dir7'); assert.strictEqual(item.getSha(), '420'); }); - - it('passes a focus() call to the component designated as its initial focus', async function() { - const wrapper = mount(buildPaneApp()); - const item = await open(wrapper); - wrapper.update(); - - const refHolder = wrapper.find('CommitDetailContainer').prop('refInitialFocus'); - const initialFocus = await refHolder.getPromise(); - sinon.spy(initialFocus, 'focus'); - - item.focus(); - - assert.isTrue(initialFocus.focus.called); - }); }); From dca78bc5a234000bc9d9e440d2952f369308a189 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 17:25:36 -0800 Subject: [PATCH 2107/4847] Fix HunkHeaderView test --- test/views/hunk-header-view.test.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/views/hunk-header-view.test.js b/test/views/hunk-header-view.test.js index 5bd0adf586..f408fc9067 100644 --- a/test/views/hunk-header-view.test.js +++ b/test/views/hunk-header-view.test.js @@ -120,12 +120,8 @@ describe('HunkHeaderView', function() { assert.isTrue(evt.stopPropagation.called); }); - it('does not render extra buttons when in a CommitPreviewItem or a CommitDetailItem', function() { - let wrapper = shallow(buildApp({itemType: CommitPreviewItem})); - assert.isFalse(wrapper.find('.github-HunkHeaderView-stageButton').exists()); - assert.isFalse(wrapper.find('.github-HunkHeaderView-discardButton').exists()); - - wrapper = shallow(buildApp({itemType: CommitDetailItem})); + it('does not render extra buttons when in a CommitDetailItem', function() { + const wrapper = shallow(buildApp({itemType: CommitDetailItem})); assert.isFalse(wrapper.find('.github-HunkHeaderView-stageButton').exists()); assert.isFalse(wrapper.find('.github-HunkHeaderView-discardButton').exists()); }); From 22754484b0f3333eab4452d16ac123c2c264b156 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 19:09:34 -0800 Subject: [PATCH 2108/4847] Fix GitTabView focus tests --- test/views/git-tab-view.test.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/test/views/git-tab-view.test.js b/test/views/git-tab-view.test.js index 5d07ce9b77..93710af685 100644 --- a/test/views/git-tab-view.test.js +++ b/test/views/git-tab-view.test.js @@ -153,15 +153,29 @@ describe('GitTabView', function() { stagingView = wrapper.prop('refStagingView').get(); event = {stopPropagation: sinon.spy()}; - sinon.stub(instance, 'setFocus'); + sinon.spy(instance, 'setFocus'); + }); + + it('focuses the enabled commit button if the recent commit view has focus', async function() { + const setFocus = sinon.spy(wrapper.find('CommitView').instance(), 'setFocus'); + + sinon.stub(instance, 'getFocus').returns(GitTabView.focus.RECENT_COMMIT); + sinon.stub(wrapper.find('CommitView').instance(), 'commitIsEnabled').returns(true); + + await wrapper.instance().retreatFocus(event); + + assert.isTrue(setFocus.calledWith(GitTabView.focus.COMMIT_BUTTON)); + assert.isTrue(event.stopPropagation.called); }); - it('focuses the commit button if the recent commit view has focus', async function() { + it('focuses the editor if the recent commit view has focus and the commit button is disabled', async function() { + const setFocus = sinon.spy(wrapper.find('CommitView').instance(), 'setFocus'); + sinon.stub(instance, 'getFocus').returns(GitTabView.focus.RECENT_COMMIT); await wrapper.instance().retreatFocus(event); - assert.isTrue(instance.setFocus.calledWith(GitTabView.focus.COMMIT_BUTTON)); + assert.isTrue(setFocus.calledWith(GitTabView.focus.EDITOR)); assert.isTrue(event.stopPropagation.called); }); From 75062d9071f3ceb7242e1aec1c6785bb4e37c27e Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 19:11:44 -0800 Subject: [PATCH 2109/4847] :shirt: --- test/views/hunk-header-view.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/views/hunk-header-view.test.js b/test/views/hunk-header-view.test.js index f408fc9067..837948f099 100644 --- a/test/views/hunk-header-view.test.js +++ b/test/views/hunk-header-view.test.js @@ -5,7 +5,6 @@ import HunkHeaderView from '../../lib/views/hunk-header-view'; import RefHolder from '../../lib/models/ref-holder'; import Hunk from '../../lib/models/patch/hunk'; import CommitDetailItem from '../../lib/items/commit-detail-item'; -import CommitPreviewItem from '../../lib/items/commit-preview-item'; describe('HunkHeaderView', function() { let atomEnv, hunk; From 54163061b9ec3852ea8ac7a6e8f2dd5a14574785 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 19:32:57 -0800 Subject: [PATCH 2110/4847] Add OpenCommitDialog tests --- test/views/open-commit-dialog.test.js | 83 +++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 test/views/open-commit-dialog.test.js diff --git a/test/views/open-commit-dialog.test.js b/test/views/open-commit-dialog.test.js new file mode 100644 index 0000000000..ef6a446880 --- /dev/null +++ b/test/views/open-commit-dialog.test.js @@ -0,0 +1,83 @@ +import React from 'react'; +import {mount} from 'enzyme'; +import path from 'path'; + +import OpenCommitDialog from '../../lib/views/open-commit-dialog'; + +describe('OpenCommitDialog', function() { + let atomEnv, config, commandRegistry; + let app, wrapper, didAccept, didCancel; + + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + config = atomEnv.config; + commandRegistry = atomEnv.commands; + sinon.stub(config, 'get').returns(path.join('home', 'me', 'codes')); + + didAccept = sinon.stub(); + didCancel = sinon.stub(); + + app = ( + + ); + wrapper = mount(app); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + const setTextIn = function(selector, text) { + wrapper.find(selector).getDOMNode().getModel().setText(text); + }; + + describe('entering a commit sha', function() { + it("updates the project path automatically if it hasn't been modified", function() { + setTextIn('.github-CommitSha atom-text-editor', 'asdf1234'); + + assert.equal(wrapper.instance().getCommitSha(), 'asdf1234'); + }); + + it('does update the sha if it was modified automatically', function() { + setTextIn('.github-CommitSha atom-text-editor', 'asdf1234'); + assert.equal(wrapper.instance().getCommitSha(), 'asdf1234'); + + setTextIn('.github-CommitSha atom-text-editor', 'zxcv5678'); + assert.equal(wrapper.instance().getCommitSha(), 'zxcv5678'); + }); + }); + + describe('open button enablement', function() { + it('disables the open button with no commit sha', function() { + setTextIn('.github-CommitSha atom-text-editor', ''); + wrapper.update(); + + assert.isTrue(wrapper.find('button.icon-commit').prop('disabled')); + }); + + it('enables the open button when commit sha box is populated', function() { + setTextIn('.github-CommitSha atom-text-editor', 'asdf1234'); + wrapper.update(); + + assert.isFalse(wrapper.find('button.icon-commit').prop('disabled')); + }); + }); + + it('calls the acceptance callback', function() { + setTextIn('.github-CommitSha atom-text-editor', 'asdf1234'); + + wrapper.find('button.icon-commit').simulate('click'); + + assert.isTrue(didAccept.calledWith({sha: 'asdf1234'})); + }); + + it('calls the cancellation callback', function() { + wrapper.find('button.github-CancelButton').simulate('click'); + assert.isTrue(didCancel.called); + }); +}); From 5aae2c5f679be7e76c9e80045f0b27863857e3f8 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 19:40:02 -0800 Subject: [PATCH 2111/4847] Clean up OpenCommitDialog test --- test/views/open-commit-dialog.test.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/views/open-commit-dialog.test.js b/test/views/open-commit-dialog.test.js index ef6a446880..7d4637015c 100644 --- a/test/views/open-commit-dialog.test.js +++ b/test/views/open-commit-dialog.test.js @@ -5,21 +5,18 @@ import path from 'path'; import OpenCommitDialog from '../../lib/views/open-commit-dialog'; describe('OpenCommitDialog', function() { - let atomEnv, config, commandRegistry; + let atomEnv, commandRegistry; let app, wrapper, didAccept, didCancel; beforeEach(function() { atomEnv = global.buildAtomEnvironment(); - config = atomEnv.config; commandRegistry = atomEnv.commands; - sinon.stub(config, 'get').returns(path.join('home', 'me', 'codes')); didAccept = sinon.stub(); didCancel = sinon.stub(); app = ( Date: Fri, 30 Nov 2018 19:52:37 -0800 Subject: [PATCH 2112/4847] :fire: unnecessary code in OpenCommitDialog --- lib/views/open-commit-dialog.js | 21 +-------------------- test/views/open-commit-dialog.test.js | 1 - 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/lib/views/open-commit-dialog.js b/lib/views/open-commit-dialog.js index 47ab2d3ec2..d81c8038d7 100644 --- a/lib/views/open-commit-dialog.js +++ b/lib/views/open-commit-dialog.js @@ -75,16 +75,7 @@ export default class OpenCommitDialog extends React.Component { return; } - const parsed = this.parseSha(); - if (!parsed) { - this.setState({ - error: 'That is not a valid commit sha.', - }); - return; - } - const {sha} = parsed; - - this.props.didAccept({sha}); + this.props.didAccept({sha: this.getCommitSha()}); } cancel() { @@ -122,16 +113,6 @@ export default class OpenCommitDialog extends React.Component { this.setState({error: null}); } - parseSha() { - const sha = this.getCommitSha(); - // const matches = url.match(ISSUEISH_URL_REGEX); - // if (!matches) { - // return false; - // } - // const [_full, repoOwner, repoName, issueishNumber] = matches; // eslint-disable-line no-unused-vars - return {sha}; - } - getCommitSha() { return this.commitShaEditor ? this.commitShaEditor.getText() : ''; } diff --git a/test/views/open-commit-dialog.test.js b/test/views/open-commit-dialog.test.js index 7d4637015c..067ba51dd4 100644 --- a/test/views/open-commit-dialog.test.js +++ b/test/views/open-commit-dialog.test.js @@ -1,6 +1,5 @@ import React from 'react'; import {mount} from 'enzyme'; -import path from 'path'; import OpenCommitDialog from '../../lib/views/open-commit-dialog'; From a71ce1494ec364bdd92753a90f17950e2dd8763a Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 19:53:16 -0800 Subject: [PATCH 2113/4847] Add tests for OpenIssueishDialog --- test/views/open-issueish-dialog.test.js | 95 +++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 test/views/open-issueish-dialog.test.js diff --git a/test/views/open-issueish-dialog.test.js b/test/views/open-issueish-dialog.test.js new file mode 100644 index 0000000000..b4caf29fe5 --- /dev/null +++ b/test/views/open-issueish-dialog.test.js @@ -0,0 +1,95 @@ +import React from 'react'; +import {mount} from 'enzyme'; + +import OpenIssueishDialog from '../../lib/views/open-issueish-dialog'; + +describe('OpenIssueishDialog', function() { + let atomEnv, commandRegistry; + let app, wrapper, didAccept, didCancel; + + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + commandRegistry = atomEnv.commands; + + didAccept = sinon.stub(); + didCancel = sinon.stub(); + + app = ( + + ); + wrapper = mount(app); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + const setTextIn = function(selector, text) { + wrapper.find(selector).getDOMNode().getModel().setText(text); + }; + + describe('entering a issueish url', function() { + it("updates the issue url automatically if it hasn't been modified", function() { + setTextIn('.github-IssueishUrl atom-text-editor', 'https://github.com/atom/github/pull/1807'); + + assert.equal(wrapper.instance().getIssueishUrl(), 'https://github.com/atom/github/pull/1807'); + }); + + it('does update the issue url if it was modified automatically', function() { + setTextIn('.github-IssueishUrl atom-text-editor', 'https://github.com/atom/github/pull/1807'); + assert.equal(wrapper.instance().getIssueishUrl(), 'https://github.com/atom/github/pull/1807'); + + setTextIn('.github-IssueishUrl atom-text-editor', 'https://github.com/atom/github/issues/1655'); + assert.equal(wrapper.instance().getIssueishUrl(), 'https://github.com/atom/github/issues/1655'); + }); + }); + + describe('open button enablement', function() { + it('disables the open button with no issue url', function() { + setTextIn('.github-IssueishUrl atom-text-editor', ''); + wrapper.update(); + + assert.isTrue(wrapper.find('button.icon-git-pull-request').prop('disabled')); + }); + + it('enables the open button when issue url box is populated', function() { + setTextIn('.github-IssueishUrl atom-text-editor', 'https://github.com/atom/github/pull/1807'); + wrapper.update(); + + assert.isFalse(wrapper.find('button.icon-git-pull-request').prop('disabled')); + }); + }); + + describe('parseUrl', function() { + it('returns an object with repo owner, repo name, and issueish number', function() { + setTextIn('.github-IssueishUrl atom-text-editor', 'https://github.com/atom/github/pull/1807'); + + assert.deepEqual(wrapper.instance().parseUrl(), { + repoOwner: 'atom', + repoName: 'github', + issueishNumber: '1807', + }); + }); + }); + + it('calls the acceptance callback', function() { + setTextIn('.github-IssueishUrl atom-text-editor', 'https://github.com/atom/github/pull/1807'); + + wrapper.find('button.icon-git-pull-request').simulate('click'); + + assert.isTrue(didAccept.calledWith({ + repoOwner: 'atom', + repoName: 'github', + issueishNumber: '1807', + })); + }); + + it('calls the cancellation callback', function() { + wrapper.find('button.github-CancelButton').simulate('click'); + assert.isTrue(didCancel.called); + }); +}); From 5d90e5bee91f5cd3d8a391ac7d5e6b5308607f2a Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 30 Nov 2018 20:02:39 -0800 Subject: [PATCH 2114/4847] :fire: unnecessary check for commit sha. Handled by disabled button --- lib/views/open-commit-dialog.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/views/open-commit-dialog.js b/lib/views/open-commit-dialog.js index d81c8038d7..ba9c1ad488 100644 --- a/lib/views/open-commit-dialog.js +++ b/lib/views/open-commit-dialog.js @@ -71,10 +71,6 @@ export default class OpenCommitDialog extends React.Component { } accept() { - if (this.getCommitSha().length === 0) { - return; - } - this.props.didAccept({sha: this.getCommitSha()}); } From f3f392da2b4b2821eee6bfada2f5fce6b084343d Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 3 Dec 2018 16:42:09 +0100 Subject: [PATCH 2115/4847] unneccessary prop --- lib/controllers/issueish-detail-controller.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index 4267f3b46f..4485e4b1f6 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -17,7 +17,6 @@ export class BareIssueishDetailController extends React.Component { login: PropTypes.string.isRequired, }).isRequired, issueish: PropTypes.any, // FIXME from IssueishPaneItemContainer.propTypes - getWorkingDirectoryPath: PropTypes.func.isRequired, }), issueishNumber: PropTypes.number.isRequired, From a830581f44c762ea7c326d0080afc6a948ed83c3 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 3 Dec 2018 16:42:24 +0100 Subject: [PATCH 2116/4847] get boolean properly --- lib/views/issueish-detail-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/issueish-detail-view.js b/lib/views/issueish-detail-view.js index 27312dff45..46752c4062 100644 --- a/lib/views/issueish-detail-view.js +++ b/lib/views/issueish-detail-view.js @@ -146,7 +146,7 @@ export class BareIssueishDetailView extends React.Component { renderPullRequestBody(issueish, childProps) { const {checkoutOp} = this.props; const reason = checkoutOp.why(); - const onBranch = reason && !reason({hidden: true, default: false}); // is there a more direct way than this? + const onBranch = !!reason && !reason({hidden: true, default: false}); // is there a more direct way than this? return ( From d5fa6506416f03a8a1fe31f6d767e69c81b80ff3 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 3 Dec 2018 17:08:33 +0100 Subject: [PATCH 2117/4847] sha not oid --- lib/views/timeline-items/commit-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/timeline-items/commit-view.js b/lib/views/timeline-items/commit-view.js index 6a0f9c4584..2b62988a01 100644 --- a/lib/views/timeline-items/commit-view.js +++ b/lib/views/timeline-items/commit-view.js @@ -67,7 +67,7 @@ export class BareCommitView extends React.Component { dangerouslySetInnerHTML={{__html: commit.messageHeadlineHTML}} onClick={this.openCommitDetailItem} /> - {commit.oid.slice(0, 8)} + {commit.sha.slice(0, 8)}
    ); } From 28dd5ce4e1680ac4637436eb8c8874c58d2202ff Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 3 Dec 2018 17:19:21 +0100 Subject: [PATCH 2118/4847] sha not oid x2 --- test/views/timeline-items/commit-view.test.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/views/timeline-items/commit-view.test.js b/test/views/timeline-items/commit-view.test.js index 8cb5445f8e..6baa9fcc92 100644 --- a/test/views/timeline-items/commit-view.test.js +++ b/test/views/timeline-items/commit-view.test.js @@ -19,7 +19,7 @@ describe('CommitView', function() { login: 'committer_login', }, }, - oid: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', + sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', message: 'commit message', messageHeadlineHTML: '

    html

    ', commitURL: 'https://github.com/aaa/bbb/commit/123abc', @@ -44,7 +44,7 @@ describe('CommitView', function() { name: 'committer_name', avatarUrl: '', user: null, }, - oid: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', + sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', authoredByCommitter: false, message: 'commit message', messageHeadlineHTML: '

    html

    ', @@ -72,7 +72,7 @@ describe('CommitView', function() { name: 'author_name', avatarUrl: '', user: null, }, - oid: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', + sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', authoredByCommitter: true, message: 'commit message', messageHeadlineHTML: '

    html

    ', @@ -100,7 +100,7 @@ describe('CommitView', function() { name: 'GitHub', avatarUrl: '', user: null, }, - oid: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', + sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', authoredByCommitter: false, message: 'commit message', messageHeadlineHTML: '

    html

    ', @@ -128,7 +128,7 @@ describe('CommitView', function() { name: 'Someone', email: 'noreply@github.com', avatarUrl: '', user: null, }, - oid: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', + sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', authoredByCommitter: false, message: 'commit message', messageHeadlineHTML: '

    html

    ', @@ -158,7 +158,7 @@ describe('CommitView', function() { login: 'committer_login', }, }, - oid: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', + sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', authoredByCommitter: false, message: 'commit message', messageHeadlineHTML: '

    html

    ', @@ -186,7 +186,7 @@ describe('CommitView', function() { name: 'author_name', avatarUrl: '', user: null, }, - oid: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', + sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', authoredByCommitter: true, message: 'full message', messageHeadlineHTML: '

    html

    ', @@ -211,7 +211,7 @@ describe('CommitView', function() { name: 'author_name', avatarUrl: '', user: null, }, - oid: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', + sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', authoredByCommitter: true, message: 'full message', messageHeadlineHTML: '

    inner HTML

    ', @@ -234,7 +234,7 @@ describe('CommitView', function() { name: 'author_name', avatarUrl: '', user: null, }, - oid: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', + sha: 'e6c80aa37dc6f7a5e5491e0ed6e00ec2c812b1a5', authoredByCommitter: true, message: 'full message', messageHeadlineHTML: '

    inner HTML

    ', From 24a5fae814569a8f8e90aa6928b4c3bc03f691d2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 3 Dec 2018 11:37:32 -0500 Subject: [PATCH 2119/4847] Test coverate for RecentCommitController's workspace tracking --- .../recent-commits-controller.test.js | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/controllers/recent-commits-controller.test.js b/test/controllers/recent-commits-controller.test.js index afe5780bb0..9e345ab931 100644 --- a/test/controllers/recent-commits-controller.test.js +++ b/test/controllers/recent-commits-controller.test.js @@ -2,6 +2,8 @@ import React from 'react'; import {shallow, mount} from 'enzyme'; import RecentCommitsController from '../../lib/controllers/recent-commits-controller'; +import CommitDetailItem from '../../lib/items/commit-detail-item'; +import URIPattern from '../../lib/atom/uri-pattern'; import {commitBuilder} from '../builder/commit'; import {cloneRepository, buildRepository} from '../helpers'; import * as reporterProxy from '../../lib/reporter-proxy'; @@ -162,4 +164,37 @@ describe('RecentCommitsController', function() { await wrapper.instance().retreatFocusFrom(RecentCommitsController.focus.RECENT_COMMIT); assert.isTrue(retreatFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT)); }); + + describe('workspace tracking', function() { + beforeEach(function() { + const pattern = new URIPattern(CommitDetailItem.uriPattern); + // Prevent the Workspace from normalizing CommitDetailItem URIs + atomEnv.workspace.addOpener(uri => { + if (pattern.matches(uri).ok()) { + return { + getURI() { return uri; }, + }; + } + return undefined; + }); + }); + + it('updates the selected sha when its CommitDetailItem is activated', async function() { + const wrapper = shallow(app); + await atomEnv.workspace.open(CommitDetailItem.buildURI(workdirPath, 'abcdef')); + assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), 'abcdef'); + }); + + it('silently disregards items with no getURI method', async function() { + const wrapper = shallow(app); + await atomEnv.workspace.open({item: {}}); + assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), ''); + }); + + it('silently disregards items that do not match the CommitDetailItem URI pattern', async function() { + const wrapper = shallow(app); + await atomEnv.workspace.open(__filename); + assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), ''); + }); + }); }); From 8afc601eb993d0504ea10ae098d5c23ff05d1cb3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 3 Dec 2018 11:57:50 -0500 Subject: [PATCH 2120/4847] Full coverage for RecentCommitsController --- .../recent-commits-controller.test.js | 69 +++++++++++++++---- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/test/controllers/recent-commits-controller.test.js b/test/controllers/recent-commits-controller.test.js index 9e345ab931..e70d003cd1 100644 --- a/test/controllers/recent-commits-controller.test.js +++ b/test/controllers/recent-commits-controller.test.js @@ -144,25 +144,66 @@ describe('RecentCommitsController', function() { }); }); - it('forwards focus management methods to its view', async function() { - const wrapper = mount(app); + describe('focus management', function() { + it('forwards focus management methods to its view', async function() { + const wrapper = mount(app); + + const setFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'setFocus'); + const rememberFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'getFocus'); + const advanceFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'advanceFocusFrom'); + const retreatFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'retreatFocusFrom'); + + wrapper.instance().setFocus(RecentCommitsController.focus.RECENT_COMMIT); + assert.isTrue(setFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT)); + + wrapper.instance().getFocus(document.body); + assert.isTrue(rememberFocusSpy.calledWith(document.body)); - const setFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'setFocus'); - const rememberFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'getFocus'); - const advanceFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'advanceFocusFrom'); - const retreatFocusSpy = sinon.spy(wrapper.find('RecentCommitsView').instance(), 'retreatFocusFrom'); + await wrapper.instance().advanceFocusFrom(RecentCommitsController.focus.RECENT_COMMIT); + assert.isTrue(advanceFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT)); - wrapper.instance().setFocus(RecentCommitsController.focus.RECENT_COMMIT); - assert.isTrue(setFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT)); + await wrapper.instance().retreatFocusFrom(RecentCommitsController.focus.RECENT_COMMIT); + assert.isTrue(retreatFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT)); + }); + + it('selects the first commit when focus enters the component', async function() { + const commits = ['0', '1', '2'].map(s => commitBuilder().sha(s).build()); + const wrapper = mount(React.cloneElement(app, {commits, selectedCommitSha: ''})); + const stateSpy = sinon.spy(wrapper.instance(), 'setSelectedCommitIndex'); + sinon.stub(wrapper.find('RecentCommitsView').instance(), 'setFocus').returns(true); - wrapper.instance().getFocus(document.body); - assert.isTrue(rememberFocusSpy.calledWith(document.body)); + assert.isTrue(wrapper.instance().setFocus(RecentCommitsController.focus.RECENT_COMMIT)); + assert.isTrue(stateSpy.called); + await stateSpy.lastCall.returnValue; + wrapper.update(); + + assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '0'); + }); - await wrapper.instance().advanceFocusFrom(RecentCommitsController.focus.RECENT_COMMIT); - assert.isTrue(advanceFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT)); + it('leaves an existing commit selection alone', function() { + const commits = ['0', '1', '2'].map(s => commitBuilder().sha(s).build()); + const wrapper = mount(React.cloneElement(app, {commits})); + wrapper.setState({selectedCommitSha: '2'}); + const stateSpy = sinon.spy(wrapper.instance(), 'setSelectedCommitIndex'); + sinon.stub(wrapper.find('RecentCommitsView').instance(), 'setFocus').returns(true); - await wrapper.instance().retreatFocusFrom(RecentCommitsController.focus.RECENT_COMMIT); - assert.isTrue(retreatFocusSpy.calledWith(RecentCommitsController.focus.RECENT_COMMIT)); + assert.isTrue(wrapper.instance().setFocus(RecentCommitsController.focus.RECENT_COMMIT)); + assert.isFalse(stateSpy.called); + + assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), '2'); + }); + + it('disregards an unrecognized focus', function() { + const commits = ['0', '1', '2'].map(s => commitBuilder().sha(s).build()); + const wrapper = mount(React.cloneElement(app, {commits, selectedCommitSha: ''})); + const stateSpy = sinon.spy(wrapper.instance(), 'setSelectedCommitIndex'); + sinon.stub(wrapper.find('RecentCommitsView').instance(), 'setFocus').returns(false); + + assert.isFalse(wrapper.instance().setFocus(Symbol('unrecognized'))); + assert.isFalse(stateSpy.called); + + assert.strictEqual(wrapper.find('RecentCommitsView').prop('selectedCommitSha'), ''); + }); }); describe('workspace tracking', function() { From 9de4e04a95fcaff759e54e0eaad9543677b57478 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 3 Dec 2018 10:24:30 -0800 Subject: [PATCH 2121/4847] remove `childProps` from `IssueDetailView` --- lib/views/issue-detail-view.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/views/issue-detail-view.js b/lib/views/issue-detail-view.js index c57547287b..a696ffacea 100644 --- a/lib/views/issue-detail-view.js +++ b/lib/views/issue-detail-view.js @@ -75,7 +75,7 @@ export class BareIssueDetailView extends React.Component { this.refresher.destroy(); } - renderIssueBody(issue, childProps) { + renderIssueBody(issue) { return ( @@ -94,10 +94,6 @@ export class BareIssueDetailView extends React.Component { render() { const repo = this.props.repository; const issue = this.props.issue; - const childProps = { - issue: issue.__typename === 'Issue' ? issue : null, - pullRequest: issue.__typename === 'PullRequest' ? issue : null, - }; return (
    @@ -136,7 +132,7 @@ export class BareIssueDetailView extends React.Component {
    - {this.renderIssueBody(issue, childProps)} + {this.renderIssueBody(issue)}
    - {this.renderPullRequestBody(pullRequest, childProps)} + {this.renderPullRequestBody(pullRequest)}
    From 52623a179dcfe1be6766c5e1c9e09ba9fbdf90a1 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 13 Dec 2018 13:02:52 -0800 Subject: [PATCH 2313/4847] add test for when fetch fails --- .../pr-changed-files-container.test.js | 111 ++++++++++-------- 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/test/containers/pr-changed-files-container.test.js b/test/containers/pr-changed-files-container.test.js index 6b0a24c3ea..e43ebcb225 100644 --- a/test/containers/pr-changed-files-container.test.js +++ b/test/containers/pr-changed-files-container.test.js @@ -21,6 +21,14 @@ describe('PullRequestChangedFilesContainer', function() { token="1234" endpoint={getEndpoint('github.com')} itemType={IssueishDetailItem} + destroy={() => {}} + shouldRefetch={false} + workspace={{}} + commands={{}} + keymaps={{}} + tooltips={{}} + config={{}} + localRepository={{}} {...overrideProps} /> ); @@ -33,58 +41,69 @@ describe('PullRequestChangedFilesContainer', function() { }); } - beforeEach(function() { - setDiffResponse(rawDiff); - sinon.stub(window, 'fetch').callsFake(() => Promise.resolve(diffResponse)); - }); - - it('renders a loading spinner if data has not yet been fetched', function() { - const wrapper = shallow(buildApp()); - assert.isTrue(wrapper.find('LoadingView').exists()); - }); - - it('passes extra props through to PullRequestChangedFilesController', async function() { - const extraProp = Symbol('really really extra'); - - const wrapper = shallow(buildApp({extraProp})); - await assert.async.isTrue(wrapper.update().find('MultiFilePatchController').exists()); - - const controller = wrapper.find('MultiFilePatchController'); - assert.strictEqual(controller.prop('extraProp'), extraProp); - }); + describe('when the data is able to be fetched successfully', function() { + beforeEach(function() { + setDiffResponse(rawDiff); + sinon.stub(window, 'fetch').callsFake(() => Promise.resolve(diffResponse)); + }); + it('renders a loading spinner if data has not yet been fetched', function() { + const wrapper = shallow(buildApp()); + assert.isTrue(wrapper.find('LoadingView').exists()); + }); + it('passes extra props through to PullRequestChangedFilesController', async function() { + const extraProp = Symbol('really really extra'); - it('builds the diff URL', function() { - const wrapper = shallow(buildApp({ - owner: 'smashwilson', - repo: 'pushbot', - number: 12, - endpoint: getEndpoint('github.com'), - })); + const wrapper = shallow(buildApp({extraProp})); + await assert.async.isTrue(wrapper.update().find('MultiFilePatchController').exists()); - const diffURL = wrapper.instance().getDiffURL(); - assert.strictEqual(diffURL, 'https://api.github.com/repos/smashwilson/pushbot/pulls/12'); - }); + const controller = wrapper.find('MultiFilePatchController'); + assert.strictEqual(controller.prop('extraProp'), extraProp); + }); - it('passes loaded diff data through to the controller', async function() { - const wrapper = shallow(buildApp({ - token: '4321', - })); - await assert.async.isTrue(wrapper.update().find('MultiFilePatchController').exists()); + it('builds the diff URL', function() { + const wrapper = shallow(buildApp({ + owner: 'smashwilson', + repo: 'pushbot', + number: 12, + endpoint: getEndpoint('github.com'), + })); - const controller = wrapper.find('MultiFilePatchController'); - const expected = buildMultiFilePatch(parseDiff(rawDiff)); - assert.isTrue(controller.prop('multiFilePatch').isEqual(expected)); + const diffURL = wrapper.instance().getDiffURL(); + assert.strictEqual(diffURL, 'https://api.github.com/repos/smashwilson/pushbot/pulls/12'); + }); - assert.deepEqual(window.fetch.lastCall.args, [ - 'https://api.github.com/repos/atom/github/pulls/1804', - { - headers: { - Accept: 'application/vnd.github.v3.diff', - Authorization: 'bearer 4321', + it('passes loaded diff data through to the controller', async function() { + const wrapper = shallow(buildApp({ + token: '4321', + })); + await assert.async.isTrue(wrapper.update().find('MultiFilePatchController').exists()); + + const controller = wrapper.find('MultiFilePatchController'); + const expected = buildMultiFilePatch(parseDiff(rawDiff)); + assert.isTrue(controller.prop('multiFilePatch').isEqual(expected)); + + assert.deepEqual(window.fetch.lastCall.args, [ + 'https://api.github.com/repos/atom/github/pulls/1804', + { + headers: { + Accept: 'application/vnd.github.v3.diff', + Authorization: 'bearer 4321', + }, }, - }, - ]); + ]); + }); }); - it('renders an error if fetch returns a non-ok response'); + describe('when fetch fails', function() { + it('renders an error if fetch returns a non-ok response', async function() { + const badResponse = new window.Response(rawDiff, { + status: 404, + statusText: 'oh noes', + headers: {'Content-type': 'text/plain'}, + }); + sinon.stub(window, 'fetch').callsFake(() => Promise.resolve(badResponse)); + const wrapper = shallow(buildApp()); + await assert.async.strictEqual(wrapper.update().instance().state.error, 'Unable to load diff for this PR.'); + }); + }); }); From 7f8707d9e33c50350cf0e2873154368bc9650e84 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 13 Dec 2018 22:17:19 +0100 Subject: [PATCH 2314/4847] update component atlas --- docs/react-component-atlas.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/react-component-atlas.md b/docs/react-component-atlas.md index a619d910d8..fe8264a752 100644 --- a/docs/react-component-atlas.md +++ b/docs/react-component-atlas.md @@ -118,6 +118,13 @@ This is a high-level overview of the structure of the React component tree that > > > [``](/lib/views/pr-commit-view.js) > > > > > > Enumerate the commits associated with a pull request. +> > +> > > [``](/lib/containers/pr-changed-files-container.js) +> > > +> > > Show all the changes, separated by files, introduced in a pull request. +> > > +> > > > [``](/lib/controllers/multi-file-patch-controller.js) +> > > > [``](/lib/views/multi-file-patch-view.js) > > > [``](/lib/views/init-dialog.js) > > [``](/lib/views/clone-dialog.js) From 18a89737fa2e811b197bad073d1c4438e65e5262 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 13 Dec 2018 13:36:39 -0800 Subject: [PATCH 2315/4847] fix test to deal with improved error handling --- lib/containers/pr-changed-files-container.js | 2 +- test/containers/pr-changed-files-container.test.js | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/containers/pr-changed-files-container.js b/lib/containers/pr-changed-files-container.js index 95cccfbb9d..09e65a360f 100644 --- a/lib/containers/pr-changed-files-container.js +++ b/lib/containers/pr-changed-files-container.js @@ -84,7 +84,7 @@ export default class PullRequestChangedFilesContainer extends React.Component { const multiFilePatch = this.buildPatch(rawDiff); await new Promise(resolve => this.setState({isLoading: false, multiFilePatch}, resolve)); } else { - diffError(`Unable to fetch diff for this pull request${response ? ' : ' + response.statusText : ''}.`); + diffError(`Unable to fetch diff for this pull request${response ? ': ' + response.statusText : ''}.`); } } catch (e) { diffError('Unable to parse diff for this pull request.'); diff --git a/test/containers/pr-changed-files-container.test.js b/test/containers/pr-changed-files-container.test.js index e43ebcb225..e6d002971f 100644 --- a/test/containers/pr-changed-files-container.test.js +++ b/test/containers/pr-changed-files-container.test.js @@ -94,7 +94,7 @@ describe('PullRequestChangedFilesContainer', function() { }); }); - describe('when fetch fails', function() { + describe.only('when fetch fails', function() { it('renders an error if fetch returns a non-ok response', async function() { const badResponse = new window.Response(rawDiff, { status: 404, @@ -103,7 +103,10 @@ describe('PullRequestChangedFilesContainer', function() { }); sinon.stub(window, 'fetch').callsFake(() => Promise.resolve(badResponse)); const wrapper = shallow(buildApp()); - await assert.async.strictEqual(wrapper.update().instance().state.error, 'Unable to load diff for this PR.'); + const expectedErrorMessage = 'Unable to fetch diff for this pull request: oh noes.'; + await assert.async.deepEqual(wrapper.update().instance().state.error, expectedErrorMessage); + const errorView = wrapper.find('ErrorView'); + assert.deepEqual(errorView.prop('descriptions'), [expectedErrorMessage]); }); }); }); From 66e5a62cb41bb3dee097ca480e67d1c8b0b55f49 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 13 Dec 2018 13:41:17 -0800 Subject: [PATCH 2316/4847] :shirt: --- .../pr-changed-files-container.test.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/containers/pr-changed-files-container.test.js b/test/containers/pr-changed-files-container.test.js index e6d002971f..d45c2aa4e7 100644 --- a/test/containers/pr-changed-files-container.test.js +++ b/test/containers/pr-changed-files-container.test.js @@ -94,19 +94,19 @@ describe('PullRequestChangedFilesContainer', function() { }); }); - describe.only('when fetch fails', function() { + describe('when fetch fails', function() { it('renders an error if fetch returns a non-ok response', async function() { - const badResponse = new window.Response(rawDiff, { - status: 404, - statusText: 'oh noes', - headers: {'Content-type': 'text/plain'}, - }); - sinon.stub(window, 'fetch').callsFake(() => Promise.resolve(badResponse)); - const wrapper = shallow(buildApp()); - const expectedErrorMessage = 'Unable to fetch diff for this pull request: oh noes.'; - await assert.async.deepEqual(wrapper.update().instance().state.error, expectedErrorMessage); - const errorView = wrapper.find('ErrorView'); - assert.deepEqual(errorView.prop('descriptions'), [expectedErrorMessage]); + const badResponse = new window.Response(rawDiff, { + status: 404, + statusText: 'oh noes', + headers: {'Content-type': 'text/plain'}, }); + sinon.stub(window, 'fetch').callsFake(() => Promise.resolve(badResponse)); + const wrapper = shallow(buildApp()); + const expectedErrorMessage = 'Unable to fetch diff for this pull request: oh noes.'; + await assert.async.deepEqual(wrapper.update().instance().state.error, expectedErrorMessage); + const errorView = wrapper.find('ErrorView'); + assert.deepEqual(errorView.prop('descriptions'), [expectedErrorMessage]); + }); }); }); From aa5f337e75f72c07d2b4adf1e401904ea7ff126d Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 13 Dec 2018 14:00:07 -0800 Subject: [PATCH 2317/4847] test diff parsing error state --- .../pr-changed-files-container.test.js | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/test/containers/pr-changed-files-container.test.js b/test/containers/pr-changed-files-container.test.js index d45c2aa4e7..005baed4f9 100644 --- a/test/containers/pr-changed-files-container.test.js +++ b/test/containers/pr-changed-files-container.test.js @@ -94,7 +94,20 @@ describe('PullRequestChangedFilesContainer', function() { }); }); - describe('when fetch fails', function() { + describe('error states', function() { + async function assertErrorRendered(expectedErrorMessage, wrapper) { + await assert.async.deepEqual(wrapper.update().instance().state.error, expectedErrorMessage); + const errorView = wrapper.find('ErrorView'); + assert.deepEqual(errorView.prop('descriptions'), [expectedErrorMessage]); + } + it('renders an error if diff parsing fails', async function() { + setDiffResponse('bad diff no treat for you'); + sinon.stub(window, 'fetch').callsFake(() => Promise.resolve(diffResponse)); + const wrapper = shallow(buildApp()); + const expectedErrorMessage = 'Unable to parse diff for this pull request.'; + await assertErrorRendered('Unable to parse diff for this pull request.', wrapper); + }); + it('renders an error if fetch returns a non-ok response', async function() { const badResponse = new window.Response(rawDiff, { status: 404, @@ -103,10 +116,7 @@ describe('PullRequestChangedFilesContainer', function() { }); sinon.stub(window, 'fetch').callsFake(() => Promise.resolve(badResponse)); const wrapper = shallow(buildApp()); - const expectedErrorMessage = 'Unable to fetch diff for this pull request: oh noes.'; - await assert.async.deepEqual(wrapper.update().instance().state.error, expectedErrorMessage); - const errorView = wrapper.find('ErrorView'); - assert.deepEqual(errorView.prop('descriptions'), [expectedErrorMessage]); + await assertErrorRendered('Unable to fetch diff for this pull request: oh noes.', wrapper); }); }); }); From 424b5c41b9ba71b11829342abca7953ad4903eca Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 13 Dec 2018 14:40:13 -0800 Subject: [PATCH 2318/4847] :shirt: againnn --- test/containers/pr-changed-files-container.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/containers/pr-changed-files-container.test.js b/test/containers/pr-changed-files-container.test.js index 005baed4f9..78a98d1a71 100644 --- a/test/containers/pr-changed-files-container.test.js +++ b/test/containers/pr-changed-files-container.test.js @@ -104,7 +104,6 @@ describe('PullRequestChangedFilesContainer', function() { setDiffResponse('bad diff no treat for you'); sinon.stub(window, 'fetch').callsFake(() => Promise.resolve(diffResponse)); const wrapper = shallow(buildApp()); - const expectedErrorMessage = 'Unable to parse diff for this pull request.'; await assertErrorRendered('Unable to parse diff for this pull request.', wrapper); }); From 879c6389a4fbe461faf8c225c9a4c3388e8bdd4f Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 13 Dec 2018 14:47:27 -0800 Subject: [PATCH 2319/4847] istanbul ignore dev debugging code to log rate limits --- lib/relay-network-layer-manager.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index fd6abf2861..f378fc9624 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -105,6 +105,7 @@ function createFetchQuery(url) { }); try { + /* istanbul ignore next */ atom && atom.inDevMode() && logRatelimitApi(response.headers); } catch (_e) { /* do nothing */ } From aeae3b35e2a4b92667d5842ceb2cf8da054a81f1 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 13 Dec 2018 16:03:10 -0800 Subject: [PATCH 2320/4847] add test for refetching data --- test/containers/pr-changed-files-container.test.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/containers/pr-changed-files-container.test.js b/test/containers/pr-changed-files-container.test.js index 78a98d1a71..c6f972dce7 100644 --- a/test/containers/pr-changed-files-container.test.js +++ b/test/containers/pr-changed-files-container.test.js @@ -92,7 +92,15 @@ describe('PullRequestChangedFilesContainer', function() { }, ]); }); - }); + it('re fetches data when shouldRefetch is true', async function() { + const wrapper = shallow(buildApp()); + await assert.async.isTrue(wrapper.update().find('MultiFilePatchController').exists()); + assert.strictEqual(window.fetch.callCount, 1); + wrapper.setProps({shouldRefetch: true}); + assert.isTrue(wrapper.instance().state.isLoading); + await assert.async.strictEqual(window.fetch.callCount, 2); + }); + }); describe('error states', function() { async function assertErrorRendered(expectedErrorMessage, wrapper) { From 714ec4b2f3696a4369766b138279f8b55e988044 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 13 Dec 2018 16:10:30 -0800 Subject: [PATCH 2321/4847] more istanbul ignoring --- lib/prop-types.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/prop-types.js b/lib/prop-types.js index bb3a298687..78fd797320 100644 --- a/lib/prop-types.js +++ b/lib/prop-types.js @@ -180,6 +180,7 @@ function createItemTypePropType(required) { } if (props[propName] === undefined || props[propName] === null) { + /* istanbul ignore else */ if (required) { return new Error(`Missing required prop ${propName} on component ${componentName}.`); } else { @@ -187,6 +188,7 @@ function createItemTypePropType(required) { } } + /* istanbul ignore if */ if (!lazyItemConstructors.has(props[propName])) { const choices = Array.from(lazyItemConstructors, each => each.name).join(', '); return new Error( From d5a0f630ceb8907110c934f7a4d48aa4ac10e07c Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 14 Dec 2018 11:41:19 +0900 Subject: [PATCH 2322/4847] Fix PrTimeline scrolling issues --- styles/pr-timeline.less | 1 + 1 file changed, 1 insertion(+) diff --git a/styles/pr-timeline.less b/styles/pr-timeline.less index 99c4e8f9f0..8a636612a5 100644 --- a/styles/pr-timeline.less +++ b/styles/pr-timeline.less @@ -3,6 +3,7 @@ @avatar-size: 20px; .github-PrTimeline { + position: relative; margin-top: @component-padding * 3; border-top: 1px solid mix(@text-color, @base-background-color, 15%); From d84707e0e41e0de254ed3994c381da74b7f8ca10 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 14 Dec 2018 19:57:30 +0900 Subject: [PATCH 2323/4847] Make header more compact --- lib/views/pr-detail-view.js | 97 +++++++++++++++--------------- styles/github-dotcom-markdown.less | 7 +++ styles/issueish-detail-view.less | 91 ++++++++++++++-------------- styles/pr-commit-view.less | 4 +- styles/pr-statuses.less | 1 - styles/pr-timeline.less | 19 +++--- 6 files changed, 111 insertions(+), 108 deletions(-) diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index bd9d9a8083..62dc2510c9 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -120,21 +120,20 @@ export class BarePullRequestDetailView extends React.Component { } renderPrMetadata(pullRequest, repo) { + // TODO: Move these infos to the tabs. E.g. Commits (3) + // {pullRequest.author.login} wants to merge{' '} + // {pullRequest.countedCommits.totalCount} commits and{' '} + // {pullRequest.changedFiles} changed files into{' '} return ( -
    - - {pullRequest.author.login} wants to merge{' '} - {pullRequest.countedCommits.totalCount} commits and{' '} - {pullRequest.changedFiles} changed files into{' '} - {pullRequest.isCrossRepository ? - `${repo.owner.login}/${pullRequest.baseRefName}` : pullRequest.baseRefName} from{' '} - {pullRequest.isCrossRepository ? - `${pullRequest.author.login}/${pullRequest.headRefName}` : pullRequest.headRefName} - -
    + + {pullRequest.isCrossRepository ? + `${repo.owner.login}/${pullRequest.baseRefName}` : pullRequest.baseRefName}{' ‹ '} + {pullRequest.isCrossRepository ? + `${pullRequest.author.login}/${pullRequest.headRefName}` : pullRequest.headRefName} + ); } @@ -167,18 +166,19 @@ export class BarePullRequestDetailView extends React.Component { {/* overview */} - No description provided.'} - switchToIssueish={this.props.switchToIssueish} - /> - - - +
    + No description provided.'} + switchToIssueish={this.props.switchToIssueish} + /> + + +
    {/* build status */} @@ -230,32 +230,30 @@ export class BarePullRequestDetailView extends React.Component {
    -
    + {this.renderPullRequestBody(pullRequest)}
    -
    +
    @@ -256,6 +256,8 @@ export class BarePullRequestDetailView extends React.Component { +
    +
    {this.renderPrMetadata(pullRequest, repo)}
    diff --git a/styles/issueish-detail-view.less b/styles/issueish-detail-view.less index e33131af99..b6ed2f685c 100644 --- a/styles/issueish-detail-view.less +++ b/styles/issueish-detail-view.less @@ -41,12 +41,18 @@ &-headerColumn { &.is-flexible { flex: 1; + display: flex; + flex-wrap: wrap; } } &-headerRow { display: flex; align-items: center; + margin: 2px 0; + &.is-fullwidth { + flex: 1 1 100%; + } } // Avatar ------------------------ @@ -57,7 +63,7 @@ } &-title { - margin: 0 0 .25em 0; + margin: 0; font-size: 1.25em; font-weight: 500; line-height: 1.3; From 3d5018aa2762f92dbe2dc462ba92874cbbc3bc32 Mon Sep 17 00:00:00 2001 From: simurai Date: Mon, 17 Dec 2018 16:51:22 +0900 Subject: [PATCH 2348/4847] Make headerLink wrap --- styles/issueish-detail-view.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/styles/issueish-detail-view.less b/styles/issueish-detail-view.less index b6ed2f685c..1f35fb3d2e 100644 --- a/styles/issueish-detail-view.less +++ b/styles/issueish-detail-view.less @@ -49,6 +49,7 @@ &-headerRow { display: flex; align-items: center; + flex-wrap: wrap; margin: 2px 0; &.is-fullwidth { flex: 1 1 100%; @@ -81,7 +82,6 @@ } &-headerLink { - margin-left: @component-padding; color: @text-color-subtle; } @@ -99,6 +99,7 @@ &-headerRefreshButton { display: inline-block; + margin-right: @component-padding; color: @text-color-subtle; cursor: pointer; From c62bb517e1d9297bd6734395656393e0e01f5809 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 17 Dec 2018 08:22:20 -0800 Subject: [PATCH 2349/4847] for realsies istanbul ignore relay-network-layer-manager --- .nycrc.json | 3 ++- lib/relay-network-layer-manager.js | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.nycrc.json b/.nycrc.json index b9380f0e5c..7135cec850 100644 --- a/.nycrc.json +++ b/.nycrc.json @@ -6,6 +6,7 @@ ], "exclude": [ "lib/views/git-cache-view.js", - "lib/views/git-timings-view.js" + "lib/views/git-timings-view.js", + "lib/relay-network-layer-manager.js" ] } diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index 555d86b931..fd6abf2861 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -1,4 +1,3 @@ -/* istanbul ignore next */ import util from 'util'; import {Environment, Network, RecordSource, Store} from 'relay-runtime'; import moment from 'moment'; From 14a2d270c8cdec24e0b065ea3df0ee1472a8b1f8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 12:20:39 -0500 Subject: [PATCH 2350/4847] IssueishDetailItem uses `github.com` as its host --- lib/controllers/root-controller.js | 2 +- test/controllers/root-controller.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index 2205e08611..b911f11b3e 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -588,7 +588,7 @@ export default class RootController extends React.Component { } acceptOpenIssueish({repoOwner, repoName, issueishNumber}) { - const uri = IssueishDetailItem.buildURI('https://api.github.com', repoOwner, repoName, issueishNumber); + const uri = IssueishDetailItem.buildURI('github.com', repoOwner, repoName, issueishNumber); this.setState({openIssueishDialogActive: false}); this.props.workspace.open(uri).then(() => { addEvent('open-issueish-in-pane', {package: 'github', from: 'dialog'}); diff --git a/test/controllers/root-controller.test.js b/test/controllers/root-controller.test.js index 5c016c7dd3..e3bf7c6530 100644 --- a/test/controllers/root-controller.test.js +++ b/test/controllers/root-controller.test.js @@ -428,7 +428,7 @@ describe('RootController', function() { resolveOpenIssueish(); await promise; - const uri = IssueishDetailItem.buildURI('https://api.github.com', repoOwner, repoName, issueishNumber); + const uri = IssueishDetailItem.buildURI('github.com', repoOwner, repoName, issueishNumber); assert.isTrue(openIssueishDetails.calledWith(uri)); From 3397d530bb778c9b98989be3e8e1f62845f83125 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 12:23:55 -0500 Subject: [PATCH 2351/4847] workdirPath is missing when looking at an issueish from another repo --- lib/controllers/issueish-detail-controller.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index 360189ef3b..f1991ab5e3 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -32,6 +32,7 @@ export class BareIssueishDetailController extends React.Component { isAbsent: PropTypes.bool.isRequired, isLoading: PropTypes.bool.isRequired, isPresent: PropTypes.bool.isRequired, + workdirPath: PropTypes.string, // Connection information endpoint: EndpointPropType.isRequired, @@ -39,7 +40,6 @@ export class BareIssueishDetailController extends React.Component { // Atom environment workspace: PropTypes.object.isRequired, - workdirPath: PropTypes.string.isRequired, commands: PropTypes.object.isRequired, keymaps: PropTypes.object.isRequired, tooltips: PropTypes.object.isRequired, @@ -277,6 +277,11 @@ export class BareIssueishDetailController extends React.Component { } openCommit = async ({sha}) => { + /* istanbul ignore if */ + if (!this.props.workdirPath) { + return; + } + const uri = CommitDetailItem.buildURI(this.props.workdirPath, sha); await this.props.workspace.open(uri, {pending: true}); addEvent('open-commit-in-pane', {package: 'github', from: this.constructor.name}); From 788dd705b8f2b108b48ce96d3036b76f83552643 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 12:26:15 -0500 Subject: [PATCH 2352/4847] onBranch and openCommit will not be set for issues --- lib/views/issueish-timeline-view.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/views/issueish-timeline-view.js b/lib/views/issueish-timeline-view.js index 6523173807..923f919abc 100644 --- a/lib/views/issueish-timeline-view.js +++ b/lib/views/issueish-timeline-view.js @@ -77,8 +77,13 @@ export default class IssueishTimelineView extends React.Component { pullRequest: PropTypes.shape({ timeline: TimelineConnectionPropType, }), - onBranch: PropTypes.bool.isRequired, - openCommit: PropTypes.func.isRequired, + onBranch: PropTypes.bool, + openCommit: PropTypes.func, + } + + static defaultProps = { + onBranch: false, + openCommit: () => {}, } constructor(props) { From e2bfeea6c08b95a0d18a85ed90a12f5a40edb63e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 13:51:07 -0500 Subject: [PATCH 2353/4847] Pass Endpoint into RemoteContainer separately --- lib/containers/remote-container.js | 25 ++++++++++++------------ lib/views/github-tab-view.js | 7 +++++-- test/containers/remote-container.test.js | 1 - 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/containers/remote-container.js b/lib/containers/remote-container.js index 1ef7a37033..e4aec30e9a 100644 --- a/lib/containers/remote-container.js +++ b/lib/containers/remote-container.js @@ -4,7 +4,9 @@ import {QueryRenderer, graphql} from 'react-relay'; import {incrementCounter} from '../reporter-proxy'; import {autobind} from '../helpers'; -import {RemotePropType, RemoteSetPropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types'; +import { + RemotePropType, RemoteSetPropType, BranchSetPropType, OperationStateObserverPropType, EndpointPropType, +} from '../prop-types'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; import RemoteController from '../controllers/remote-controller'; @@ -15,18 +17,21 @@ import GithubLoginView from '../views/github-login-view'; export default class RemoteContainer extends React.Component { static propTypes = { + // Connection loginModel: PropTypes.object.isRequired, + endpoint: EndpointPropType.isRequired, + // Repository attributes remoteOperationObserver: OperationStateObserverPropType.isRequired, + pushInProgress: PropTypes.bool.isRequired, workingDirectory: PropTypes.string.isRequired, workspace: PropTypes.object.isRequired, remote: RemotePropType.isRequired, remotes: RemoteSetPropType.isRequired, branches: BranchSetPropType.isRequired, - aheadCount: PropTypes.number, - pushInProgress: PropTypes.bool.isRequired, + // Action methods onPushBranch: PropTypes.func.isRequired, } @@ -37,7 +42,7 @@ export default class RemoteContainer extends React.Component { } fetchToken(loginModel) { - return loginModel.getToken(this.endpoint().getLoginAccount()); + return loginModel.getToken(this.props.endpoint.getLoginAccount()); } render() { @@ -67,7 +72,7 @@ export default class RemoteContainer extends React.Component { ); } - const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.endpoint(), token); + const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.endpoint, token); const query = graphql` query remoteContainerQuery($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { @@ -112,7 +117,7 @@ export default class RemoteContainer extends React.Component { return ( this.props.handlePushBranch(this.props.currentBranch, this.props.currentRemote)} remote={this.props.currentRemote} remotes={this.props.remotes} branches={this.props.branches} aheadCount={this.props.aheadCount} - pushInProgress={this.props.pushInProgress} + + onPushBranch={() => this.props.handlePushBranch(this.props.currentBranch, this.props.currentRemote)} /> ); } diff --git a/test/containers/remote-container.test.js b/test/containers/remote-container.test.js index 87c651a0c2..2d60943684 100644 --- a/test/containers/remote-container.test.js +++ b/test/containers/remote-container.test.js @@ -34,7 +34,6 @@ describe('RemoteContainer', function() { return ( Date: Mon, 17 Dec 2018 10:56:59 -0800 Subject: [PATCH 2354/4847] add tests for UserStore uncovered lines --- lib/models/user-store.js | 21 ++++++++------ test/models/user-store.test.js | 50 +++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index 1f27ac7c7e..ae11ba48a2 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -113,6 +113,17 @@ export default class UserStore { ); } + async getToken(loginModel, loginAccount) { + if (!loginModel) { + return null; + } + const token = await loginModel.getToken(loginAccount); + if (token === UNAUTHENTICATED || token === INSUFFICIENT) { + return null; + } + return token; + } + async loadMentionableUsers(remote) { const cached = this.cache.get(remote); if (cached !== null) { @@ -121,14 +132,8 @@ export default class UserStore { } const endpoint = remote.getEndpoint(); - - const loginModel = this.loginObserver.getActiveModel(); - if (!loginModel) { - return; - } - - const token = await loginModel.getToken(endpoint.getLoginAccount()); - if (token === UNAUTHENTICATED || token === INSUFFICIENT) { + const token = await this.getToken(this.loginObserver.getActiveModel(), endpoint.getLoginAccount()); + if (!token) { return; } diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 10ef5c993c..61f46a4694 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -3,7 +3,7 @@ import dedent from 'dedent-js'; import UserStore, {source} from '../../lib/models/user-store'; import Author, {nullAuthor} from '../../lib/models/author'; import GithubLoginModel from '../../lib/models/github-login-model'; -import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; +import {InMemoryStrategy, UNAUTHENTICATED} from '../../lib/shared/keytar-strategy'; import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import {cloneRepository, buildRepository, FAKE_USER} from '../helpers'; @@ -365,6 +365,51 @@ describe('UserStore', function() { ]); }); + describe.only('getToken', function() { + let repository, workdirPath; + beforeEach(async function() { + workdirPath = await cloneRepository('multiple-commits'); + repository = await buildRepository(workdirPath); + }) + it('returns null if loginModel is falsy', async function() { + store = new UserStore({repository, login, config}); + const token = await store.getToken(undefined, 'https://api.github.com'); + assert.isNull(token); + }); + + it('returns null if token is INSUFFICIENT', async function() { + const loginModel = new GithubLoginModel(InMemoryStrategy); + sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'read:org'])); + + await loginModel.setToken('https://api.github.com', '1234'); + store = new UserStore({repository, loginModel, config}); + const token = await store.getToken(loginModel, 'https://api.github.com'); + assert.isNull(token); + }); + + it('returns null if token is UNAUTHENTICATED', async function() { + const loginModel = new GithubLoginModel(InMemoryStrategy); + sinon.stub(loginModel, 'getToken').returns(Promise.resolve(UNAUTHENTICATED)); + + store = new UserStore({repository, loginModel, config}); + const getToken = await store.getToken(loginModel, 'https://api.github.com'); + assert.isNull(getToken); + }); + + it('return token if token is sufficient and model is truthy', async function() { + const loginModel = new GithubLoginModel(InMemoryStrategy); + sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'read:org', 'user:email'])); + + const expectedToken = '1234'; + await loginModel.setToken('https://api.github.com', expectedToken); + store = new UserStore({repository, loginModel, config}); + const actualToken = await store.getToken(loginModel, 'https://api.github.com'); + assert.strictEqual(expectedToken, actualToken); + }); + + }); + + describe('GraphQL response caching', function() { it('caches mentionable users acquired from GraphQL', async function() { await login.setToken('https://api.github.com', '1234'); @@ -384,6 +429,7 @@ describe('UserStore', function() { store = new UserStore({repository, login, config}); sinon.spy(store, 'loadUsers'); + sinon.spy(store, 'getToken'); // The first update is triggered by the commiter, the second from GraphQL results arriving. await nextUpdatePromise(); @@ -396,6 +442,8 @@ describe('UserStore', function() { await assert.async.strictEqual(store.loadUsers.callCount, 2); await store.loadUsers.returnValues[1]; + await assert.async.strictEqual(store.getToken.callCount, 1) + assert.deepEqual(store.getUsers(), [ new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), new Author('mona@lisa.com', 'Mona Lisa', 'octocat'), From 83c8ecb3a4e4529a617f7f0bdcff1c4c2f60ba73 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 17 Dec 2018 11:01:14 -0800 Subject: [PATCH 2355/4847] stupid .only --- test/models/user-store.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 61f46a4694..deec063032 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -365,7 +365,7 @@ describe('UserStore', function() { ]); }); - describe.only('getToken', function() { + describe('getToken', function() { let repository, workdirPath; beforeEach(async function() { workdirPath = await cloneRepository('multiple-commits'); From b745c3724f1a11825a9edb809459117fc2506908 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 17 Dec 2018 11:32:39 -0800 Subject: [PATCH 2356/4847] :shirt: I really need to fix my in editor linting. --- test/models/user-store.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index deec063032..6e33d407d0 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -370,7 +370,7 @@ describe('UserStore', function() { beforeEach(async function() { workdirPath = await cloneRepository('multiple-commits'); repository = await buildRepository(workdirPath); - }) + }); it('returns null if loginModel is falsy', async function() { store = new UserStore({repository, login, config}); const token = await store.getToken(undefined, 'https://api.github.com'); @@ -442,7 +442,7 @@ describe('UserStore', function() { await assert.async.strictEqual(store.loadUsers.callCount, 2); await store.loadUsers.returnValues[1]; - await assert.async.strictEqual(store.getToken.callCount, 1) + await assert.async.strictEqual(store.getToken.callCount, 1); assert.deepEqual(store.getUsers(), [ new Author('smashwilson@github.com', 'Ash Wilson', 'smashwilson'), From b9b29c37f6f36c76468311f011a7790dbd37cdf6 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 17 Dec 2018 11:45:33 -0800 Subject: [PATCH 2357/4847] log console errors in `PullRequestChangedFilesContainer` --- lib/containers/pr-changed-files-container.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/containers/pr-changed-files-container.js b/lib/containers/pr-changed-files-container.js index e569f733fb..ece3bf4a82 100644 --- a/lib/containers/pr-changed-files-container.js +++ b/lib/containers/pr-changed-files-container.js @@ -64,8 +64,13 @@ export default class PullRequestChangedFilesContainer extends React.Component { } async fetchDiff() { - const diffError = message => new Promise(resolve => - this.setState({isLoading: false, error: message}, resolve)); + const diffError = (message, err = null) => new Promise(resolve => { + if (err) { + // eslint-disable-next-line no-console + console.error(err); + } + this.setState({isLoading: false, error: message}, resolve); + }); const url = this.getDiffURL(); const response = await fetch(url, { @@ -75,7 +80,7 @@ export default class PullRequestChangedFilesContainer extends React.Component { }, // eslint-disable-next-line handle-callback-err }).catch(err => { - diffError(`Network error encountered at fetching ${url}`); + diffError(`Network error encountered at fetching ${url}`, err); }); if (this.state.error) { return; @@ -88,8 +93,8 @@ export default class PullRequestChangedFilesContainer extends React.Component { } else { diffError(`Unable to fetch diff for this pull request${response ? ': ' + response.statusText : ''}.`); } - } catch (e) { - diffError('Unable to parse diff for this pull request.'); + } catch (err) { + diffError('Unable to parse diff for this pull request.', err); } } From f784275d4e8b1e3654d70c052525ed7db40e9825 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 15:03:18 -0500 Subject: [PATCH 2358/4847] Separate cmd- and ctrl- commands by platform --- keymaps/git.cson | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/keymaps/git.cson b/keymaps/git.cson index dddf1e91a0..0579826954 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -26,21 +26,33 @@ 'shift-tab': 'core:focus-previous' 'o': 'github:jump-to-file' 'left': 'core:move-left' +'.platform-darwin .github-StagingView': 'cmd-left': 'core:move-left' +'.platform-linux .github-StagingView, .platform-win32 .github-StagingView': + 'ctrl-left': 'core-move-left' '.github-CommitView button': 'tab': 'core:focus-next' 'shift-tab': 'core:focus-previous' -'.github-StagingView.unstaged-changes-focused': +'.platform-darwin .github-StagingView.unstaged-changes-focused': 'cmd-backspace': 'github:discard-changes-in-selected-files' +'.platform-linux .github-StagingView.unstaged-changes-focused': + 'ctrl-backspace': 'github:discard-changes-in-selected-files' +'.platform-win32 .github-StagingView.unstaged-changes-focused': + # Repeated to avoid line length 'ctrl-backspace': 'github:discard-changes-in-selected-files' '.github-CommitView-editor atom-text-editor:not([mini])': - 'cmd-enter': 'github:commit' - 'ctrl-enter': 'github:commit' 'tab': 'core:focus-next' 'shift-tab': 'core:focus-previous' +'.platform-darwin .github-CommitView-editor atom-text-editor:not([mini])': + 'cmd-enter': 'github:commit' +'.platform-win32 .github-CommitView-editor atom-text-editor:not([mini])': + 'ctrl-enter': 'github:commit' +'.platform-linux .github-CommitView-editor atom-text-editor:not([mini])': + # Repeated to avoid line length + 'ctrl-enter': 'github:commit' '.github-CommitView-commitPreview': 'cmd-left': 'github:dive' @@ -49,25 +61,38 @@ '.github-RecentCommits': 'enter': 'github:dive' - 'cmd-left': 'github:dive' - 'ctrl-left': 'github:dive' 'tab': 'core:focus-next' 'shift-tab': 'core:focus-previous' +'.platform-darwin .github-RecentCommits': + 'cmd-left': 'github:dive' +'.platform-win32 .github-RecentCommits, .platform-linux .github-RecentCommits': + 'ctrl-left': 'github:dive' -'.github-CommitDetailView': +'.platform-darwin .github-CommitDetailView': 'cmd-right': 'github:surface' +'.platform-win32 .github-CommitDetailView': + 'ctrl-right': 'github:surface' +'.platform-linux .github-CommitDetailView': 'ctrl-right': 'github:surface' '.github-FilePatchView atom-text-editor:not([mini])': +'.platform-darwin .github-FilePatchView atom-text-editor:not([mini])': 'cmd-/': 'github:toggle-patch-selection-mode' - 'ctrl-/': 'github:toggle-patch-selection-mode' 'cmd-backspace': 'github:discard-selected-lines' - 'ctrl-backspace': 'github:discard-selected-lines' - 'ctrl-enter': 'core:confirm' 'cmd-enter': 'core:confirm' 'cmd-right': 'github:surface' - 'ctrl-right': 'github:surface' 'cmd-o': 'github:jump-to-file' +'.platform-win32 .github-FilePatchView atom-text-editor:not([mini])': + 'ctrl-/': 'github:toggle-patch-selection-mode' + 'ctrl-backspace': 'github:discard-selected-lines' + 'ctrl-enter': 'core:confirm' + 'ctrl-right': 'github:surface' + 'ctrl-o': 'github:jump-to-file' +'.platform-linux .github-FilePatchView atom-text-editor:not([mini])': + 'ctrl-/': 'github:toggle-patch-selection-mode' + 'ctrl-backspace': 'github:discard-selected-lines' + 'ctrl-enter': 'core:confirm' + 'ctrl-right': 'github:surface' 'ctrl-o': 'github:jump-to-file' '.github-FilePatchView--hunkMode atom-text-editor:not([mini])': From d07dac77ec88fbb25eb6b34fb38f2432d9d82eed Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 15:03:43 -0500 Subject: [PATCH 2359/4847] Support unprefixed MultiFilePatch commands until they're editable --- keymaps/git.cson | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/keymaps/git.cson b/keymaps/git.cson index 0579826954..067b05035b 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -76,6 +76,13 @@ 'ctrl-right': 'github:surface' '.github-FilePatchView atom-text-editor:not([mini])': + # Only support unprefixed file patch keybindings until MultiFilePatch is + # editable + '/': 'github:toggle-patch-selection-mode' + 'backspace': 'github:discard-selected-lines' + 'enter': 'core:confirm' + 'right': 'github:surface' + 'o': 'github:jump-to-file' '.platform-darwin .github-FilePatchView atom-text-editor:not([mini])': 'cmd-/': 'github:toggle-patch-selection-mode' 'cmd-backspace': 'github:discard-selected-lines' From 214e3129ce037e4d38245fafa1ba02e04a92c70c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 15:10:59 -0500 Subject: [PATCH 2360/4847] CommitDetailView is not actually a focus target --- keymaps/git.cson | 7 ------- 1 file changed, 7 deletions(-) diff --git a/keymaps/git.cson b/keymaps/git.cson index 067b05035b..e031268f1b 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -68,13 +68,6 @@ '.platform-win32 .github-RecentCommits, .platform-linux .github-RecentCommits': 'ctrl-left': 'github:dive' -'.platform-darwin .github-CommitDetailView': - 'cmd-right': 'github:surface' -'.platform-win32 .github-CommitDetailView': - 'ctrl-right': 'github:surface' -'.platform-linux .github-CommitDetailView': - 'ctrl-right': 'github:surface' - '.github-FilePatchView atom-text-editor:not([mini])': # Only support unprefixed file patch keybindings until MultiFilePatch is # editable From cd9f9203563d67cd68541f9f7d7aef6a62716276 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 15:11:14 -0500 Subject: [PATCH 2361/4847] Dive from recent commits on left or enter --- keymaps/git.cson | 1 + 1 file changed, 1 insertion(+) diff --git a/keymaps/git.cson b/keymaps/git.cson index e031268f1b..bcd27f7bd4 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -60,6 +60,7 @@ 'enter': 'native!' '.github-RecentCommits': + 'left': 'github:dive' 'enter': 'github:dive' 'tab': 'core:focus-next' 'shift-tab': 'core:focus-previous' From 9a0344e95e580614cff0f081db280ce20d737e3a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 15:13:26 -0500 Subject: [PATCH 2362/4847] Split commitPreview bindings by platform --- keymaps/git.cson | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/keymaps/git.cson b/keymaps/git.cson index bcd27f7bd4..452c1f34a0 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -55,9 +55,13 @@ 'ctrl-enter': 'github:commit' '.github-CommitView-commitPreview': + 'enter': 'native!' +'.platform-darwin .github-CommitView-commitPreview': 'cmd-left': 'github:dive' +'.platform-win32 .github-CommitView-commitPreview': + 'ctrl-left': 'github:dive' +'.platform-linux .github-CommitView-commitPreview': 'ctrl-left': 'github:dive' - 'enter': 'native!' '.github-RecentCommits': 'left': 'github:dive' From 5b7c575cc07976fb2bbcb3bdf2c511cf3de64dcd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 15:15:09 -0500 Subject: [PATCH 2363/4847] Dive on unadorned "left" --- keymaps/git.cson | 1 + 1 file changed, 1 insertion(+) diff --git a/keymaps/git.cson b/keymaps/git.cson index 452c1f34a0..67c178042e 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -55,6 +55,7 @@ 'ctrl-enter': 'github:commit' '.github-CommitView-commitPreview': + 'left': 'github-dive' 'enter': 'native!' '.platform-darwin .github-CommitView-commitPreview': 'cmd-left': 'github:dive' From 54f00ba12e0dcb96b63a1a8983b750b348c2fbf7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 15:19:11 -0500 Subject: [PATCH 2364/4847] Dive from staged and unstaged file lists on enter --- keymaps/git.cson | 1 + 1 file changed, 1 insertion(+) diff --git a/keymaps/git.cson b/keymaps/git.cson index 67c178042e..ea44c08369 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -26,6 +26,7 @@ 'shift-tab': 'core:focus-previous' 'o': 'github:jump-to-file' 'left': 'core:move-left' + 'enter': 'core:move-left' '.platform-darwin .github-StagingView': 'cmd-left': 'core:move-left' '.platform-linux .github-StagingView, .platform-win32 .github-StagingView': From 9d50524426801240c8107b01f40120759c3808ef Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 15:24:35 -0500 Subject: [PATCH 2365/4847] Split .github-Git bindings --- keymaps/git.cson | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/keymaps/git.cson b/keymaps/git.cson index ea44c08369..4945d43710 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -17,8 +17,9 @@ 'alt-m enter': 'github:resolve-as-current' 'alt-m r': 'github:revert-current' -'.github-Git': +'.platform-darwin .github-Git': 'cmd-enter': 'github:commit' +'.platform-win32 .github-Git, .platform-linux .github-Git': 'ctrl-enter': 'github:commit' '.github-StagingView': From a5fe3a0b9afbcd5999be76ab26f630cf5dcd5045 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 17 Dec 2018 15:31:05 -0500 Subject: [PATCH 2366/4847] Let's not do that just yet --- keymaps/git.cson | 1 - 1 file changed, 1 deletion(-) diff --git a/keymaps/git.cson b/keymaps/git.cson index 4945d43710..887217721b 100644 --- a/keymaps/git.cson +++ b/keymaps/git.cson @@ -27,7 +27,6 @@ 'shift-tab': 'core:focus-previous' 'o': 'github:jump-to-file' 'left': 'core:move-left' - 'enter': 'core:move-left' '.platform-darwin .github-StagingView': 'cmd-left': 'core:move-left' '.platform-linux .github-StagingView, .platform-win32 .github-StagingView': From 1c58579e317349414badcb11528f73e6555e4af7 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 17 Dec 2018 13:30:00 -0800 Subject: [PATCH 2367/4847] add test for `UserStore.loadMentionableUsers` --- test/models/user-store.test.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 6e33d407d0..6d5d255928 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -408,7 +408,23 @@ describe('UserStore', function() { }); }); + describe('loadMentionableUsers', function() { + it('returns undefined if token is null', async function() { + const workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); + + store = new UserStore({repository, login, config}); + sinon.stub(store, 'getToken').returns(null); + + const remoteSet = await repository.getRemotes(); + const remote = remoteSet.byDotcomRepo.get('me/stuff')[0]; + + const users = await store.loadMentionableUsers(remote); + assert.notOk(users); + }); + }); describe('GraphQL response caching', function() { it('caches mentionable users acquired from GraphQL', async function() { @@ -431,7 +447,7 @@ describe('UserStore', function() { sinon.spy(store, 'loadUsers'); sinon.spy(store, 'getToken'); - // The first update is triggered by the commiter, the second from GraphQL results arriving. + // The first update is triggered by the committer, the second from GraphQL results arriving. await nextUpdatePromise(); await nextUpdatePromise(); From ac64240e656583d31d0d86d2388091c746b14d3e Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 17 Dec 2018 13:56:37 -0800 Subject: [PATCH 2368/4847] add tests for `ErrorView` --- lib/views/error-view.js | 2 +- test/views/error-view.test.js | 69 +++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 test/views/error-view.test.js diff --git a/lib/views/error-view.js b/lib/views/error-view.js index 21e47d2200..6d1228bdf6 100644 --- a/lib/views/error-view.js +++ b/lib/views/error-view.js @@ -36,7 +36,7 @@ export default class ErrorView extends React.Component { )} {this.props.logout && ( - + )}
    diff --git a/test/views/error-view.test.js b/test/views/error-view.test.js new file mode 100644 index 0000000000..f36a1c93a6 --- /dev/null +++ b/test/views/error-view.test.js @@ -0,0 +1,69 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import ErrorView from '../../lib/views/error-view'; + +describe('ErrorView', function() { + function buildApp(overrideProps = {}) { + return ( + {}} + logout={() => {}} + {...overrideProps} + /> + ); + } + it('renders title', function() { + const wrapper = shallow(buildApp()); + const title = wrapper.find('.github-Message-title'); + assert.strictEqual(title.text(), 'zomg'); + }); + + it('renders descriptions', function() { + const wrapper = shallow(buildApp()); + const descriptions = wrapper.find('.github-Message-description'); + assert.lengthOf(descriptions, 3); + assert.strictEqual(descriptions.at(0).text(), 'something'); + assert.strictEqual(descriptions.at(1).text(), 'went'); + assert.strictEqual(descriptions.at(2).text(), 'wrong'); + }); + + it('renders retry button that if retry prop is passed', function() { + const retrySpy = sinon.spy(); + const wrapper = shallow(buildApp({retry: retrySpy})); + + const retryButton = wrapper.find('.btn-primary'); + assert.strictEqual(retryButton.text(), 'Try Again'); + + assert.strictEqual(retrySpy.callCount, 0); + retryButton.simulate('click'); + assert.strictEqual(retrySpy.callCount, 1); + }); + + it('does not render retry button if retry prop is not passed', function() { + const wrapper = shallow(buildApp({retry: null})); + const retryButton = wrapper.find('.btn-primary'); + assert.lengthOf(retryButton, 0); + }); + + it('renders logout button if logout prop is passed', function() { + const logoutSpy = sinon.spy(); + const wrapper = shallow(buildApp({logout: logoutSpy})); + + const logoutButton = wrapper.find('.btn-logout'); + assert.strictEqual(logoutButton.text(), 'Logout'); + + assert.strictEqual(logoutSpy.callCount, 0); + logoutButton.simulate('click'); + assert.strictEqual(logoutSpy.callCount, 1); + }); + + it('does not render logout button if logout prop is not passed', function() { + const wrapper = shallow(buildApp({logout: null})); + const logoutButton = wrapper.find('.btn-logout'); + assert.lengthOf(logoutButton, 0); + }); +}); From 0e9e1cd98a9f14aa799bc592fdd713ee85cf8e89 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 18 Dec 2018 10:52:26 +0900 Subject: [PATCH 2369/4847] Move dock styles to its own file --- styles/dock.less | 134 +++++++++++++++++++++++++++++++ styles/git-tab.less | 32 -------- styles/issueish-detail-view.less | 95 ---------------------- 3 files changed, 134 insertions(+), 127 deletions(-) create mode 100644 styles/dock.less diff --git a/styles/dock.less b/styles/dock.less new file mode 100644 index 0000000000..525c327b4e --- /dev/null +++ b/styles/dock.less @@ -0,0 +1,134 @@ +@import "variables"; + +// Dock overrides +// Here ALL the overrides when a pane/panel gets used as a dock item +// It's not too high of a priority, but still good to check (and fix) once in a while + + +// Git Panel (in bottom dock) ---------------------------------------------- + +atom-dock.bottom { + .github-Git { + flex-direction: row; + } + + .github-StagingView { + display: contents; // make these invisible to layout + } + + .github-Git > div { + flex: 1; + } + + .github-StagedChanges { + border-left: 1px solid @base-border-color; + border-right: 1px solid @base-border-color; + } + + .github-StagingView-header { + flex-wrap: wrap; + } + .github-StagingView-group:first-child .github-StagingView-header { + border-top: 1px solid @base-border-color; + } + + .github-RecentCommits { + max-height: none; + border-left: 1px solid @base-border-color; + } + +} + + +// GitHub Pane ---------------------------------------------- + +atom-dock .react-tabs__tab { + padding: none; + + &--selected { + font-weight: bold; + } +} + +atom-dock .github-IssueishDetailView { + padding: @component-padding; + font-size: @font-size; + background-color: @tool-panel-background-color; + + &-tab { + border: none; + } + + &-tablist { + border-bottom: none; + display: inline; + } + + &-header { + margin-bottom: @component-padding*1.5; + padding: 0; + border: none; + border-radius: 0; + } + + &-headerGroup { + margin: 0; + } + + &-avatarImage { + width: 24px; + height: 24px; + border-radius: @component-border-radius; + } + + &-title { + font-size: 1.25em; + font-weight: 500; + line-height: 1.3; + } + + &-reactions { + padding-top: @component-padding; + } + + &-buildStatus { + margin: @component-padding 0; + + &:empty { + display: none; + } + } + + .github-PrTimeline { + margin-top: @component-padding; + } + + .timeline-item { + margin: 0; + padding: @component-padding*1.5 0; + } + + .pre-timeline-item-icon { + position: relative; + margin: 0; + &:before { + vertical-align: middle; + } + } + + &-container > .github-DotComMarkdownHtml { + margin: @component-padding 0; + } + +} + +atom-dock .github-PrStatuses { + &-header, + &-list-item { + border-radius: 0; + padding-left: 0; + padding-right: 0; + border-left: none; + border-right: none; + } +} diff --git a/styles/git-tab.less b/styles/git-tab.less index a3bfb85e5d..54d6ff2bcf 100644 --- a/styles/git-tab.less +++ b/styles/git-tab.less @@ -45,35 +45,3 @@ } } } - -atom-dock.bottom { - .github-Git { - flex-direction: row; - } - - .github-StagingView { - display: contents; // make these invisible to layout - } - - .github-Git > div { - flex: 1; - } - - .github-StagedChanges { - border-left: 1px solid @base-border-color; - border-right: 1px solid @base-border-color; - } - - .github-StagingView-header { - flex-wrap: wrap; - } - .github-StagingView-group:first-child .github-StagingView-header { - border-top: 1px solid @base-border-color; - } - - .github-RecentCommits { - max-height: none; - border-left: 1px solid @base-border-color; - } - -} diff --git a/styles/issueish-detail-view.less b/styles/issueish-detail-view.less index 1f35fb3d2e..27c61d54b4 100644 --- a/styles/issueish-detail-view.less +++ b/styles/issueish-detail-view.less @@ -241,98 +241,3 @@ } } - - -// Dock Overrides ------------------------ -// When the IssueishDetailView is shown as a Dock item - -atom-dock .react-tabs__tab { - padding: none; - - &--selected { - font-weight: bold; - } -} - -atom-dock .github-IssueishDetailView { - padding: @component-padding; - font-size: @font-size; - background-color: @tool-panel-background-color; - - &-tab { - border: none; - } - - &-tablist { - border-bottom: none; - display: inline; - } - - &-header { - margin-bottom: @component-padding*1.5; - padding: 0; - border: none; - border-radius: 0; - } - - &-headerGroup { - margin: 0; - } - - &-avatarImage { - width: 24px; - height: 24px; - border-radius: @component-border-radius; - } - - &-title { - font-size: 1.25em; - font-weight: 500; - line-height: 1.3; - } - - &-reactions { - padding-top: @component-padding; - } - - &-buildStatus { - margin: @component-padding 0; - - &:empty { - display: none; - } - } - - .github-PrTimeline { - margin-top: @component-padding; - } - - .timeline-item { - margin: 0; - padding: @component-padding*1.5 0; - } - - .pre-timeline-item-icon { - position: relative; - margin: 0; - &:before { - vertical-align: middle; - } - } - - &-container > .github-DotComMarkdownHtml { - margin: @component-padding 0; - } - -} - -atom-dock .github-PrStatuses { - &-header, - &-list-item { - border-radius: 0; - padding-left: 0; - padding-right: 0; - border-left: none; - border-right: none; - } -} From 12c6df112342fa010ee7bba523caa05bd29c774b Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 18 Dec 2018 11:02:32 +0900 Subject: [PATCH 2370/4847] Separate left/right and bottom docks --- styles/dock.less | 139 ++++++++++++++++++++++++----------------------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/styles/dock.less b/styles/dock.less index 525c327b4e..8bdc4a7a3a 100644 --- a/styles/dock.less +++ b/styles/dock.less @@ -42,93 +42,96 @@ atom-dock.bottom { // GitHub Pane ---------------------------------------------- -atom-dock .react-tabs__tab { - padding: none; +atom-dock.left, +atom-dock.right { + .react-tabs__tab { + padding: none; - &--selected { - font-weight: bold; + &--selected { + font-weight: bold; + } } -} -atom-dock .github-IssueishDetailView { - padding: @component-padding; - font-size: @font-size; - background-color: @tool-panel-background-color; + .github-IssueishDetailView { + padding: @component-padding; + font-size: @font-size; + background-color: @tool-panel-background-color; - &-tab { - border: none; - } + &-tab { + border: none; + } - &-tablist { - border-bottom: none; - display: inline; - } + &-tablist { + border-bottom: none; + display: inline; + } - &-header { - margin-bottom: @component-padding*1.5; - padding: 0; - border: none; - border-radius: 0; - } + &-header { + margin-bottom: @component-padding*1.5; + padding: 0; + border: none; + border-radius: 0; + } - &-headerGroup { - margin: 0; - } + &-headerGroup { + margin: 0; + } - &-avatarImage { - width: 24px; - height: 24px; - border-radius: @component-border-radius; - } + &-avatarImage { + width: 24px; + height: 24px; + border-radius: @component-border-radius; + } - &-title { - font-size: 1.25em; - font-weight: 500; - line-height: 1.3; - } + &-title { + font-size: 1.25em; + font-weight: 500; + line-height: 1.3; + } - &-reactions { - padding-top: @component-padding; - } + &-reactions { + padding-top: @component-padding; + } - &-buildStatus { - margin: @component-padding 0; + &-buildStatus { + margin: @component-padding 0; - &:empty { - display: none; + &:empty { + display: none; + } } - } - .github-PrTimeline { - margin-top: @component-padding; - } + .github-PrTimeline { + margin-top: @component-padding; + } - .timeline-item { - margin: 0; - padding: @component-padding*1.5 0; - } + .timeline-item { + margin: 0; + padding: @component-padding*1.5 0; + } - .pre-timeline-item-icon { - position: relative; - margin: 0; - &:before { - vertical-align: middle; + .pre-timeline-item-icon { + position: relative; + margin: 0; + &:before { + vertical-align: middle; + } } - } - &-container > .github-DotComMarkdownHtml { - margin: @component-padding 0; - } + &-container > .github-DotComMarkdownHtml { + margin: @component-padding 0; + } -} + } -atom-dock .github-PrStatuses { - &-header, - &-list-item { - border-radius: 0; - padding-left: 0; - padding-right: 0; - border-left: none; - border-right: none; + .github-PrStatuses { + &-header, + &-list-item { + border-radius: 0; + padding-left: 0; + padding-right: 0; + border-left: none; + border-right: none; + } } } From 8b1055b5753f3c3643f3066101ade67b75f7e9a5 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 18 Dec 2018 14:48:04 +0900 Subject: [PATCH 2371/4847] Restyle PR panes in docks --- styles/dock.less | 130 ++++++++++++++++--------------------- styles/pr-commit-view.less | 3 +- 2 files changed, 59 insertions(+), 74 deletions(-) diff --git a/styles/dock.less b/styles/dock.less index 8bdc4a7a3a..ad2ab5b7da 100644 --- a/styles/dock.less +++ b/styles/dock.less @@ -40,98 +40,82 @@ atom-dock.bottom { } -// GitHub Pane ---------------------------------------------- +// GitHub Pane (in left/right dock) ---------------------------------------------- -atom-dock.left, -atom-dock.right { - .react-tabs__tab { - padding: none; +atom-dock.left .github-IssueishDetailView, +atom-dock.right .github-IssueishDetailView { - &--selected { - font-weight: bold; - } - } - - .github-IssueishDetailView { + // Header + &-header { + display: block; padding: @component-padding; - font-size: @font-size; background-color: @tool-panel-background-color; + } + &-avatar { position: absolute; } + &-avatarImage { + width: 20px; + height: 20px; + } + &-headerRow:nth-child(1) { + padding-left: 25px; // space for avatar + overflow: hidden; + } + &-title { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } + &-checkoutButton { + margin: @component-padding 0 0 0; + } - &-tab { - border: none; - } - - &-tablist { - border-bottom: none; - display: inline; - } - - &-header { - margin-bottom: @component-padding*1.5; - padding: 0; - border: none; - border-radius: 0; - } - - &-headerGroup { - margin: 0; - } - - &-avatarImage { - width: 24px; - height: 24px; - border-radius: @component-border-radius; - } - - &-title { - font-size: 1.25em; - font-weight: 500; - line-height: 1.3; - } - - &-reactions { - padding-top: @component-padding; - } - &-buildStatus { - margin: @component-padding 0; + &-tablist { flex-wrap: wrap; } + &-tab { padding: @component-padding/2 @component-padding; } + &-tab-icon { display: none; } - &:empty { - display: none; - } - } - .github-PrTimeline { - margin-top: @component-padding; - } + // [Overview] + &-overview { + font-size: .9em; + & > .github-DotComMarkdownHtml, .timeline-item { - margin: 0; - padding: @component-padding*1.5 0; - } - - .pre-timeline-item-icon { - position: relative; - margin: 0; - &:before { - vertical-align: middle; - } + padding: @component-padding; } - - &-container > .github-DotComMarkdownHtml { - margin: @component-padding 0; - } - } + + // [Build Status] + &-buildStatus { padding: 0; } .github-PrStatuses { + &-header { border-top: none; } &-header, &-list-item { border-radius: 0; - padding-left: 0; - padding-right: 0; border-left: none; border-right: none; } } + + + // [Commits] + .github-PrCommitsView-commitWrapper { + padding: 0; + } + .github-PrCommitView-container { + font-size: .9em; + border-left: none; + border-right: none; + + &:first-child { + border-top: none; + border-radius: 0; + } + &:last-child { + border-bottom: none; + border-radius: 0; + } + } + } diff --git a/styles/pr-commit-view.less b/styles/pr-commit-view.less index ce2c93caef..f39b4b3e33 100644 --- a/styles/pr-commit-view.less +++ b/styles/pr-commit-view.less @@ -39,9 +39,11 @@ &-messageHeadline.is-button { padding: 0; + margin-right: @default-padding/1.5; background-color: transparent; border: none; cursor: pointer; + text-align: left; color: @text-color-highlight; &:hover, @@ -71,7 +73,6 @@ &-moreButton { border: none; - margin-left: @default-padding/1.5; padding: 0em .2em; color: @text-color-subtle; font-style: italic; From 41f4045c32c7aadc8385e9353616b192fa679624 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 18 Dec 2018 15:11:39 +0900 Subject: [PATCH 2372/4847] Style Commit Detail in dock --- styles/dock.less | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/styles/dock.less b/styles/dock.less index ad2ab5b7da..016e30f63d 100644 --- a/styles/dock.less +++ b/styles/dock.less @@ -119,3 +119,14 @@ atom-dock.right .github-IssueishDetailView { } } + + +// Commit Detail (in left/right dock) ---------------------------------------------- + +atom-dock.left .github-CommitDetailView, +atom-dock.right .github-CommitDetailView { + &-header { background-color: @tool-panel-background-color; } + &-commit { padding: @component-padding @component-padding 0 @component-padding; } + &-meta { margin-bottom: @component-padding; } + &-moreText { padding: @component-padding 0; } +} From 412cfae3dd823936b5fcbd912011b34d8895e3b2 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 18 Dec 2018 19:47:28 +0900 Subject: [PATCH 2373/4847] Fix styling for issues --- lib/views/issue-detail-view.js | 40 ++++++++++++++++---------------- styles/issueish-detail-view.less | 15 +++++++++--- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/lib/views/issue-detail-view.js b/lib/views/issue-detail-view.js index 36842041fe..285e1e5344 100644 --- a/lib/views/issue-detail-view.js +++ b/lib/views/issue-detail-view.js @@ -71,7 +71,7 @@ export class BareIssueDetailView extends React.Component { renderIssueBody(issue) { return ( - +
    No description provided.'} switchToIssueish={this.props.switchToIssueish} @@ -81,7 +81,7 @@ export class BareIssueDetailView extends React.Component { issue={issue} switchToIssueish={this.props.switchToIssueish} /> - +
    ); } @@ -93,31 +93,30 @@ export class BareIssueDetailView extends React.Component {
    -
    + {this.renderIssueBody(issue)}
    diff --git a/styles/issueish-detail-view.less b/styles/issueish-detail-view.less index 27c61d54b4..89781361f1 100644 --- a/styles/issueish-detail-view.less +++ b/styles/issueish-detail-view.less @@ -119,9 +119,6 @@ } } - - - &-avatarImage { width: 40px; height: 40px; @@ -240,4 +237,16 @@ padding: @component-padding*2; } + + // Issue Body ------------------------ + + &-issueBody { + flex: 1; + overflow: auto; + + & > .github-DotComMarkdownHtml { + padding: @component-padding*2; + } + } + } From 54d31909764e0fdb47fdd600e184fe08a85706a7 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 18 Dec 2018 13:51:30 +0100 Subject: [PATCH 2374/4847] remove unused import --- lib/views/issue-detail-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/issue-detail-view.js b/lib/views/issue-detail-view.js index 285e1e5344..54d07e74cb 100644 --- a/lib/views/issue-detail-view.js +++ b/lib/views/issue-detail-view.js @@ -1,4 +1,4 @@ -import React, {Fragment} from 'react'; +import React from 'react'; import {graphql, createRefetchContainer} from 'react-relay'; import PropTypes from 'prop-types'; import cx from 'classnames'; From 56cf3aeb7432019b94876efa4df87bba7f26b703 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen <6842965+vanessayuenn@users.noreply.github.com> Date: Tue, 18 Dec 2018 14:04:01 +0100 Subject: [PATCH 2375/4847] remove status section --- docs/feature-requests/000-template.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/feature-requests/000-template.md b/docs/feature-requests/000-template.md index a976c58dec..7fe932ef19 100644 --- a/docs/feature-requests/000-template.md +++ b/docs/feature-requests/000-template.md @@ -6,10 +6,6 @@ For community contributors -- Please fill out Part 1 of the following template. # Feature title -## :tipping_hand_woman: Status - -Proposed - ## :memo: Summary One paragraph explanation of the feature. From f422a4b740e723b49d6e9c76d34a9673379cc405 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 18 Dec 2018 10:27:29 -0800 Subject: [PATCH 2376/4847] hide unstage / staging buttons for filemode and symlink changes --- lib/views/file-patch-meta-view.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/views/file-patch-meta-view.js b/lib/views/file-patch-meta-view.js index 10dd2e723a..16b072440a 100644 --- a/lib/views/file-patch-meta-view.js +++ b/lib/views/file-patch-meta-view.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import cx from 'classnames'; import CommitDetailItem from '../items/commit-detail-item'; +import IssueishDetailItem from '../items/issueish-detail-item'; import {ItemTypePropType} from '../prop-types'; export default class FilePatchMetaView extends React.Component { @@ -18,7 +19,7 @@ export default class FilePatchMetaView extends React.Component { }; renderMetaControls() { - if (this.props.itemType === CommitDetailItem) { + if (this.props.itemType === CommitDetailItem || this.props.itemType === IssueishDetailItem) { return null; } return ( From edc4226f07ceeca50355fba483733f0388b70d33 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 18 Dec 2018 10:31:28 -0800 Subject: [PATCH 2377/4847] add tests for FilePatchHeaderView buttons --- test/views/file-patch-header-view.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/views/file-patch-header-view.test.js b/test/views/file-patch-header-view.test.js index cf778723cb..74f5111dd6 100644 --- a/test/views/file-patch-header-view.test.js +++ b/test/views/file-patch-header-view.test.js @@ -6,6 +6,7 @@ import FilePatchHeaderView from '../../lib/views/file-patch-header-view'; import ChangedFileItem from '../../lib/items/changed-file-item'; import CommitPreviewItem from '../../lib/items/commit-preview-item'; import CommitDetailItem from '../../lib/items/commit-detail-item'; +import IssueishDetailItem from '../../lib/items/issueish-detail-item'; describe('FilePatchHeaderView', function() { const relPath = path.join('dir', 'a.txt'); @@ -184,5 +185,11 @@ describe('FilePatchHeaderView', function() { const wrapper = shallow(buildApp({itemType: CommitDetailItem})); assert.isFalse(wrapper.find('.btn-group').exists()); }); + + it('does not render buttons when in an IssueishDetailItem', function() { + const wrapper = shallow(buildApp({itemType: IssueishDetailItem})); + assert.isFalse(wrapper.find('.btn-group').exists()); + }); + }); }); From b7c5c7f41751e449d6d30a40392c5bd92dd865e6 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 19 Dec 2018 01:54:17 +0000 Subject: [PATCH 2378/4847] fix(package): update what-the-diff to version 0.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c7acc28813..6ab320fd1c 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "tinycolor2": "1.4.1", "tree-kill": "1.2.1", "underscore-plus": "1.6.8", - "what-the-diff": "0.4.0", + "what-the-diff": "0.5.0", "what-the-status": "1.0.3", "yubikiri": "1.0.0" }, From 06ea6653f5535488faca3e177f7f36c82cc02624 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 19 Dec 2018 01:54:23 +0000 Subject: [PATCH 2379/4847] chore(package): update lockfile package-lock.json --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 865d361557..712f5bcef8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8344,9 +8344,9 @@ } }, "what-the-diff": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/what-the-diff/-/what-the-diff-0.4.0.tgz", - "integrity": "sha1-vIXGP7yWxA1H0p+EMpM0RV18PrY=" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/what-the-diff/-/what-the-diff-0.5.0.tgz", + "integrity": "sha512-+ZX92uzic8Ufbyvl128Rsi8Hf67lYMKA4MJBOUtDnA3PD+rQY0493G25KAKzb9qQ8NN5TcD6VyV/BqBFq1Ktuw==" }, "what-the-status": { "version": "1.0.3", From 66faaf96344cb0b4ed070ff5425005cce1bbf40f Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 19 Dec 2018 17:09:58 +0900 Subject: [PATCH 2380/4847] Update README screenshot With the changes from https://github.com/atom/github/pull/1829 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 975b89fbf8..b146ccf65f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The Atom GitHub package provides Git and GitHub integration for Atom. Check out git-integration -github-integration +github-integration ## Installation From 109820d857114ea065f773aeb0046f82b5ac3b58 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 19 Dec 2018 10:55:40 +0100 Subject: [PATCH 2381/4847] starts with test! --- test/views/file-patch-header-view.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/views/file-patch-header-view.test.js b/test/views/file-patch-header-view.test.js index 74f5111dd6..5cf5564823 100644 --- a/test/views/file-patch-header-view.test.js +++ b/test/views/file-patch-header-view.test.js @@ -60,6 +60,13 @@ describe('FilePatchHeaderView', function() { assert.strictEqual(wrapper.find('.github-FilePatchView-title').text(), `Staged Changes for ${relPath}`); }); }); + + it('renders title for a renamed file as oldPath → newPath', function() { + const oldPath = path.join('dir', 'a.txt'); + const newPath = path.join('dir', 'b.txt'); + const wrapper = shallow(buildApp({relPath: oldPath, newPath})); + assert.strictEqual(wrapper.find('.github-FilePatchView-title').text(), `${oldPath} → ${newPath}`); + }); }); describe('the button group', function() { From 0772a053b53350d178112cfa6c3458c2a6656a51 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 19 Dec 2018 10:55:51 +0100 Subject: [PATCH 2382/4847] handles rename of file --- lib/views/file-patch-header-view.js | 21 ++++++++++++++++----- lib/views/multi-file-patch-view.js | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/views/file-patch-header-view.js b/lib/views/file-patch-header-view.js index eba8278094..1425221120 100644 --- a/lib/views/file-patch-header-view.js +++ b/lib/views/file-patch-header-view.js @@ -13,6 +13,7 @@ import {ItemTypePropType} from '../prop-types'; export default class FilePatchHeaderView extends React.Component { static propTypes = { relPath: PropTypes.string.isRequired, + newPath: PropTypes.string, stagingStatus: PropTypes.oneOf(['staged', 'unstaged']), isPartiallyStaged: PropTypes.bool, hasHunks: PropTypes.bool.isRequired, @@ -51,16 +52,26 @@ export default class FilePatchHeaderView extends React.Component { if (this.props.itemType === ChangedFileItem) { const status = this.props.stagingStatus; return ( - {status[0].toUpperCase()}{status.slice(1)} Changes for {this.renderPath()} + {status[0].toUpperCase()}{status.slice(1)} Changes for {this.renderDisplayPath()} ); } else { - return this.renderPath(); + return this.renderDisplayPath(); } } - renderPath() { - const dirname = path.dirname(this.props.relPath); - const basename = path.basename(this.props.relPath); + renderDisplayPath() { + if (this.props.newPath && this.props.newPath !== this.props.relPath) { + const oldPath = this.renderPath(this.props.relPath); + const newPath = this.renderPath(this.props.newPath); + return {oldPath} {newPath}; + } else { + return this.renderPath(this.props.relPath); + } + } + + renderPath(filePath) { + const dirname = path.dirname(filePath); + const basename = path.basename(filePath); if (dirname === '.') { return {basename}; diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index b8d46976f8..479434e8be 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -316,6 +316,7 @@ export default class MultiFilePatchView extends React.Component { 0} From e558a36e1653e0321662bb9066afc5d780ba4a01 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 19 Dec 2018 16:52:43 +0100 Subject: [PATCH 2383/4847] add test for pruning file path prefix after parsing the diff --- test/containers/pr-changed-files-container.test.js | 10 +++++++++- test/fixtures/diffs/raw-diff.js | 14 +++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/test/containers/pr-changed-files-container.test.js b/test/containers/pr-changed-files-container.test.js index bcbe406bd9..0d63b22587 100644 --- a/test/containers/pr-changed-files-container.test.js +++ b/test/containers/pr-changed-files-container.test.js @@ -2,7 +2,7 @@ import React from 'react'; import {shallow} from 'enzyme'; import {parse as parseDiff} from 'what-the-diff'; -import rawDiff from '../fixtures/diffs/raw-diff'; +import {rawDiff, rawDiffWithPathPrefix} from '../fixtures/diffs/raw-diff'; import {buildMultiFilePatch} from '../../lib/models/patch'; import {getEndpoint} from '../../lib/models/endpoint'; @@ -72,6 +72,14 @@ describe('PullRequestChangedFilesContainer', function() { assert.strictEqual(diffURL, 'https://api.github.com/repos/smashwilson/pushbot/pulls/12'); }); + it('builds multifilepatch without the a/ and b/ prefixes in file paths', function() { + const wrapper = shallow(buildApp()); + const {filePatches} = wrapper.instance().buildPatch(rawDiffWithPathPrefix); + console.log(filePatches) + assert.notMatch(filePatches[0].newFile.path, /^[a|b]\//); + assert.notMatch(filePatches[0].oldFile.path, /^[a|b]\//); + }); + it('passes loaded diff data through to the controller', async function() { const wrapper = shallow(buildApp({ token: '4321', diff --git a/test/fixtures/diffs/raw-diff.js b/test/fixtures/diffs/raw-diff.js index 81f56d896f..0d57194fec 100644 --- a/test/fixtures/diffs/raw-diff.js +++ b/test/fixtures/diffs/raw-diff.js @@ -1,4 +1,5 @@ import dedent from 'dedent-js'; + const rawDiff = dedent` diff --git file.txt file.txt index 83db48f..bf269f4 100644 @@ -10,4 +11,15 @@ const rawDiff = dedent` +new line line3 `; -export default rawDiff; +const rawDiffWithPathPrefix = dedent` + diff --git a/badpath.txt b/badpath.txt + index af607bb..cfac420 100644 + --- a/badpath.txt + +++ b/badpath.txt + @@ -1,2 +1,3 @@ + line0 + -line1 + +line1.5 + +line2 +`; +export {rawDiff, rawDiffWithPathPrefix}; From 98a48ce35326839785caa309fe68718d998a2b9a Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 19 Dec 2018 16:53:44 +0100 Subject: [PATCH 2384/4847] prune prefix --- lib/containers/pr-changed-files-container.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/containers/pr-changed-files-container.js b/lib/containers/pr-changed-files-container.js index ece3bf4a82..beb3c5d38b 100644 --- a/lib/containers/pr-changed-files-container.js +++ b/lib/containers/pr-changed-files-container.js @@ -59,7 +59,16 @@ export default class PullRequestChangedFilesContainer extends React.Component { } buildPatch(rawDiff) { - const diffs = parseDiff(rawDiff); + const diffs = parseDiff(rawDiff).map(diff => { + // diff coming from API will have the defaul git diff prefixes a/ and b/ + // e.g. a/file1.js and b/file2.js + // see https://git-scm.com/docs/git-diff#_generating_patches_with_p + return { + ...diff, + newPath: diff.newPath ? diff.newPath.replace(/^[a|b]\//, '') : diff.newPath, + oldPath: diff.oldPath ? diff.oldPath.replace(/^[a|b]\//, '') : diff.oldPath, + }; + }); return buildMultiFilePatch(diffs); } From 0d1f597f0f00d66bb6b4c1e852b49418ada4e752 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 19 Dec 2018 16:53:53 +0100 Subject: [PATCH 2385/4847] no console log! --- test/containers/pr-changed-files-container.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/containers/pr-changed-files-container.test.js b/test/containers/pr-changed-files-container.test.js index 0d63b22587..af252cb56c 100644 --- a/test/containers/pr-changed-files-container.test.js +++ b/test/containers/pr-changed-files-container.test.js @@ -75,7 +75,6 @@ describe('PullRequestChangedFilesContainer', function() { it('builds multifilepatch without the a/ and b/ prefixes in file paths', function() { const wrapper = shallow(buildApp()); const {filePatches} = wrapper.instance().buildPatch(rawDiffWithPathPrefix); - console.log(filePatches) assert.notMatch(filePatches[0].newFile.path, /^[a|b]\//); assert.notMatch(filePatches[0].oldFile.path, /^[a|b]\//); }); From 267dbbb93acff5726eef3c90edb4a06ec9bbde95 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 19 Dec 2018 10:41:22 -0800 Subject: [PATCH 2386/4847] start on graphQL query for fetching inline comments --- .../issueishDetailContainerQuery.graphql.js | 151 +++++++++++------- lib/containers/issueish-detail-container.js | 8 +- ...eishDetailController_repository.graphql.js | 90 +++++++---- lib/controllers/issueish-detail-controller.js | 6 +- .../prDetailViewRefetchQuery.graphql.js | 123 +++++++++----- .../prDetailView_pullRequest.graphql.js | 27 +++- lib/views/pr-detail-view.js | 13 +- 7 files changed, 286 insertions(+), 132 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 517618ebe4..7b9148daa7 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 1f4afcef5bb1a9ba60f9a80a6c964d13 + * @relayHash b86bf34f5fb29cecb56582b73ffb540b */ /* eslint-disable */ @@ -18,6 +18,8 @@ export type issueishDetailContainerQueryVariables = {| timelineCursor?: ?string, commitCount: number, commitCursor?: ?string, + commentCount: number, + commentCursor?: ?string, |}; export type issueishDetailContainerQueryResponse = {| +repository: ?{| @@ -42,12 +44,12 @@ query issueishDetailContainerQuery( $commitCursor: String ) { repository(owner: $repoOwner, name: $repoName) { - ...issueishDetailController_repository_1mXVvq + ...issueishDetailController_repository_2LgaQ1 id } } -fragment issueishDetailController_repository_1mXVvq on Repository { +fragment issueishDetailController_repository_2LgaQ1 on Repository { ...issueDetailView_repository ...prDetailView_repository name @@ -84,7 +86,7 @@ fragment issueishDetailController_repository_1mXVvq on Repository { sshUrl id } - ...prDetailView_pullRequest_4cAEh0 + ...prDetailView_pullRequest_1Etigl } ... on Node { id @@ -149,13 +151,16 @@ fragment issueDetailView_issue_4cAEh0 on Issue { } } -fragment prDetailView_pullRequest_4cAEh0 on PullRequest { +fragment prDetailView_pullRequest_1Etigl on PullRequest { __typename ... on Node { id } isCrossRepository changedFiles + comments { + totalCount + } ...prCommitsView_pullRequest_38TpXw countedCommits: commits { totalCount @@ -556,6 +561,18 @@ var v0 = [ "name": "commitCursor", "type": "String", "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCount", + "type": "Int!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCursor", + "type": "String", + "defaultValue": null } ], v1 = [ @@ -1043,7 +1060,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_1mXVvq\n id\n }\n}\n\nfragment issueishDetailController_repository_1mXVvq on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_4cAEh0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_4cAEh0 on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_2LgaQ1\n id\n }\n}\n\nfragment issueishDetailController_repository_2LgaQ1 on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_1Etigl\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1065,6 +1082,18 @@ return { "kind": "FragmentSpread", "name": "issueishDetailController_repository", "args": [ + { + "kind": "Variable", + "name": "commentCount", + "variableName": "commentCount", + "type": null + }, + { + "kind": "Variable", + "name": "commentCursor", + "variableName": "commentCursor", + "type": null + }, { "kind": "Variable", "name": "commitCount", @@ -1208,55 +1237,6 @@ return { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - { - "kind": "LinkedField", - "alias": "countedCommits", - "name": "commits", - "storageKey": null, - "args": null, - "concreteType": "PullRequestCommitConnection", - "plural": false, - "selections": v29 - }, - v9, - { - "kind": "ScalarField", - "alias": null, - "name": "headRefName", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "headRepository", - "storageKey": null, - "args": null, - "concreteType": "Repository", - "plural": false, - "selections": [ - v3, - v7, - v14, - { - "kind": "ScalarField", - "alias": null, - "name": "sshUrl", - "args": null, - "storageKey": null - }, - v2 - ] - }, - v20, - { - "kind": "ScalarField", - "alias": null, - "name": "changedFiles", - "args": null, - "storageKey": null - }, - v14, { "kind": "LinkedField", "alias": null, @@ -1358,7 +1338,66 @@ return { "key": "prCommitsView_commits", "filters": null }, + v9, + { + "kind": "ScalarField", + "alias": null, + "name": "headRefName", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "headRepository", + "storageKey": null, + "args": null, + "concreteType": "Repository", + "plural": false, + "selections": [ + v3, + v7, + v14, + { + "kind": "ScalarField", + "alias": null, + "name": "sshUrl", + "args": null, + "storageKey": null + }, + v2 + ] + }, + v20, + { + "kind": "ScalarField", + "alias": null, + "name": "changedFiles", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": null, + "args": null, + "concreteType": "IssueCommentConnection", + "plural": false, + "selections": v29 + }, + v14, v10, + { + "kind": "LinkedField", + "alias": "countedCommits", + "name": "commits", + "storageKey": null, + "args": null, + "concreteType": "PullRequestCommitConnection", + "plural": false, + "selections": v29 + }, { "kind": "LinkedField", "alias": "recentCommits", @@ -1672,5 +1711,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'a7a95576735d58263820790226b82e2f'; +(node/*: any*/).hash = 'b749679230ad5e75455f1923ba78b425'; module.exports = node; diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index c428b9fe47..2f8a2e40f1 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -121,7 +121,9 @@ export default class IssueishDetailContainer extends React.Component { $timelineCount: Int! $timelineCursor: String $commitCount: Int! - $commitCursor: String + $commitCursor: String, + $commentCount: Int!, + $commentCursor: String, ) { repository(owner: $repoOwner, name: $repoName) { ...issueishDetailController_repository @arguments( @@ -130,6 +132,8 @@ export default class IssueishDetailContainer extends React.Component { timelineCursor: $timelineCursor, commitCount: $commitCount, commitCursor: $commitCursor, + commentCount: $commentCount, + commentCursor: $commentCursor, ) } } @@ -142,6 +146,8 @@ export default class IssueishDetailContainer extends React.Component { timelineCursor: null, commitCount: 100, commitCursor: null, + commentCount: 100, + commentCursor: null, }; return ( diff --git a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js index e36d6c2e87..5f17d1be10 100644 --- a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js +++ b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js @@ -109,32 +109,30 @@ v5 = { "args": null, "storageKey": null }, -v6 = [ - { - "kind": "Variable", - "name": "commitCount", - "variableName": "commitCount", - "type": null - }, - { - "kind": "Variable", - "name": "commitCursor", - "variableName": "commitCursor", - "type": null - }, - { - "kind": "Variable", - "name": "timelineCount", - "variableName": "timelineCount", - "type": null - }, - { - "kind": "Variable", - "name": "timelineCursor", - "variableName": "timelineCursor", - "type": null - } -]; +v6 = { + "kind": "Variable", + "name": "commitCount", + "variableName": "commitCount", + "type": null +}, +v7 = { + "kind": "Variable", + "name": "commitCursor", + "variableName": "commitCursor", + "type": null +}, +v8 = { + "kind": "Variable", + "name": "timelineCount", + "variableName": "timelineCount", + "type": null +}, +v9 = { + "kind": "Variable", + "name": "timelineCursor", + "variableName": "timelineCursor", + "type": null +}; return { "kind": "Fragment", "name": "issueishDetailController_repository", @@ -170,6 +168,18 @@ return { "name": "commitCursor", "type": "String", "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCount", + "type": "Int!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCursor", + "type": "String", + "defaultValue": null } ], "selections": [ @@ -204,7 +214,12 @@ return { { "kind": "FragmentSpread", "name": "issueDetailView_issue", - "args": v6 + "args": [ + v6, + v7, + v8, + v9 + ] } ] } @@ -263,7 +278,24 @@ return { { "kind": "FragmentSpread", "name": "prDetailView_pullRequest", - "args": v6 + "args": [ + { + "kind": "Variable", + "name": "commentCount", + "variableName": "commentCount", + "type": null + }, + { + "kind": "Variable", + "name": "commentCursor", + "variableName": "commentCursor", + "type": null + }, + v6, + v7, + v8, + v9 + ] } ] } @@ -273,5 +305,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '616ab785cf6824cb91ed3002553abb70'; +(node/*: any*/).hash = '0a288c1ab2398af40de27baf5db2aacb'; module.exports = node; diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index f1991ab5e3..ae8bc47bda 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -287,7 +287,7 @@ export class BareIssueishDetailController extends React.Component { addEvent('open-commit-in-pane', {package: 'github', from: this.constructor.name}); } } - +// todo: we probably don't need to commit count and cursor in the issue fragment export default createFragmentContainer(BareIssueishDetailController, { repository: graphql` fragment issueishDetailController_repository on Repository @@ -297,6 +297,8 @@ export default createFragmentContainer(BareIssueishDetailController, { timelineCursor: {type: "String"}, commitCount: {type: "Int!"}, commitCursor: {type: "String"}, + commentCount: {type: "Int!"}, + commentCursor: {type: "String"}, ) { ...issueDetailView_repository ...prDetailView_repository @@ -336,6 +338,8 @@ export default createFragmentContainer(BareIssueishDetailController, { timelineCursor: $timelineCursor, commitCount: $commitCount, commitCursor: $commitCursor, + commentCount: $commentCount, + commentCursor: $commentCursor, ) } } diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index cd360364a9..eb62f5be7c 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash ca7d9bf45e372c3f19fe741b4132b7bd + * @relayHash 690cc435f3a8f5738ba609aa81c359b4 */ /* eslint-disable */ @@ -18,6 +18,8 @@ export type prDetailViewRefetchQueryVariables = {| timelineCursor?: ?string, commitCount: number, commitCursor?: ?string, + commentCount: number, + commentCursor?: ?string, |}; export type prDetailViewRefetchQueryResponse = {| +repository: ?{| @@ -50,7 +52,7 @@ query prDetailViewRefetchQuery( } pullRequest: node(id: $issueishId) { __typename - ...prDetailView_pullRequest_4cAEh0 + ...prDetailView_pullRequest_1Etigl id } } @@ -65,13 +67,16 @@ fragment prDetailView_repository_3D8CP9 on Repository { } } -fragment prDetailView_pullRequest_4cAEh0 on PullRequest { +fragment prDetailView_pullRequest_1Etigl on PullRequest { __typename ... on Node { id } isCrossRepository changedFiles + comments { + totalCount + } ...prCommitsView_pullRequest_38TpXw countedCommits: commits { totalCount @@ -444,6 +449,18 @@ var v0 = [ "name": "commitCursor", "type": "String", "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCount", + "type": "Int!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCursor", + "type": "String", + "defaultValue": null } ], v1 = [ @@ -531,14 +548,23 @@ v12 = { "args": null, "storageKey": null }, -v13 = { +v13 = [ + { + "kind": "ScalarField", + "alias": null, + "name": "totalCount", + "args": null, + "storageKey": null + } +], +v14 = { "kind": "ScalarField", "alias": null, "name": "url", "args": null, "storageKey": null }, -v14 = [ +v15 = [ { "kind": "Variable", "name": "after", @@ -552,7 +578,7 @@ v14 = [ "type": "Int" } ], -v15 = { +v16 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -577,36 +603,27 @@ v15 = { } ] }, -v16 = { +v17 = { "kind": "ScalarField", "alias": null, "name": "cursor", "args": null, "storageKey": null }, -v17 = { +v18 = { "kind": "ScalarField", "alias": null, "name": "avatarUrl", "args": null, "storageKey": null }, -v18 = { +v19 = { "kind": "ScalarField", "alias": "sha", "name": "oid", "args": null, "storageKey": null }, -v19 = [ - { - "kind": "ScalarField", - "alias": null, - "name": "totalCount", - "args": null, - "storageKey": null - } -], v20 = { "kind": "ScalarField", "alias": null, @@ -629,7 +646,7 @@ v22 = { "storageKey": null }, v23 = [ - v13 + v14 ], v24 = [ { @@ -648,7 +665,7 @@ v24 = [ v25 = [ v5, v8, - v17, + v18, v6 ], v26 = [ @@ -680,7 +697,7 @@ v28 = { }, v29 = [ v5, - v17, + v18, v8, v6 ], @@ -712,7 +729,7 @@ return { "operationKind": "query", "name": "prDetailViewRefetchQuery", "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_4cAEh0\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_4cAEh0 on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_1Etigl\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -753,6 +770,18 @@ return { "kind": "FragmentSpread", "name": "prDetailView_pullRequest", "args": [ + { + "kind": "Variable", + "name": "commentCount", + "variableName": "commentCount", + "type": null + }, + { + "kind": "Variable", + "name": "commentCursor", + "variableName": "commentCursor", + "type": null + }, { "kind": "Variable", "name": "commitCount", @@ -824,17 +853,27 @@ return { "args": null, "storageKey": null }, - v13, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": null, + "args": null, + "concreteType": "IssueCommentConnection", + "plural": false, + "selections": v13 + }, + v14, { "kind": "LinkedField", "alias": null, "name": "commits", "storageKey": null, - "args": v14, + "args": v15, "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ - v15, + v16, { "kind": "LinkedField", "alias": null, @@ -844,7 +883,7 @@ return { "concreteType": "PullRequestCommitEdge", "plural": true, "selections": [ - v16, + v17, { "kind": "LinkedField", "alias": null, @@ -873,7 +912,7 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v17, + v18, v7, { "kind": "ScalarField", @@ -905,8 +944,8 @@ return { "args": null, "storageKey": null }, - v18, - v13 + v19, + v14 ] }, v6, @@ -921,7 +960,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v14, + "args": v15, "handle": "connection", "key": "prCommitsView_commits", "filters": null @@ -934,7 +973,7 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v19 + "selections": v13 }, { "kind": "LinkedField", @@ -1064,7 +1103,7 @@ return { "selections": [ v5, v8, - v17, + v18, v6, { "kind": "InlineFragment", @@ -1110,7 +1149,7 @@ return { "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v15, + v16, { "kind": "LinkedField", "alias": null, @@ -1120,7 +1159,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v16, + v17, { "kind": "LinkedField", "alias": null, @@ -1192,7 +1231,7 @@ return { "selections": [ v11, v21, - v13, + v14, { "kind": "ScalarField", "alias": "prState", @@ -1208,7 +1247,7 @@ return { "selections": [ v11, v21, - v13, + v14, { "kind": "ScalarField", "alias": "issueState", @@ -1357,7 +1396,7 @@ return { }, v22, v28, - v13 + v14 ] }, { @@ -1375,7 +1414,7 @@ return { "selections": [ v7, v31, - v17 + v18 ] }, { @@ -1388,7 +1427,7 @@ return { "plural": false, "selections": [ v7, - v17, + v18, v31 ] }, @@ -1399,7 +1438,7 @@ return { "args": null, "storageKey": null }, - v18, + v19, { "kind": "ScalarField", "alias": null, @@ -1462,7 +1501,7 @@ return { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v19 + "selections": v13 } ] } @@ -1475,5 +1514,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '04dad90234c09010553beb02cf90cbb1'; +(node/*: any*/).hash = 'f928e12221da7ed9e70170512e98cbb2'; module.exports = node; diff --git a/lib/views/__generated__/prDetailView_pullRequest.graphql.js b/lib/views/__generated__/prDetailView_pullRequest.graphql.js index ae06b6754a..b510f50297 100644 --- a/lib/views/__generated__/prDetailView_pullRequest.graphql.js +++ b/lib/views/__generated__/prDetailView_pullRequest.graphql.js @@ -19,6 +19,9 @@ export type prDetailView_pullRequest = {| +id?: string, +isCrossRepository: boolean, +changedFiles: number, + +comments: {| + +totalCount: number + |}, +countedCommits: {| +totalCount: number |}, @@ -96,6 +99,18 @@ return { "name": "commitCursor", "type": "String", "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCount", + "type": "Int!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCursor", + "type": "String", + "defaultValue": null } ], "selections": [ @@ -127,6 +142,16 @@ return { "args": null, "storageKey": null }, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": null, + "args": null, + "concreteType": "IssueCommentConnection", + "plural": false, + "selections": v0 + }, { "kind": "FragmentSpread", "name": "prCommitsView_pullRequest", @@ -288,5 +313,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '2b7cc9778a3440738f809f76fcd3fd25'; +(node/*: any*/).hash = 'a1d134e400b0baa7d6a558165f406bb2'; module.exports = node; diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index 2c9b63ce32..22d9f6e8a8 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -373,6 +373,8 @@ export default createRefetchContainer(BarePullRequestDetailView, { timelineCursor: {type: "String"}, commitCount: {type: "Int!"}, commitCursor: {type: "String"}, + commentCount: {type: "Int!"}, + commentCursor: {type: "String"} ) { __typename @@ -383,6 +385,9 @@ export default createRefetchContainer(BarePullRequestDetailView, { ... on PullRequest { isCrossRepository changedFiles + comments { + totalCount + } ...prCommitsView_pullRequest @arguments(commitCount: $commitCount, commitCursor: $commitCursor) countedCommits: commits { totalCount @@ -415,7 +420,9 @@ export default createRefetchContainer(BarePullRequestDetailView, { $timelineCount: Int!, $timelineCursor: String, $commitCount: Int!, - $commitCursor: String + $commitCursor: String, + $commentCount: Int!, + $commentCursor: String ) { repository:node(id: $repoId) { ...prDetailView_repository @arguments( @@ -429,7 +436,9 @@ export default createRefetchContainer(BarePullRequestDetailView, { timelineCount: $timelineCount, timelineCursor: $timelineCursor, commitCount: $commitCount, - commitCursor: $commitCursor + commitCursor: $commitCursor, + commentCount: $commentCount, + commentCursor: $commentCursor ) } } From 2e215699175ed1301ec3fc4fbd2a735571ebe4ca Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 19 Dec 2018 11:51:21 -0800 Subject: [PATCH 2387/4847] add query to fetch reviews in the PullRequestDetailView Co-Authored-By: Vanessa Yuen --- .../issueishDetailContainerQuery.graphql.js | 457 ++++++++++++--- .../prDetailViewRefetchQuery.graphql.js | 541 +++++++++++++----- .../prDetailView_pullRequest.graphql.js | 386 +++++++++++-- lib/views/pr-detail-view.js | 57 ++ 4 files changed, 1163 insertions(+), 278 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 7b9148daa7..235deacd1c 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash b86bf34f5fb29cecb56582b73ffb540b + * @relayHash ac44654a5df27b896a882aa457ebf399 */ /* eslint-disable */ @@ -161,6 +161,82 @@ fragment prDetailView_pullRequest_1Etigl on PullRequest { comments { totalCount } + reviews(first: 100) { + pageInfo { + hasNextPage + endCursor + } + nodes { + id + body + commitId: commit { + oid + id + } + state + submittedAt + login: author { + __typename + login + ... on Node { + id + } + } + author { + __typename + avatarUrl + ... on Node { + id + } + } + comments(first: 100) { + pageInfo { + hasNextPage + endCursor + } + nodes { + id + pullRequestId: pullRequest { + number + id + } + databaseId + login: author { + __typename + login + ... on Node { + id + } + } + author { + __typename + avatarUrl + ... on Node { + id + } + } + body + path + commitSha: commit { + oid + id + } + diffHunk + position + originalPosition + originalCommitId: originalCommit { + oid + id + } + replyTo { + id + } + createdAt + url + } + } + } + } ...prCommitsView_pullRequest_38TpXw countedCommits: commits { totalCount @@ -725,6 +801,20 @@ v17 = [ } ], v18 = { + "kind": "ScalarField", + "alias": null, + "name": "endCursor", + "args": null, + "storageKey": null +}, +v19 = { + "kind": "ScalarField", + "alias": null, + "name": "hasNextPage", + "args": null, + "storageKey": null +}, +v20 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -733,43 +823,31 @@ v18 = { "concreteType": "PageInfo", "plural": false, "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "endCursor", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "hasNextPage", - "args": null, - "storageKey": null - } + v18, + v19 ] }, -v19 = { +v21 = { "kind": "ScalarField", "alias": null, "name": "cursor", "args": null, "storageKey": null }, -v20 = { +v22 = { "kind": "ScalarField", "alias": null, "name": "isCrossRepository", "args": null, "storageKey": null }, -v21 = [ +v23 = [ v4, v5, v13, v2 ], -v22 = { +v24 = { "kind": "InlineFragment", "type": "CrossReferencedEvent", "selections": [ @@ -780,7 +858,7 @@ v22 = { "args": null, "storageKey": null }, - v20, + v22, { "kind": "LinkedField", "alias": null, @@ -789,7 +867,7 @@ v22 = { "args": null, "concreteType": null, "plural": false, - "selections": v21 + "selections": v23 }, { "kind": "LinkedField", @@ -859,20 +937,20 @@ v22 = { } ] }, -v23 = [ +v25 = [ v4, v13, v5, v2 ], -v24 = { +v26 = { "kind": "ScalarField", "alias": null, "name": "createdAt", "args": null, "storageKey": null }, -v25 = { +v27 = { "kind": "InlineFragment", "type": "IssueComment", "selections": [ @@ -884,14 +962,14 @@ v25 = { "args": null, "concreteType": null, "plural": false, - "selections": v23 + "selections": v25 }, v12, - v24, + v26, v14 ] }, -v26 = { +v28 = { "kind": "LinkedField", "alias": null, "name": "user", @@ -904,14 +982,14 @@ v26 = { v2 ] }, -v27 = { +v29 = { "kind": "ScalarField", "alias": "sha", "name": "oid", "args": null, "storageKey": null }, -v28 = { +v30 = { "kind": "InlineFragment", "type": "Commit", "selections": [ @@ -925,7 +1003,7 @@ v28 = { "plural": false, "selections": [ v3, - v26, + v28, v13 ] }, @@ -940,7 +1018,7 @@ v28 = { "selections": [ v3, v13, - v26 + v28 ] }, { @@ -950,7 +1028,7 @@ v28 = { "args": null, "storageKey": null }, - v27, + v29, { "kind": "ScalarField", "alias": null, @@ -974,7 +1052,7 @@ v28 = { } ] }, -v29 = [ +v31 = [ { "kind": "ScalarField", "alias": null, @@ -983,7 +1061,7 @@ v29 = [ "storageKey": null } ], -v30 = { +v32 = { "kind": "LinkedField", "alias": null, "name": "reactionGroups", @@ -1007,11 +1085,11 @@ v30 = { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v29 + "selections": v31 } ] }, -v31 = [ +v33 = [ { "kind": "Variable", "name": "after", @@ -1025,7 +1103,35 @@ v31 = [ "type": "Int" } ], -v32 = [ +v34 = [ + { + "kind": "Literal", + "name": "first", + "value": 100, + "type": "Int" + } +], +v35 = { + "kind": "LinkedField", + "alias": null, + "name": "pageInfo", + "storageKey": null, + "args": null, + "concreteType": "PageInfo", + "plural": false, + "selections": [ + v19, + v18 + ] +}, +v36 = { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null +}, +v37 = [ { "kind": "ScalarField", "alias": null, @@ -1035,7 +1141,45 @@ v32 = [ }, v2 ], -v33 = { +v38 = { + "kind": "LinkedField", + "alias": "login", + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": v6 +}, +v39 = { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v4, + v13, + v2 + ] +}, +v40 = { + "kind": "ScalarField", + "alias": null, + "name": "path", + "args": null, + "storageKey": null +}, +v41 = { + "kind": "ScalarField", + "alias": null, + "name": "position", + "args": null, + "storageKey": null +}, +v42 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -1043,9 +1187,9 @@ v33 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v32 + "selections": v37 }, -v34 = { +v43 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -1053,14 +1197,14 @@ v34 = { "args": null, "concreteType": null, "plural": false, - "selections": v23 + "selections": v25 }; return { "kind": "Request", "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_2LgaQ1\n id\n }\n}\n\nfragment issueishDetailController_repository_2LgaQ1 on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_1Etigl\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_2LgaQ1\n id\n }\n}\n\nfragment issueishDetailController_repository_2LgaQ1 on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_1Etigl\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n body\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1177,7 +1321,7 @@ return { "concreteType": "IssueTimelineConnection", "plural": false, "selections": [ - v18, + v20, { "kind": "LinkedField", "alias": null, @@ -1187,7 +1331,7 @@ return { "concreteType": "IssueTimelineItemEdge", "plural": true, "selections": [ - v19, + v21, { "kind": "LinkedField", "alias": null, @@ -1199,9 +1343,9 @@ return { "selections": [ v4, v2, - v22, - v25, - v28 + v24, + v27, + v30 ] } ] @@ -1217,7 +1361,7 @@ return { "key": "IssueTimelineController_timeline", "filters": null }, - v30 + v32 ] } ] @@ -1242,11 +1386,11 @@ return { "alias": null, "name": "commits", "storageKey": null, - "args": v31, + "args": v33, "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ - v18, + v20, { "kind": "LinkedField", "alias": null, @@ -1256,7 +1400,7 @@ return { "concreteType": "PullRequestCommitEdge", "plural": true, "selections": [ - v19, + v21, { "kind": "LinkedField", "alias": null, @@ -1317,7 +1461,7 @@ return { "args": null, "storageKey": null }, - v27, + v29, v14 ] }, @@ -1333,7 +1477,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v31, + "args": v33, "handle": "connection", "key": "prCommitsView_commits", "filters": null @@ -1368,7 +1512,7 @@ return { v2 ] }, - v20, + v22, { "kind": "ScalarField", "alias": null, @@ -1384,7 +1528,149 @@ return { "args": null, "concreteType": "IssueCommentConnection", "plural": false, - "selections": v29 + "selections": v31 + }, + { + "kind": "LinkedField", + "alias": null, + "name": "reviews", + "storageKey": "reviews(first:100)", + "args": v34, + "concreteType": "PullRequestReviewConnection", + "plural": false, + "selections": [ + v35, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReview", + "plural": true, + "selections": [ + v2, + v36, + { + "kind": "LinkedField", + "alias": "commitId", + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v37 + }, + v11, + { + "kind": "ScalarField", + "alias": null, + "name": "submittedAt", + "args": null, + "storageKey": null + }, + v38, + v39, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": "comments(first:100)", + "args": v34, + "concreteType": "PullRequestReviewCommentConnection", + "plural": false, + "selections": [ + v35, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": true, + "selections": [ + { + "kind": "LinkedField", + "alias": "commitSha", + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v37 + }, + v2, + { + "kind": "ScalarField", + "alias": null, + "name": "databaseId", + "args": null, + "storageKey": null + }, + v38, + v39, + v36, + v40, + { + "kind": "LinkedField", + "alias": "pullRequestId", + "name": "pullRequest", + "storageKey": null, + "args": null, + "concreteType": "PullRequest", + "plural": false, + "selections": [ + v10, + v2 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "diffHunk", + "args": null, + "storageKey": null + }, + v41, + { + "kind": "ScalarField", + "alias": null, + "name": "originalPosition", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "originalCommitId", + "name": "originalCommit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v37 + }, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v2 + ] + }, + v26, + v14 + ] + } + ] + } + ] + } + ] }, v14, v10, @@ -1396,7 +1682,7 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v29 + "selections": v31 }, { "kind": "LinkedField", @@ -1540,7 +1826,7 @@ return { "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v18, + v20, { "kind": "LinkedField", "alias": null, @@ -1550,7 +1836,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v19, + v21, { "kind": "LinkedField", "alias": null, @@ -1562,25 +1848,18 @@ return { "selections": [ v4, v2, - v22, + v24, { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v33, + v42, { "kind": "LinkedField", "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 100, - "type": "Int" - } - ], + "args": v34, "concreteType": "CommitCommentConnection", "plural": false, "selections": [ @@ -1611,25 +1890,13 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v21 + "selections": v23 }, - v33, + v42, v12, - v24, - { - "kind": "ScalarField", - "alias": null, - "name": "path", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "position", - "args": null, - "storageKey": null - } + v26, + v40, + v41 ] } ] @@ -1642,7 +1909,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v34, + v43, { "kind": "LinkedField", "alias": null, @@ -1651,7 +1918,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v32 + "selections": v37 }, { "kind": "LinkedField", @@ -1661,17 +1928,17 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v32 + "selections": v37 }, - v24 + v26 ] }, { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v34, - v33, + v43, + v42, { "kind": "ScalarField", "alias": null, @@ -1679,11 +1946,11 @@ return { "args": null, "storageKey": null }, - v24 + v26 ] }, - v25, - v28 + v27, + v30 ] } ] @@ -1699,7 +1966,7 @@ return { "key": "prTimelineContainer_timeline", "filters": null }, - v30 + v32 ] } ] diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index eb62f5be7c..ac451dad1e 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 690cc435f3a8f5738ba609aa81c359b4 + * @relayHash 3a8852bc38dab1b82916974271e7eec4 */ /* eslint-disable */ @@ -77,6 +77,82 @@ fragment prDetailView_pullRequest_1Etigl on PullRequest { comments { totalCount } + reviews(first: 100) { + pageInfo { + hasNextPage + endCursor + } + nodes { + id + body + commitId: commit { + oid + id + } + state + submittedAt + login: author { + __typename + login + ... on Node { + id + } + } + author { + __typename + avatarUrl + ... on Node { + id + } + } + comments(first: 100) { + pageInfo { + hasNextPage + endCursor + } + nodes { + id + pullRequestId: pullRequest { + number + id + } + databaseId + login: author { + __typename + login + ... on Node { + id + } + } + author { + __typename + avatarUrl + ... on Node { + id + } + } + body + path + commitSha: commit { + oid + id + } + diffHunk + position + originalPosition + originalCommitId: originalCommit { + oid + id + } + replyTo { + id + } + createdAt + url + } + } + } + } ...prCommitsView_pullRequest_38TpXw countedCommits: commits { totalCount @@ -537,7 +613,7 @@ v10 = { v11 = { "kind": "ScalarField", "alias": null, - "name": "number", + "name": "state", "args": null, "storageKey": null }, @@ -557,14 +633,125 @@ v13 = [ "storageKey": null } ], -v14 = { +v14 = [ + { + "kind": "Literal", + "name": "first", + "value": 100, + "type": "Int" + } +], +v15 = { + "kind": "ScalarField", + "alias": null, + "name": "hasNextPage", + "args": null, + "storageKey": null +}, +v16 = { + "kind": "ScalarField", + "alias": null, + "name": "endCursor", + "args": null, + "storageKey": null +}, +v17 = { + "kind": "LinkedField", + "alias": null, + "name": "pageInfo", + "storageKey": null, + "args": null, + "concreteType": "PageInfo", + "plural": false, + "selections": [ + v15, + v16 + ] +}, +v18 = { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null +}, +v19 = [ + { + "kind": "ScalarField", + "alias": null, + "name": "oid", + "args": null, + "storageKey": null + }, + v6 +], +v20 = { + "kind": "LinkedField", + "alias": "login", + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": v9 +}, +v21 = { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null +}, +v22 = { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v5, + v21, + v6 + ] +}, +v23 = { + "kind": "ScalarField", + "alias": null, + "name": "path", + "args": null, + "storageKey": null +}, +v24 = { + "kind": "ScalarField", + "alias": null, + "name": "number", + "args": null, + "storageKey": null +}, +v25 = { + "kind": "ScalarField", + "alias": null, + "name": "position", + "args": null, + "storageKey": null +}, +v26 = { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null +}, +v27 = { "kind": "ScalarField", "alias": null, "name": "url", "args": null, "storageKey": null }, -v15 = [ +v28 = [ { "kind": "Variable", "name": "after", @@ -578,7 +765,7 @@ v15 = [ "type": "Int" } ], -v16 = { +v29 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -587,68 +774,42 @@ v16 = { "concreteType": "PageInfo", "plural": false, "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "endCursor", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "hasNextPage", - "args": null, - "storageKey": null - } + v16, + v15 ] }, -v17 = { +v30 = { "kind": "ScalarField", "alias": null, "name": "cursor", "args": null, "storageKey": null }, -v18 = { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null -}, -v19 = { +v31 = { "kind": "ScalarField", "alias": "sha", "name": "oid", "args": null, "storageKey": null }, -v20 = { - "kind": "ScalarField", - "alias": null, - "name": "state", - "args": null, - "storageKey": null -}, -v21 = { +v32 = { "kind": "ScalarField", "alias": null, "name": "title", "args": null, "storageKey": null }, -v22 = { +v33 = { "kind": "ScalarField", "alias": null, "name": "bodyHTML", "args": null, "storageKey": null }, -v23 = [ - v14 +v34 = [ + v27 ], -v24 = [ +v35 = [ { "kind": "Variable", "name": "after", @@ -662,23 +823,13 @@ v24 = [ "type": "Int" } ], -v25 = [ +v36 = [ v5, v8, - v18, + v21, v6 ], -v26 = [ - { - "kind": "ScalarField", - "alias": null, - "name": "oid", - "args": null, - "storageKey": null - }, - v6 -], -v27 = { +v37 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -686,22 +837,15 @@ v27 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v26 + "selections": v19 }, -v28 = { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null -}, -v29 = [ +v38 = [ v5, - v18, + v21, v8, v6 ], -v30 = { +v39 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -709,9 +853,9 @@ v30 = { "args": null, "concreteType": null, "plural": false, - "selections": v29 + "selections": v38 }, -v31 = { +v40 = { "kind": "LinkedField", "alias": null, "name": "user", @@ -729,7 +873,7 @@ return { "operationKind": "query", "name": "prDetailViewRefetchQuery", "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_1Etigl\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_1Etigl\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n body\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -863,17 +1007,159 @@ return { "plural": false, "selections": v13 }, - v14, + { + "kind": "LinkedField", + "alias": null, + "name": "reviews", + "storageKey": "reviews(first:100)", + "args": v14, + "concreteType": "PullRequestReviewConnection", + "plural": false, + "selections": [ + v17, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReview", + "plural": true, + "selections": [ + v6, + v18, + { + "kind": "LinkedField", + "alias": "commitId", + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v19 + }, + v11, + { + "kind": "ScalarField", + "alias": null, + "name": "submittedAt", + "args": null, + "storageKey": null + }, + v20, + v22, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": "comments(first:100)", + "args": v14, + "concreteType": "PullRequestReviewCommentConnection", + "plural": false, + "selections": [ + v17, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": true, + "selections": [ + { + "kind": "LinkedField", + "alias": "commitSha", + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v19 + }, + v6, + { + "kind": "ScalarField", + "alias": null, + "name": "databaseId", + "args": null, + "storageKey": null + }, + v20, + v22, + v18, + v23, + { + "kind": "LinkedField", + "alias": "pullRequestId", + "name": "pullRequest", + "storageKey": null, + "args": null, + "concreteType": "PullRequest", + "plural": false, + "selections": [ + v24, + v6 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "diffHunk", + "args": null, + "storageKey": null + }, + v25, + { + "kind": "ScalarField", + "alias": null, + "name": "originalPosition", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "originalCommitId", + "name": "originalCommit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v19 + }, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v6 + ] + }, + v26, + v27 + ] + } + ] + } + ] + } + ] + }, + v27, { "kind": "LinkedField", "alias": null, "name": "commits", "storageKey": null, - "args": v15, + "args": v28, "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ - v16, + v29, { "kind": "LinkedField", "alias": null, @@ -883,7 +1169,7 @@ return { "concreteType": "PullRequestCommitEdge", "plural": true, "selections": [ - v17, + v30, { "kind": "LinkedField", "alias": null, @@ -912,7 +1198,7 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v18, + v21, v7, { "kind": "ScalarField", @@ -944,8 +1230,8 @@ return { "args": null, "storageKey": null }, - v19, - v14 + v31, + v27 ] }, v6, @@ -960,7 +1246,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v15, + "args": v28, "handle": "connection", "key": "prCommitsView_commits", "filters": null @@ -1027,7 +1313,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v20, + v11, { "kind": "LinkedField", "alias": null, @@ -1038,7 +1324,7 @@ return { "plural": true, "selections": [ v6, - v20, + v11, { "kind": "ScalarField", "alias": null, @@ -1075,9 +1361,9 @@ return { } ] }, - v20, - v21, - v22, + v24, + v32, + v33, { "kind": "ScalarField", "alias": null, @@ -1103,17 +1389,17 @@ return { "selections": [ v5, v8, - v18, + v21, v6, { "kind": "InlineFragment", "type": "Bot", - "selections": v23 + "selections": v34 }, { "kind": "InlineFragment", "type": "User", - "selections": v23 + "selections": v34 } ] }, @@ -1145,11 +1431,11 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": v24, + "args": v35, "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v16, + v29, { "kind": "LinkedField", "alias": null, @@ -1159,7 +1445,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v17, + v30, { "kind": "LinkedField", "alias": null, @@ -1191,7 +1477,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v25 + "selections": v36 }, { "kind": "LinkedField", @@ -1229,9 +1515,9 @@ return { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v11, - v21, - v14, + v24, + v32, + v27, { "kind": "ScalarField", "alias": "prState", @@ -1245,9 +1531,9 @@ return { "kind": "InlineFragment", "type": "Issue", "selections": [ - v11, - v21, - v14, + v24, + v32, + v27, { "kind": "ScalarField", "alias": "issueState", @@ -1265,20 +1551,13 @@ return { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v27, + v37, { "kind": "LinkedField", "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 100, - "type": "Int" - } - ], + "args": v14, "concreteType": "CommitCommentConnection", "plural": false, "selections": [ @@ -1309,25 +1588,13 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v25 + "selections": v36 }, - v27, - v22, - v28, - { - "kind": "ScalarField", - "alias": null, - "name": "path", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "position", - "args": null, - "storageKey": null - } + v37, + v33, + v26, + v23, + v25 ] } ] @@ -1340,7 +1607,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v30, + v39, { "kind": "LinkedField", "alias": null, @@ -1349,7 +1616,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v26 + "selections": v19 }, { "kind": "LinkedField", @@ -1359,17 +1626,17 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v26 + "selections": v19 }, - v28 + v26 ] }, { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v30, - v27, + v39, + v37, { "kind": "ScalarField", "alias": null, @@ -1377,7 +1644,7 @@ return { "args": null, "storageKey": null }, - v28 + v26 ] }, { @@ -1392,11 +1659,11 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v29 + "selections": v38 }, - v22, - v28, - v14 + v33, + v26, + v27 ] }, { @@ -1413,8 +1680,8 @@ return { "plural": false, "selections": [ v7, - v31, - v18 + v40, + v21 ] }, { @@ -1427,8 +1694,8 @@ return { "plural": false, "selections": [ v7, - v18, - v31 + v21, + v40 ] }, { @@ -1438,7 +1705,7 @@ return { "args": null, "storageKey": null }, - v19, + v31, { "kind": "ScalarField", "alias": null, @@ -1472,7 +1739,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v24, + "args": v35, "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null diff --git a/lib/views/__generated__/prDetailView_pullRequest.graphql.js b/lib/views/__generated__/prDetailView_pullRequest.graphql.js index b510f50297..28adeb4059 100644 --- a/lib/views/__generated__/prDetailView_pullRequest.graphql.js +++ b/lib/views/__generated__/prDetailView_pullRequest.graphql.js @@ -11,6 +11,7 @@ import type { ConcreteFragment } from 'relay-runtime'; type prCommitsView_pullRequest$ref = any; type prStatusesView_pullRequest$ref = any; type prTimelineController_pullRequest$ref = any; +export type PullRequestReviewState = "APPROVED" | "CHANGES_REQUESTED" | "COMMENTED" | "DISMISSED" | "PENDING" | "%future added value"; export type PullRequestState = "CLOSED" | "MERGED" | "OPEN" | "%future added value"; export type ReactionContent = "CONFUSED" | "HEART" | "HOORAY" | "LAUGH" | "THUMBS_DOWN" | "THUMBS_UP" | "%future added value"; import type { FragmentReference } from "relay-runtime"; @@ -22,6 +23,62 @@ export type prDetailView_pullRequest = {| +comments: {| +totalCount: number |}, + +reviews: ?{| + +pageInfo: {| + +hasNextPage: boolean, + +endCursor: ?string, + |}, + +nodes: ?$ReadOnlyArray, + |}, + |}>, + |}, +countedCommits: {| +totalCount: number |}, @@ -51,7 +108,14 @@ export type prDetailView_pullRequest = {| const node/*: ConcreteFragment*/ = (function(){ -var v0 = [ +var v0 = { + "kind": "ScalarField", + "alias": null, + "name": "state", + "args": null, + "storageKey": null +}, +v1 = [ { "kind": "ScalarField", "alias": null, @@ -60,15 +124,116 @@ var v0 = [ "storageKey": null } ], -v1 = { +v2 = [ + { + "kind": "Literal", + "name": "first", + "value": 100, + "type": "Int" + } +], +v3 = { + "kind": "LinkedField", + "alias": null, + "name": "pageInfo", + "storageKey": null, + "args": null, + "concreteType": "PageInfo", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "hasNextPage", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "endCursor", + "args": null, + "storageKey": null + } + ] +}, +v4 = { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null +}, +v5 = { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null +}, +v6 = [ + { + "kind": "ScalarField", + "alias": null, + "name": "oid", + "args": null, + "storageKey": null + } +], +v7 = { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null +}, +v8 = { + "kind": "LinkedField", + "alias": "login", + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v7 + ] +}, +v9 = { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null +}, +v10 = { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v9 + ] +}, +v11 = { + "kind": "ScalarField", + "alias": null, + "name": "number", + "args": null, + "storageKey": null +}, +v12 = { "kind": "ScalarField", "alias": null, "name": "url", "args": null, "storageKey": null }, -v2 = [ - v1 +v13 = [ + v12 ]; return { "kind": "Fragment", @@ -114,13 +279,7 @@ return { } ], "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "number", - "args": null, - "storageKey": null - }, + v0, { "kind": "ScalarField", "alias": null, @@ -150,7 +309,166 @@ return { "args": null, "concreteType": "IssueCommentConnection", "plural": false, - "selections": v0 + "selections": v1 + }, + { + "kind": "LinkedField", + "alias": null, + "name": "reviews", + "storageKey": "reviews(first:100)", + "args": v2, + "concreteType": "PullRequestReviewConnection", + "plural": false, + "selections": [ + v3, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReview", + "plural": true, + "selections": [ + v4, + v5, + { + "kind": "LinkedField", + "alias": "commitId", + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v6 + }, + v0, + { + "kind": "ScalarField", + "alias": null, + "name": "submittedAt", + "args": null, + "storageKey": null + }, + v8, + v10, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": "comments(first:100)", + "args": v2, + "concreteType": "PullRequestReviewCommentConnection", + "plural": false, + "selections": [ + v3, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": true, + "selections": [ + { + "kind": "LinkedField", + "alias": "commitSha", + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v6 + }, + v4, + { + "kind": "ScalarField", + "alias": null, + "name": "databaseId", + "args": null, + "storageKey": null + }, + v8, + v10, + v5, + { + "kind": "ScalarField", + "alias": null, + "name": "path", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "pullRequestId", + "name": "pullRequest", + "storageKey": null, + "args": null, + "concreteType": "PullRequest", + "plural": false, + "selections": [ + v11 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "diffHunk", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "position", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "originalPosition", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "originalCommitId", + "name": "originalCommit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v6 + }, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v4 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + v12 + ] + } + ] + } + ] + } + ] }, { "kind": "FragmentSpread", @@ -178,27 +496,15 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v0 + "selections": v1 }, { "kind": "FragmentSpread", "name": "prStatusesView_pullRequest", "args": null }, - { - "kind": "ScalarField", - "alias": null, - "name": "state", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null - }, + v4, + v11, { "kind": "ScalarField", "alias": null, @@ -236,29 +542,17 @@ return { "concreteType": null, "plural": false, "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null - }, + v7, + v9, { "kind": "InlineFragment", "type": "Bot", - "selections": v2 + "selections": v13 }, { "kind": "InlineFragment", "type": "User", - "selections": v2 + "selections": v13 } ] }, @@ -280,7 +574,7 @@ return { } ] }, - v1, + v12, { "kind": "LinkedField", "alias": null, @@ -305,7 +599,7 @@ return { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v0 + "selections": v1 } ] } @@ -313,5 +607,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'a1d134e400b0baa7d6a558165f406bb2'; +(node/*: any*/).hash = '6b79c21bb0d8e16f2d4c094d0fd055c8'; module.exports = node; diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index 22d9f6e8a8..63762085c3 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -218,6 +218,7 @@ export class BarePullRequestDetailView extends React.Component { render() { const repo = this.props.repository; const pullRequest = this.props.pullRequest; + console.log(pullRequest); return (
    @@ -388,6 +389,62 @@ export default createRefetchContainer(BarePullRequestDetailView, { comments { totalCount } + reviews(first: 100) { + pageInfo { + hasNextPage + endCursor + } + nodes { + id + body + commitId: commit { + oid + } + state + submittedAt + login: author { + login + } + author { + avatarUrl + } + comments(first: 100) { + pageInfo { + hasNextPage + endCursor + } + nodes { + id + pullRequestId: pullRequest { + number + } + databaseId + login: author { + login + } + author { + avatarUrl + } + body + path + commitSha: commit { + oid + } + diffHunk + position + originalPosition + originalCommitId: originalCommit { + oid + } + replyTo { + id + } + createdAt + url + } + } + } + } ...prCommitsView_pullRequest @arguments(commitCount: $commitCount, commitCursor: $commitCursor) countedCommits: commits { totalCount From a5ea73a6513524c8fa9d659f992259479ec635c3 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 19 Dec 2018 12:51:01 -0800 Subject: [PATCH 2388/4847] render some comments, woo Co-Authored-By: Vanessa Yuen --- lib/views/multi-file-patch-view.js | 94 ++++++++++++++++++------------ lib/views/pr-detail-view.js | 2 +- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index b8d46976f8..96e57447e4 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -179,12 +179,28 @@ export default class MultiFilePatchView extends React.Component { {this.renderCommands()}
    + {this.renderComments()} {this.props.multiFilePatch.anyPresent() ? this.renderNonEmptyPatch() : this.renderEmptyPatch()}
    ); } + renderComments() { + if (this.props.reviews) { + return this.props.reviews.nodes.map(review => { + return review.comments.nodes.map(comment => { + return ( +
    + + {comment.body} +
    + ); + }); + }); + } + } + renderCommands() { if (this.props.itemType === CommitDetailItem || this.props.itemType === IssueishDetailItem) { return ( @@ -235,49 +251,50 @@ export default class MultiFilePatchView extends React.Component { renderNonEmptyPatch() { return ( - - - - - {this.props.config.get('github.showDiffIconGutter') && ( + + + + + {this.props.config.get('github.showDiffIconGutter') && ( + )} {this.props.multiFilePatch.getFilePatches().map(this.renderFilePatchDecorations)} @@ -305,6 +322,7 @@ export default class MultiFilePatchView extends React.Component { )} + ); } diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index 63762085c3..80d3979fc1 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -209,6 +209,7 @@ export class BarePullRequestDetailView extends React.Component { destroy={this.props.destroy} shouldRefetch={this.state.refreshing} + reviews={this.props.pullRequest.reviews} /> @@ -218,7 +219,6 @@ export class BarePullRequestDetailView extends React.Component { render() { const repo = this.props.repository; const pullRequest = this.props.pullRequest; - console.log(pullRequest); return (
    From 346b2dce071f4a4d4a4f5f100806a022cfee69de Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 19 Dec 2018 12:55:13 -0800 Subject: [PATCH 2389/4847] maybe my avatar does not need to be the giantest. Co-Authored-By: Vanessa Yuen --- lib/views/multi-file-patch-view.js | 2 +- styles/file-patch-view.less | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 96e57447e4..6e975eafd5 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -192,7 +192,7 @@ export default class MultiFilePatchView extends React.Component { return review.comments.nodes.map(comment => { return (
    - + {comment.body}
    ); diff --git a/styles/file-patch-view.less b/styles/file-patch-view.less index 62ba2b660b..208628f173 100644 --- a/styles/file-patch-view.less +++ b/styles/file-patch-view.less @@ -142,6 +142,11 @@ } } + &-commentAuthorAvatar { + height: 16px; + width: 16px; + } + &-metaDetails { padding: @component-padding; } From 8b8f11206aa74b1222c7696c0db877f0a50b97a0 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 19 Dec 2018 13:21:04 -0800 Subject: [PATCH 2390/4847] :fire: unnecessary fragment --- lib/views/multi-file-patch-view.js | 132 ++++++++++++++--------------- 1 file changed, 65 insertions(+), 67 deletions(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 6e975eafd5..60225d84a1 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -251,78 +251,76 @@ export default class MultiFilePatchView extends React.Component { renderNonEmptyPatch() { return ( - - - + + + + + {this.props.config.get('github.showDiffIconGutter') && ( - - {this.props.config.get('github.showDiffIconGutter') && ( - - )} - - {this.props.multiFilePatch.getFilePatches().map(this.renderFilePatchDecorations)} - - {this.renderLineDecorations( - Array.from(this.props.selectedRows, row => Range.fromObject([[row, 0], [row, Infinity]])), - 'github-FilePatchView-line--selected', - {gutter: true, icon: true, line: true}, - )} - - {this.renderDecorationsOnLayer( - this.props.multiFilePatch.getAdditionLayer(), - 'github-FilePatchView-line--added', - {icon: true, line: true}, - )} - {this.renderDecorationsOnLayer( - this.props.multiFilePatch.getDeletionLayer(), - 'github-FilePatchView-line--deleted', - {icon: true, line: true}, - )} - {this.renderDecorationsOnLayer( - this.props.multiFilePatch.getNoNewlineLayer(), - 'github-FilePatchView-line--nonewline', - {icon: true, line: true}, - )} - - - + )} + + {this.props.multiFilePatch.getFilePatches().map(this.renderFilePatchDecorations)} + + {this.renderLineDecorations( + Array.from(this.props.selectedRows, row => Range.fromObject([[row, 0], [row, Infinity]])), + 'github-FilePatchView-line--selected', + {gutter: true, icon: true, line: true}, + )} + + {this.renderDecorationsOnLayer( + this.props.multiFilePatch.getAdditionLayer(), + 'github-FilePatchView-line--added', + {icon: true, line: true}, + )} + {this.renderDecorationsOnLayer( + this.props.multiFilePatch.getDeletionLayer(), + 'github-FilePatchView-line--deleted', + {icon: true, line: true}, + )} + {this.renderDecorationsOnLayer( + this.props.multiFilePatch.getNoNewlineLayer(), + 'github-FilePatchView-line--nonewline', + {icon: true, line: true}, + )} + + ); } From 442033dc0875a208516861161c7094ac884a04fe Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 19 Dec 2018 14:10:26 -0800 Subject: [PATCH 2391/4847] fix borked indentation --- lib/views/multi-file-patch-view.js | 54 +++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 60225d84a1..a558509609 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -294,33 +294,33 @@ export default class MultiFilePatchView extends React.Component { onMouseDown={this.didMouseDownOnLineNumber} onMouseMove={this.didMouseMoveOnLineNumber} /> - )} - - {this.props.multiFilePatch.getFilePatches().map(this.renderFilePatchDecorations)} - - {this.renderLineDecorations( - Array.from(this.props.selectedRows, row => Range.fromObject([[row, 0], [row, Infinity]])), - 'github-FilePatchView-line--selected', - {gutter: true, icon: true, line: true}, - )} - - {this.renderDecorationsOnLayer( - this.props.multiFilePatch.getAdditionLayer(), - 'github-FilePatchView-line--added', - {icon: true, line: true}, - )} - {this.renderDecorationsOnLayer( - this.props.multiFilePatch.getDeletionLayer(), - 'github-FilePatchView-line--deleted', - {icon: true, line: true}, - )} - {this.renderDecorationsOnLayer( - this.props.multiFilePatch.getNoNewlineLayer(), - 'github-FilePatchView-line--nonewline', - {icon: true, line: true}, - )} - - + )} + + {this.props.multiFilePatch.getFilePatches().map(this.renderFilePatchDecorations)} + + {this.renderLineDecorations( + Array.from(this.props.selectedRows, row => Range.fromObject([[row, 0], [row, Infinity]])), + 'github-FilePatchView-line--selected', + {gutter: true, icon: true, line: true}, + )} + + {this.renderDecorationsOnLayer( + this.props.multiFilePatch.getAdditionLayer(), + 'github-FilePatchView-line--added', + {icon: true, line: true}, + )} + {this.renderDecorationsOnLayer( + this.props.multiFilePatch.getDeletionLayer(), + 'github-FilePatchView-line--deleted', + {icon: true, line: true}, + )} + {this.renderDecorationsOnLayer( + this.props.multiFilePatch.getNoNewlineLayer(), + 'github-FilePatchView-line--nonewline', + {icon: true, line: true}, + )} + + ); } From 1b1a7fc1466f89330aa4e4c108b5fa0d58fceac4 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 20 Dec 2018 18:37:05 +0100 Subject: [PATCH 2392/4847] get the comments to render as a decoration block --- lib/views/multi-file-patch-view.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index a558509609..74d02795de 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -179,7 +179,6 @@ export default class MultiFilePatchView extends React.Component { {this.renderCommands()}
    - {this.renderComments()} {this.props.multiFilePatch.anyPresent() ? this.renderNonEmptyPatch() : this.renderEmptyPatch()}
    @@ -190,12 +189,21 @@ export default class MultiFilePatchView extends React.Component { if (this.props.reviews) { return this.props.reviews.nodes.map(review => { return review.comments.nodes.map(comment => { - return ( -
    - - {comment.body} -
    - ); + if (comment.position !== null) { + console.log(comment); + const range = new Range([comment.position, 0], [comment.position, 0]) + return ( + + +
    + + {comment.body} +
    +
    +
    + ); + } + return null; }); }); } @@ -296,6 +304,7 @@ export default class MultiFilePatchView extends React.Component { /> )} + {this.renderComments()} {this.props.multiFilePatch.getFilePatches().map(this.renderFilePatchDecorations)} {this.renderLineDecorations( From d0adf4392cdc70724e6089a54c083a14c6eb50e4 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 20 Dec 2018 20:18:59 +0100 Subject: [PATCH 2393/4847] make comments show up at the (somewhat) correct location Co-Authored-By: Tilde Ann Thurium --- lib/models/patch/multi-file-patch.js | 4 ++++ lib/views/multi-file-patch-view.js | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index c329d66ff4..7336ca1381 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -71,6 +71,10 @@ export default class MultiFilePatch { return this.filePatches; } + getFilePatchByPath(path) { + return this.filePatches.find(filePatch => filePatch.getPath() === path); + } + getPathSet() { return this.getFilePatches().reduce((pathSet, filePatch) => { for (const file of [filePatch.getOldFile(), filePatch.getNewFile()]) { diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 985627c04c..ba7fe37b6d 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -1,7 +1,7 @@ import React, {Fragment} from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; -import {Range} from 'atom'; +import {Point, Range} from 'atom'; import {CompositeDisposable} from 'event-kit'; import {autobind} from '../helpers'; @@ -186,12 +186,17 @@ export default class MultiFilePatchView extends React.Component { } renderComments() { + // 1. need to figure out which file patch the comment belongs to + // 2. how many hunks since beginning of file till comment + // 3. filePatch.beginRange + number of hunks + comment.position + if (this.props.reviews) { return this.props.reviews.nodes.map(review => { return review.comments.nodes.map(comment => { if (comment.position !== null) { - console.log(comment); - const range = new Range([comment.position, 0], [comment.position, 0]) + const filePatch = this.props.multiFilePatch.getFilePatchByPath(comment.path); + const commentStartPoint = filePatch.getStartRange().start.translate(new Point(comment.position, 0)); + const range = new Range(commentStartPoint, commentStartPoint); return ( From 5f4f5137bb97e70952b66f0e0742b5a0cea8bf71 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 20 Dec 2018 20:58:40 +0100 Subject: [PATCH 2394/4847] put in comment position also Co-Authored-By: Tilde Ann Thurium --- lib/views/multi-file-patch-view.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index ba7fe37b6d..0b7282dda1 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -203,6 +203,7 @@ export default class MultiFilePatchView extends React.Component {
    {comment.body} + {comment.position}
    From b341c5dd9c1cca132a260a28fd5bce55abc541ac Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 20 Dec 2018 17:24:21 -0800 Subject: [PATCH 2395/4847] make `PullRequestCommentsView` into its own component. --- lib/views/multi-file-patch-view.js | 35 +++------------------------ lib/views/pr-comments-view.js | 38 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 32 deletions(-) create mode 100644 lib/views/pr-comments-view.js diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 0b7282dda1..2eaa0b89e8 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -1,7 +1,7 @@ import React, {Fragment} from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; -import {Point, Range} from 'atom'; +import {Range} from 'atom'; import {CompositeDisposable} from 'event-kit'; import {autobind} from '../helpers'; @@ -15,6 +15,7 @@ import Commands, {Command} from '../atom/commands'; import FilePatchHeaderView from './file-patch-header-view'; import FilePatchMetaView from './file-patch-meta-view'; import HunkHeaderView from './hunk-header-view'; +import PullRequestCommentsView from './pr-comments-view'; import RefHolder from '../models/ref-holder'; import ChangedFileItem from '../items/changed-file-item'; import CommitDetailItem from '../items/commit-detail-item'; @@ -185,36 +186,6 @@ export default class MultiFilePatchView extends React.Component { ); } - renderComments() { - // 1. need to figure out which file patch the comment belongs to - // 2. how many hunks since beginning of file till comment - // 3. filePatch.beginRange + number of hunks + comment.position - - if (this.props.reviews) { - return this.props.reviews.nodes.map(review => { - return review.comments.nodes.map(comment => { - if (comment.position !== null) { - const filePatch = this.props.multiFilePatch.getFilePatchByPath(comment.path); - const commentStartPoint = filePatch.getStartRange().start.translate(new Point(comment.position, 0)); - const range = new Range(commentStartPoint, commentStartPoint); - return ( - - -
    - - {comment.body} - {comment.position} -
    -
    -
    - ); - } - return null; - }); - }); - } - } - renderCommands() { if (this.props.itemType === CommitDetailItem || this.props.itemType === IssueishDetailItem) { return ( @@ -310,7 +281,7 @@ export default class MultiFilePatchView extends React.Component { /> )} - {this.renderComments()} + {this.props.multiFilePatch.getFilePatches().map(this.renderFilePatchDecorations)} {this.renderLineDecorations( diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js new file mode 100644 index 0000000000..aab51871f8 --- /dev/null +++ b/lib/views/pr-comments-view.js @@ -0,0 +1,38 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Point, Range} from 'atom'; + +import Marker from '../atom/marker'; +import MarkerLayer from '../atom/marker-layer'; +import Decoration from '../atom/decoration'; + +import Timeago from './timeago'; + +export default class PullRequestCommentsView extends React.Component { + + render() { + + if (this.props.reviews) { + return this.props.reviews.nodes.map(review => { + return review.comments.nodes.map(comment => { + if (comment.position !== null) { + const filePatch = this.props.multiFilePatch.getFilePatchByPath(comment.path); + const commentStartPoint = filePatch.getStartRange().start.translate(new Point(comment.position, 0)); + const range = new Range(commentStartPoint, commentStartPoint); + return ( + + +
    + + {comment.body} +
    +
    +
    + ); + } + return null; + }); + }); + } + } +} From 847829c4f5aacc372c7e479ce7c7de9b30fee9b4 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 20 Dec 2018 17:44:04 -0800 Subject: [PATCH 2396/4847] render comment timestamp --- .../issueishDetailContainerQuery.graphql.js | 147 +++++++-------- .../prDetailViewRefetchQuery.graphql.js | 169 +++++++++--------- .../prDetailView_pullRequest.graphql.js | 62 ++++--- lib/views/pr-comments-view.js | 8 +- lib/views/pr-detail-view.js | 1 + 5 files changed, 203 insertions(+), 184 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 235deacd1c..1a24ef5d10 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash ac44654a5df27b896a882aa457ebf399 + * @relayHash 46254fc27ddba523ae7fba989c5e320a */ /* eslint-disable */ @@ -211,6 +211,7 @@ fragment prDetailView_pullRequest_1Etigl on PullRequest { author { __typename avatarUrl + login ... on Node { id } @@ -944,32 +945,33 @@ v25 = [ v2 ], v26 = { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": v25 +}, +v27 = { "kind": "ScalarField", "alias": null, "name": "createdAt", "args": null, "storageKey": null }, -v27 = { +v28 = { "kind": "InlineFragment", "type": "IssueComment", "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": v25 - }, - v12, v26, + v12, + v27, v14 ] }, -v28 = { +v29 = { "kind": "LinkedField", "alias": null, "name": "user", @@ -982,14 +984,14 @@ v28 = { v2 ] }, -v29 = { +v30 = { "kind": "ScalarField", "alias": "sha", "name": "oid", "args": null, "storageKey": null }, -v30 = { +v31 = { "kind": "InlineFragment", "type": "Commit", "selections": [ @@ -1003,7 +1005,7 @@ v30 = { "plural": false, "selections": [ v3, - v28, + v29, v13 ] }, @@ -1018,7 +1020,7 @@ v30 = { "selections": [ v3, v13, - v28 + v29 ] }, { @@ -1028,7 +1030,7 @@ v30 = { "args": null, "storageKey": null }, - v29, + v30, { "kind": "ScalarField", "alias": null, @@ -1052,7 +1054,7 @@ v30 = { } ] }, -v31 = [ +v32 = [ { "kind": "ScalarField", "alias": null, @@ -1061,7 +1063,7 @@ v31 = [ "storageKey": null } ], -v32 = { +v33 = { "kind": "LinkedField", "alias": null, "name": "reactionGroups", @@ -1085,11 +1087,11 @@ v32 = { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v31 + "selections": v32 } ] }, -v33 = [ +v34 = [ { "kind": "Variable", "name": "after", @@ -1103,7 +1105,7 @@ v33 = [ "type": "Int" } ], -v34 = [ +v35 = [ { "kind": "Literal", "name": "first", @@ -1111,7 +1113,7 @@ v34 = [ "type": "Int" } ], -v35 = { +v36 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -1124,14 +1126,14 @@ v35 = { v18 ] }, -v36 = { +v37 = { "kind": "ScalarField", "alias": null, "name": "body", "args": null, "storageKey": null }, -v37 = [ +v38 = [ { "kind": "ScalarField", "alias": null, @@ -1141,7 +1143,7 @@ v37 = [ }, v2 ], -v38 = { +v39 = { "kind": "LinkedField", "alias": "login", "name": "author", @@ -1151,20 +1153,6 @@ v38 = { "plural": false, "selections": v6 }, -v39 = { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v4, - v13, - v2 - ] -}, v40 = { "kind": "ScalarField", "alias": null, @@ -1187,7 +1175,7 @@ v42 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": v38 }, v43 = { "kind": "LinkedField", @@ -1204,7 +1192,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_2LgaQ1\n id\n }\n}\n\nfragment issueishDetailController_repository_2LgaQ1 on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_1Etigl\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n body\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_2LgaQ1\n id\n }\n}\n\nfragment issueishDetailController_repository_2LgaQ1 on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_1Etigl\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1344,8 +1332,8 @@ return { v4, v2, v24, - v27, - v30 + v28, + v31 ] } ] @@ -1361,7 +1349,7 @@ return { "key": "IssueTimelineController_timeline", "filters": null }, - v32 + v33 ] } ] @@ -1386,7 +1374,7 @@ return { "alias": null, "name": "commits", "storageKey": null, - "args": v33, + "args": v34, "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ @@ -1461,7 +1449,7 @@ return { "args": null, "storageKey": null }, - v29, + v30, v14 ] }, @@ -1477,7 +1465,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v33, + "args": v34, "handle": "connection", "key": "prCommitsView_commits", "filters": null @@ -1528,18 +1516,18 @@ return { "args": null, "concreteType": "IssueCommentConnection", "plural": false, - "selections": v31 + "selections": v32 }, { "kind": "LinkedField", "alias": null, "name": "reviews", "storageKey": "reviews(first:100)", - "args": v34, + "args": v35, "concreteType": "PullRequestReviewConnection", "plural": false, "selections": [ - v35, + v36, { "kind": "LinkedField", "alias": null, @@ -1550,7 +1538,7 @@ return { "plural": true, "selections": [ v2, - v36, + v37, { "kind": "LinkedField", "alias": "commitId", @@ -1559,7 +1547,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": v38 }, v11, { @@ -1569,18 +1557,31 @@ return { "args": null, "storageKey": null }, - v38, v39, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v4, + v13, + v2 + ] + }, { "kind": "LinkedField", "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v34, + "args": v35, "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ - v35, + v36, { "kind": "LinkedField", "alias": null, @@ -1598,7 +1599,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": v38 }, v2, { @@ -1608,9 +1609,9 @@ return { "args": null, "storageKey": null }, - v38, v39, - v36, + v26, + v37, v40, { "kind": "LinkedField", @@ -1648,7 +1649,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": v38 }, { "kind": "LinkedField", @@ -1662,7 +1663,7 @@ return { v2 ] }, - v26, + v27, v14 ] } @@ -1682,7 +1683,7 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v31 + "selections": v32 }, { "kind": "LinkedField", @@ -1859,7 +1860,7 @@ return { "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v34, + "args": v35, "concreteType": "CommitCommentConnection", "plural": false, "selections": [ @@ -1894,7 +1895,7 @@ return { }, v42, v12, - v26, + v27, v40, v41 ] @@ -1918,7 +1919,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": v38 }, { "kind": "LinkedField", @@ -1928,9 +1929,9 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": v38 }, - v26 + v27 ] }, { @@ -1946,11 +1947,11 @@ return { "args": null, "storageKey": null }, - v26 + v27 ] }, - v27, - v30 + v28, + v31 ] } ] @@ -1966,7 +1967,7 @@ return { "key": "prTimelineContainer_timeline", "filters": null }, - v32 + v33 ] } ] diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index ac451dad1e..da5b973fc9 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 3a8852bc38dab1b82916974271e7eec4 + * @relayHash 7c4ab71fc777de210cae63ab5e4481cc */ /* eslint-disable */ @@ -127,6 +127,7 @@ fragment prDetailView_pullRequest_1Etigl on PullRequest { author { __typename avatarUrl + login ... on Node { id } @@ -702,7 +703,13 @@ v21 = { "args": null, "storageKey": null }, -v22 = { +v22 = [ + v5, + v21, + v8, + v6 +], +v23 = { "kind": "LinkedField", "alias": null, "name": "author", @@ -710,48 +717,44 @@ v22 = { "args": null, "concreteType": null, "plural": false, - "selections": [ - v5, - v21, - v6 - ] + "selections": v22 }, -v23 = { +v24 = { "kind": "ScalarField", "alias": null, "name": "path", "args": null, "storageKey": null }, -v24 = { +v25 = { "kind": "ScalarField", "alias": null, "name": "number", "args": null, "storageKey": null }, -v25 = { +v26 = { "kind": "ScalarField", "alias": null, "name": "position", "args": null, "storageKey": null }, -v26 = { +v27 = { "kind": "ScalarField", "alias": null, "name": "createdAt", "args": null, "storageKey": null }, -v27 = { +v28 = { "kind": "ScalarField", "alias": null, "name": "url", "args": null, "storageKey": null }, -v28 = [ +v29 = [ { "kind": "Variable", "name": "after", @@ -765,7 +768,7 @@ v28 = [ "type": "Int" } ], -v29 = { +v30 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -778,38 +781,38 @@ v29 = { v15 ] }, -v30 = { +v31 = { "kind": "ScalarField", "alias": null, "name": "cursor", "args": null, "storageKey": null }, -v31 = { +v32 = { "kind": "ScalarField", "alias": "sha", "name": "oid", "args": null, "storageKey": null }, -v32 = { +v33 = { "kind": "ScalarField", "alias": null, "name": "title", "args": null, "storageKey": null }, -v33 = { +v34 = { "kind": "ScalarField", "alias": null, "name": "bodyHTML", "args": null, "storageKey": null }, -v34 = [ - v27 -], v35 = [ + v28 +], +v36 = [ { "kind": "Variable", "name": "after", @@ -823,13 +826,13 @@ v35 = [ "type": "Int" } ], -v36 = [ +v37 = [ v5, v8, v21, v6 ], -v37 = { +v38 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -839,12 +842,6 @@ v37 = { "plural": false, "selections": v19 }, -v38 = [ - v5, - v21, - v8, - v6 -], v39 = { "kind": "LinkedField", "alias": null, @@ -853,7 +850,7 @@ v39 = { "args": null, "concreteType": null, "plural": false, - "selections": v38 + "selections": v22 }, v40 = { "kind": "LinkedField", @@ -873,7 +870,7 @@ return { "operationKind": "query", "name": "prDetailViewRefetchQuery", "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_1Etigl\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n body\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_1Etigl\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1047,7 +1044,20 @@ return { "storageKey": null }, v20, - v22, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v5, + v21, + v6 + ] + }, { "kind": "LinkedField", "alias": null, @@ -1086,9 +1096,9 @@ return { "storageKey": null }, v20, - v22, - v18, v23, + v18, + v24, { "kind": "LinkedField", "alias": "pullRequestId", @@ -1098,7 +1108,7 @@ return { "concreteType": "PullRequest", "plural": false, "selections": [ - v24, + v25, v6 ] }, @@ -1109,7 +1119,7 @@ return { "args": null, "storageKey": null }, - v25, + v26, { "kind": "ScalarField", "alias": null, @@ -1139,8 +1149,8 @@ return { v6 ] }, - v26, - v27 + v27, + v28 ] } ] @@ -1149,17 +1159,17 @@ return { } ] }, - v27, + v28, { "kind": "LinkedField", "alias": null, "name": "commits", "storageKey": null, - "args": v28, + "args": v29, "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ - v29, + v30, { "kind": "LinkedField", "alias": null, @@ -1169,7 +1179,7 @@ return { "concreteType": "PullRequestCommitEdge", "plural": true, "selections": [ - v30, + v31, { "kind": "LinkedField", "alias": null, @@ -1230,8 +1240,8 @@ return { "args": null, "storageKey": null }, - v31, - v27 + v32, + v28 ] }, v6, @@ -1246,7 +1256,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v28, + "args": v29, "handle": "connection", "key": "prCommitsView_commits", "filters": null @@ -1361,9 +1371,9 @@ return { } ] }, - v24, - v32, + v25, v33, + v34, { "kind": "ScalarField", "alias": null, @@ -1394,12 +1404,12 @@ return { { "kind": "InlineFragment", "type": "Bot", - "selections": v34 + "selections": v35 }, { "kind": "InlineFragment", "type": "User", - "selections": v34 + "selections": v35 } ] }, @@ -1431,11 +1441,11 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": v35, + "args": v36, "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v29, + v30, { "kind": "LinkedField", "alias": null, @@ -1445,7 +1455,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v30, + v31, { "kind": "LinkedField", "alias": null, @@ -1477,7 +1487,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v36 + "selections": v37 }, { "kind": "LinkedField", @@ -1515,9 +1525,9 @@ return { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v24, - v32, - v27, + v25, + v33, + v28, { "kind": "ScalarField", "alias": "prState", @@ -1531,9 +1541,9 @@ return { "kind": "InlineFragment", "type": "Issue", "selections": [ - v24, - v32, - v27, + v25, + v33, + v28, { "kind": "ScalarField", "alias": "issueState", @@ -1551,7 +1561,7 @@ return { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v37, + v38, { "kind": "LinkedField", "alias": null, @@ -1588,13 +1598,13 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v36 + "selections": v37 }, - v37, - v33, - v26, - v23, - v25 + v38, + v34, + v27, + v24, + v26 ] } ] @@ -1628,7 +1638,7 @@ return { "plural": false, "selections": v19 }, - v26 + v27 ] }, { @@ -1636,7 +1646,7 @@ return { "type": "MergedEvent", "selections": [ v39, - v37, + v38, { "kind": "ScalarField", "alias": null, @@ -1644,26 +1654,17 @@ return { "args": null, "storageKey": null }, - v26 + v27 ] }, { "kind": "InlineFragment", "type": "IssueComment", "selections": [ - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": v38 - }, - v33, - v26, - v27 + v23, + v34, + v27, + v28 ] }, { @@ -1705,7 +1706,7 @@ return { "args": null, "storageKey": null }, - v31, + v32, { "kind": "ScalarField", "alias": null, @@ -1739,7 +1740,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v35, + "args": v36, "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null diff --git a/lib/views/__generated__/prDetailView_pullRequest.graphql.js b/lib/views/__generated__/prDetailView_pullRequest.graphql.js index 28adeb4059..3d3b3a848f 100644 --- a/lib/views/__generated__/prDetailView_pullRequest.graphql.js +++ b/lib/views/__generated__/prDetailView_pullRequest.graphql.js @@ -57,7 +57,8 @@ export type prDetailView_pullRequest = {| +login: string |}, +author: ?{| - +avatarUrl: any + +avatarUrl: any, + +login: string, |}, +body: string, +path: string, @@ -207,33 +208,21 @@ v9 = { "storageKey": null }, v10 = { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v9 - ] -}, -v11 = { "kind": "ScalarField", "alias": null, "name": "number", "args": null, "storageKey": null }, -v12 = { +v11 = { "kind": "ScalarField", "alias": null, "name": "url", "args": null, "storageKey": null }, -v13 = [ - v12 +v12 = [ + v11 ]; return { "kind": "Fragment", @@ -351,7 +340,18 @@ return { "storageKey": null }, v8, - v10, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v9 + ] + }, { "kind": "LinkedField", "alias": null, @@ -390,7 +390,19 @@ return { "storageKey": null }, v8, - v10, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v9, + v7 + ] + }, v5, { "kind": "ScalarField", @@ -408,7 +420,7 @@ return { "concreteType": "PullRequest", "plural": false, "selections": [ - v11 + v10 ] }, { @@ -461,7 +473,7 @@ return { "args": null, "storageKey": null }, - v12 + v11 ] } ] @@ -504,7 +516,7 @@ return { "args": null }, v4, - v11, + v10, { "kind": "ScalarField", "alias": null, @@ -547,12 +559,12 @@ return { { "kind": "InlineFragment", "type": "Bot", - "selections": v13 + "selections": v12 }, { "kind": "InlineFragment", "type": "User", - "selections": v13 + "selections": v12 } ] }, @@ -574,7 +586,7 @@ return { } ] }, - v12, + v11, { "kind": "LinkedField", "alias": null, @@ -607,5 +619,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '6b79c21bb0d8e16f2d4c094d0fd055c8'; +(node/*: any*/).hash = '9feb173b93416270e2ac66924239d1b1'; module.exports = node; diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index aab51871f8..6d9108a544 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -11,7 +11,6 @@ import Timeago from './timeago'; export default class PullRequestCommentsView extends React.Component { render() { - if (this.props.reviews) { return this.props.reviews.nodes.map(review => { return review.comments.nodes.map(comment => { @@ -19,11 +18,16 @@ export default class PullRequestCommentsView extends React.Component { const filePatch = this.props.multiFilePatch.getFilePatchByPath(comment.path); const commentStartPoint = filePatch.getStartRange().start.translate(new Point(comment.position, 0)); const range = new Range(commentStartPoint, commentStartPoint); + const author = comment.author; return (
    diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index 80d3979fc1..1314a1029f 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -424,6 +424,7 @@ export default createRefetchContainer(BarePullRequestDetailView, { } author { avatarUrl + login } body path From 3259c9f519c9cd90dbed562a0eae63eb6a980041 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 21 Dec 2018 16:58:04 +0900 Subject: [PATCH 2397/4847] Only use UI font-size for the headers --- styles/file-patch-view.less | 2 +- styles/hunk-header-view.less | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/styles/file-patch-view.less b/styles/file-patch-view.less index 62ba2b660b..696bd143e8 100644 --- a/styles/file-patch-view.less +++ b/styles/file-patch-view.less @@ -42,6 +42,7 @@ border: 1px solid @base-border-color; border-radius: @component-border-radius; font-family: system-ui; + font-size: @font-size; background-color: @header-bg-color; cursor: default; @@ -248,7 +249,6 @@ // Readonly editor atom-text-editor[readonly] { - font-size: @font-size; // Use font-size form UI themes and not the editor config .cursors { display: none; } diff --git a/styles/hunk-header-view.less b/styles/hunk-header-view.less index 5d4bfa61de..ccdb4396ab 100644 --- a/styles/hunk-header-view.less +++ b/styles/hunk-header-view.less @@ -10,7 +10,7 @@ display: flex; align-items: stretch; - font-size: .9em; + font-size: @font-size; border: 1px solid @base-border-color; border-radius: @component-border-radius; background-color: @hunk-bg-color; From 2cd9b54afb370ae7a01b20337ecf4a0f7e5fa786 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 21 Dec 2018 17:00:40 +0900 Subject: [PATCH 2398/4847] :fire: Remove default font family Will inherit from the editor --- styles/hunk-header-view.less | 2 -- 1 file changed, 2 deletions(-) diff --git a/styles/hunk-header-view.less b/styles/hunk-header-view.less index ccdb4396ab..e31ea9b209 100644 --- a/styles/hunk-header-view.less +++ b/styles/hunk-header-view.less @@ -6,8 +6,6 @@ @hunk-bg-color-active: mix(@syntax-text-color, @syntax-background-color, 2%); .github-HunkHeaderView { - font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; - display: flex; align-items: stretch; font-size: @font-size; From 793cc3342f479420e347a97d357bc78d65afc975 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 21 Dec 2018 17:01:13 +0900 Subject: [PATCH 2399/4847] Use font family from UI themes --- styles/file-patch-view.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styles/file-patch-view.less b/styles/file-patch-view.less index 696bd143e8..a51fd5d820 100644 --- a/styles/file-patch-view.less +++ b/styles/file-patch-view.less @@ -41,7 +41,7 @@ padding-left: @component-padding; border: 1px solid @base-border-color; border-radius: @component-border-radius; - font-family: system-ui; + font-family: @font-family; font-size: @font-size; background-color: @header-bg-color; cursor: default; From 1a2ac47f0fea6f75abc6fc097694b09623071be7 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 21 Dec 2018 20:31:01 +0900 Subject: [PATCH 2400/4847] Style PrComment --- lib/views/pr-comments-view.js | 20 +++++++++++-------- styles/file-patch-view.less | 5 ----- styles/pr-comment.less | 36 +++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 styles/pr-comment.less diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index 6d9108a544..d5f87c6108 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -21,14 +21,18 @@ export default class PullRequestCommentsView extends React.Component { const author = comment.author; return ( - -
    -
    - - {author ? author.login : 'someone'} commented - {' '} -
    - {comment.body} + +
    +
    + + {author ? author.login : 'someone'} commented{' '} + + + +
    +
    + {comment.body} +
    diff --git a/styles/file-patch-view.less b/styles/file-patch-view.less index 208628f173..62ba2b660b 100644 --- a/styles/file-patch-view.less +++ b/styles/file-patch-view.less @@ -142,11 +142,6 @@ } } - &-commentAuthorAvatar { - height: 16px; - width: 16px; - } - &-metaDetails { padding: @component-padding; } diff --git a/styles/pr-comment.less b/styles/pr-comment.less new file mode 100644 index 0000000000..7cb0e62654 --- /dev/null +++ b/styles/pr-comment.less @@ -0,0 +1,36 @@ +@import 'variables'; + +@avatar-size: 16px; + +.github-PrComment { + font-family: @font-family; + font-size: @font-size; + + &-wrapper { + max-width: 60em; + padding-right: @component-padding*2; + padding-bottom: @component-padding; + } + + &-header { + padding: @component-padding 0 @component-padding/2 0; + color: @text-color-subtle; + } + + &-avatar { + margin-right: 4px; + height: @avatar-size; + width: @avatar-size; + border-radius: @component-border-radius; + } + + &-timeAgo { + color: inherit; + } + + &-body { + margin-left: @avatar-size + 4px; // avatar + margin + font-size: 1.15em; + } + +} From b7e443d21248b79d97f009f461de2c0e14c8f9f1 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 21 Dec 2018 13:24:51 +0100 Subject: [PATCH 2401/4847] comment as its own class --- lib/views/pr-comments-view.js | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index d5f87c6108..04a99e78b6 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -18,22 +18,10 @@ export default class PullRequestCommentsView extends React.Component { const filePatch = this.props.multiFilePatch.getFilePatchByPath(comment.path); const commentStartPoint = filePatch.getStartRange().start.translate(new Point(comment.position, 0)); const range = new Range(commentStartPoint, commentStartPoint); - const author = comment.author; return ( -
    -
    - - {author ? author.login : 'someone'} commented{' '} - - - -
    -
    - {comment.body} -
    -
    +
    ); @@ -44,3 +32,24 @@ export default class PullRequestCommentsView extends React.Component { } } } + +class PullRequestCommentView extends React.Component { + + render() { + const author = this.props.comment.author; + return ( +
    +
    + {author.login} + {author ? author.login : 'someone'} commented{' '} + + + +
    +
    + {this.props.comment.body} {this.props.comment.position} +
    +
    + ) + } +} From 33f16d2bc2a945562286a238fed15f0d3a8b239c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 21 Dec 2018 08:53:59 -0500 Subject: [PATCH 2402/4847] Return `null` from render() when there are no comments --- lib/views/pr-comments-view.js | 45 +++++++++++++++++------------------ 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index 04a99e78b6..ba3775fead 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -3,44 +3,43 @@ import PropTypes from 'prop-types'; import {Point, Range} from 'atom'; import Marker from '../atom/marker'; -import MarkerLayer from '../atom/marker-layer'; import Decoration from '../atom/decoration'; import Timeago from './timeago'; export default class PullRequestCommentsView extends React.Component { - render() { - if (this.props.reviews) { - return this.props.reviews.nodes.map(review => { - return review.comments.nodes.map(comment => { - if (comment.position !== null) { - const filePatch = this.props.multiFilePatch.getFilePatchByPath(comment.path); - const commentStartPoint = filePatch.getStartRange().start.translate(new Point(comment.position, 0)); - const range = new Range(commentStartPoint, commentStartPoint); - return ( - - - - - - ); - } - return null; - }); - }); + if (!this.props.reviews) { + return null; } + + return this.props.reviews.nodes.map(review => { + return review.comments.nodes.map(comment => { + if (comment.position !== null) { + const filePatch = this.props.multiFilePatch.getFilePatchByPath(comment.path); + const commentStartPoint = filePatch.getStartRange().start.translate(new Point(comment.position, 0)); + const range = new Range(commentStartPoint, commentStartPoint); + return ( + + + + + + ); + } + return null; + }); + }); } } class PullRequestCommentView extends React.Component { - render() { const author = this.props.comment.author; return ( - ) + ); } } From 4efcb0584b043b307cfe57a3c0d649e2c6e3775c Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 21 Dec 2018 15:26:42 +0100 Subject: [PATCH 2403/4847] get bodyHTML for comment also --- .../issueishDetailContainerQuery.graphql.js | 6 +- .../prDetailViewRefetchQuery.graphql.js | 100 +++++++++--------- .../prDetailView_pullRequest.graphql.js | 37 ++++--- lib/views/pr-detail-view.js | 1 + 4 files changed, 76 insertions(+), 68 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 1a24ef5d10..55b80a18d2 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 46254fc27ddba523ae7fba989c5e320a + * @relayHash 063056b23fdd8f4f06939894757d5382 */ /* eslint-disable */ @@ -217,6 +217,7 @@ fragment prDetailView_pullRequest_1Etigl on PullRequest { } } body + bodyHTML path commitSha: commit { oid @@ -1192,7 +1193,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_2LgaQ1\n id\n }\n}\n\nfragment issueishDetailController_repository_2LgaQ1 on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_1Etigl\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_2LgaQ1\n id\n }\n}\n\nfragment issueishDetailController_repository_2LgaQ1 on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_1Etigl\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1612,6 +1613,7 @@ return { v39, v26, v37, + v12, v40, { "kind": "LinkedField", diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index da5b973fc9..34aff4255d 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 7c4ab71fc777de210cae63ab5e4481cc + * @relayHash 83a0f29490df40e31d9f5aee5cdbae2f */ /* eslint-disable */ @@ -133,6 +133,7 @@ fragment prDetailView_pullRequest_1Etigl on PullRequest { } } body + bodyHTML path commitSha: commit { oid @@ -722,39 +723,46 @@ v23 = { v24 = { "kind": "ScalarField", "alias": null, - "name": "path", + "name": "bodyHTML", "args": null, "storageKey": null }, v25 = { "kind": "ScalarField", "alias": null, - "name": "number", + "name": "path", "args": null, "storageKey": null }, v26 = { "kind": "ScalarField", "alias": null, - "name": "position", + "name": "number", "args": null, "storageKey": null }, v27 = { "kind": "ScalarField", "alias": null, - "name": "createdAt", + "name": "position", "args": null, "storageKey": null }, v28 = { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null +}, +v29 = { "kind": "ScalarField", "alias": null, "name": "url", "args": null, "storageKey": null }, -v29 = [ +v30 = [ { "kind": "Variable", "name": "after", @@ -768,7 +776,7 @@ v29 = [ "type": "Int" } ], -v30 = { +v31 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -781,36 +789,29 @@ v30 = { v15 ] }, -v31 = { +v32 = { "kind": "ScalarField", "alias": null, "name": "cursor", "args": null, "storageKey": null }, -v32 = { +v33 = { "kind": "ScalarField", "alias": "sha", "name": "oid", "args": null, "storageKey": null }, -v33 = { - "kind": "ScalarField", - "alias": null, - "name": "title", - "args": null, - "storageKey": null -}, v34 = { "kind": "ScalarField", "alias": null, - "name": "bodyHTML", + "name": "title", "args": null, "storageKey": null }, v35 = [ - v28 + v29 ], v36 = [ { @@ -870,7 +871,7 @@ return { "operationKind": "query", "name": "prDetailViewRefetchQuery", "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_1Etigl\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_1Etigl\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1099,6 +1100,7 @@ return { v23, v18, v24, + v25, { "kind": "LinkedField", "alias": "pullRequestId", @@ -1108,7 +1110,7 @@ return { "concreteType": "PullRequest", "plural": false, "selections": [ - v25, + v26, v6 ] }, @@ -1119,7 +1121,7 @@ return { "args": null, "storageKey": null }, - v26, + v27, { "kind": "ScalarField", "alias": null, @@ -1149,8 +1151,8 @@ return { v6 ] }, - v27, - v28 + v28, + v29 ] } ] @@ -1159,17 +1161,17 @@ return { } ] }, - v28, + v29, { "kind": "LinkedField", "alias": null, "name": "commits", "storageKey": null, - "args": v29, + "args": v30, "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ - v30, + v31, { "kind": "LinkedField", "alias": null, @@ -1179,7 +1181,7 @@ return { "concreteType": "PullRequestCommitEdge", "plural": true, "selections": [ - v31, + v32, { "kind": "LinkedField", "alias": null, @@ -1240,8 +1242,8 @@ return { "args": null, "storageKey": null }, - v32, - v28 + v33, + v29 ] }, v6, @@ -1256,7 +1258,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v29, + "args": v30, "handle": "connection", "key": "prCommitsView_commits", "filters": null @@ -1371,9 +1373,9 @@ return { } ] }, - v25, - v33, + v26, v34, + v24, { "kind": "ScalarField", "alias": null, @@ -1445,7 +1447,7 @@ return { "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v30, + v31, { "kind": "LinkedField", "alias": null, @@ -1455,7 +1457,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v31, + v32, { "kind": "LinkedField", "alias": null, @@ -1525,9 +1527,9 @@ return { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v25, - v33, - v28, + v26, + v34, + v29, { "kind": "ScalarField", "alias": "prState", @@ -1541,9 +1543,9 @@ return { "kind": "InlineFragment", "type": "Issue", "selections": [ - v25, - v33, - v28, + v26, + v34, + v29, { "kind": "ScalarField", "alias": "issueState", @@ -1601,10 +1603,10 @@ return { "selections": v37 }, v38, - v34, - v27, v24, - v26 + v28, + v25, + v27 ] } ] @@ -1638,7 +1640,7 @@ return { "plural": false, "selections": v19 }, - v27 + v28 ] }, { @@ -1654,7 +1656,7 @@ return { "args": null, "storageKey": null }, - v27 + v28 ] }, { @@ -1662,9 +1664,9 @@ return { "type": "IssueComment", "selections": [ v23, - v34, - v27, - v28 + v24, + v28, + v29 ] }, { @@ -1706,7 +1708,7 @@ return { "args": null, "storageKey": null }, - v32, + v33, { "kind": "ScalarField", "alias": null, diff --git a/lib/views/__generated__/prDetailView_pullRequest.graphql.js b/lib/views/__generated__/prDetailView_pullRequest.graphql.js index 3d3b3a848f..e98a5c4a5f 100644 --- a/lib/views/__generated__/prDetailView_pullRequest.graphql.js +++ b/lib/views/__generated__/prDetailView_pullRequest.graphql.js @@ -61,6 +61,7 @@ export type prDetailView_pullRequest = {| +login: string, |}, +body: string, + +bodyHTML: any, +path: string, +commitSha: {| +oid: any @@ -210,19 +211,26 @@ v9 = { v10 = { "kind": "ScalarField", "alias": null, - "name": "number", + "name": "bodyHTML", "args": null, "storageKey": null }, v11 = { + "kind": "ScalarField", + "alias": null, + "name": "number", + "args": null, + "storageKey": null +}, +v12 = { "kind": "ScalarField", "alias": null, "name": "url", "args": null, "storageKey": null }, -v12 = [ - v11 +v13 = [ + v12 ]; return { "kind": "Fragment", @@ -404,6 +412,7 @@ return { ] }, v5, + v10, { "kind": "ScalarField", "alias": null, @@ -420,7 +429,7 @@ return { "concreteType": "PullRequest", "plural": false, "selections": [ - v10 + v11 ] }, { @@ -473,7 +482,7 @@ return { "args": null, "storageKey": null }, - v11 + v12 ] } ] @@ -516,7 +525,7 @@ return { "args": null }, v4, - v10, + v11, { "kind": "ScalarField", "alias": null, @@ -524,13 +533,7 @@ return { "args": null, "storageKey": null }, - { - "kind": "ScalarField", - "alias": null, - "name": "bodyHTML", - "args": null, - "storageKey": null - }, + v10, { "kind": "ScalarField", "alias": null, @@ -559,12 +562,12 @@ return { { "kind": "InlineFragment", "type": "Bot", - "selections": v12 + "selections": v13 }, { "kind": "InlineFragment", "type": "User", - "selections": v12 + "selections": v13 } ] }, @@ -586,7 +589,7 @@ return { } ] }, - v11, + v12, { "kind": "LinkedField", "alias": null, @@ -619,5 +622,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '9feb173b93416270e2ac66924239d1b1'; +(node/*: any*/).hash = 'ab20ccdc3ccc10843176a48cd07d03ae'; module.exports = node; diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index 1314a1029f..f57a26ffc9 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -427,6 +427,7 @@ export default createRefetchContainer(BarePullRequestDetailView, { login } body + bodyHTML path commitSha: commit { oid From 6093aa4ef4a0f8f5f22de1332073c05f16a645d3 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 21 Dec 2018 15:32:30 +0100 Subject: [PATCH 2404/4847] use github markdown component to show the comments --- lib/views/pr-comments-view.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index ba3775fead..e0f21a094b 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -4,9 +4,10 @@ import {Point, Range} from 'atom'; import Marker from '../atom/marker'; import Decoration from '../atom/decoration'; - +import GithubDotcomMarkdown from './github-dotcom-markdown'; import Timeago from './timeago'; + export default class PullRequestCommentsView extends React.Component { render() { if (!this.props.reviews) { @@ -46,7 +47,7 @@ class PullRequestCommentView extends React.Component {
    - {this.props.comment.body} {this.props.comment.position} +
    ); From 7f4661437c4a8d630ae0110dfb65f02739548544 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 21 Dec 2018 15:32:52 +0100 Subject: [PATCH 2405/4847] drill switchToIssueish prop --- lib/views/multi-file-patch-view.js | 2 +- lib/views/pr-detail-view.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 2eaa0b89e8..7768d9d5e1 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -281,7 +281,7 @@ export default class MultiFilePatchView extends React.Component { /> )} - + {this.props.multiFilePatch.getFilePatches().map(this.renderFilePatchDecorations)} {this.renderLineDecorations( diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index f57a26ffc9..44560797bf 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -210,6 +210,7 @@ export class BarePullRequestDetailView extends React.Component { shouldRefetch={this.state.refreshing} reviews={this.props.pullRequest.reviews} + switchToIssueish={this.props.switchToIssueish} /> From 6c3a335d8bf86150d1789a625aaa83e775e129ee Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 21 Dec 2018 15:39:40 +0100 Subject: [PATCH 2406/4847] pass switchToIssueish through properly --- lib/controllers/multi-file-patch-controller.js | 1 + lib/views/pr-comments-view.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/controllers/multi-file-patch-controller.js b/lib/controllers/multi-file-patch-controller.js index cdba88def6..0214aa2db9 100644 --- a/lib/controllers/multi-file-patch-controller.js +++ b/lib/controllers/multi-file-patch-controller.js @@ -83,6 +83,7 @@ export default class MultiFilePatchController extends React.Component { discardRows={this.discardRows} selectNextHunk={this.selectNextHunk} selectPreviousHunk={this.selectPreviousHunk} + switchToIssueish={this.props.switchToIssueish} /> ); } diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index e0f21a094b..64750796b1 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -23,7 +23,7 @@ export default class PullRequestCommentsView extends React.Component { return ( - + ); From 43e679d01c38e6eec9e46c285806db78b09be214 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 21 Dec 2018 10:15:51 -0500 Subject: [PATCH 2407/4847] Start a (failing) test for comment positioning --- test/builder/pr.js | 130 ++++++++++++++++++++++++++++ test/views/pr-comments-view.test.js | 33 +++++++ 2 files changed, 163 insertions(+) create mode 100644 test/builder/pr.js create mode 100644 test/views/pr-comments-view.test.js diff --git a/test/builder/pr.js b/test/builder/pr.js new file mode 100644 index 0000000000..24758ece0b --- /dev/null +++ b/test/builder/pr.js @@ -0,0 +1,130 @@ +class CommentBuilder { + constructor() { + this._id = 0; + this._path = 'first.txt'; + this._position = 0; + this._authorLogin = 'someone'; + this._authorAvatarUrl = 'https://avatars3.githubusercontent.com/u/17565?s=32&v=4'; + this._url = 'https://github.com/atom/github/pull/1829/files#r242224689'; + this._createdAt = 0; + this._body = 'Lorem ipsum dolor sit amet, te urbanitas appellantur est.'; + } + + id(i) { + this._id = i; + return this; + } + + path(p) { + this._path = p; + return this; + } + + position(pos) { + this._position = pos; + return this; + } + + authorLogin(login) { + this._authorLogin = login; + return this; + } + + authorAvatarUrl(url) { + this._authorAvatarUrl = url; + return this; + } + + url(u) { + this._url = u; + return this; + } + + createdAt(ts) { + this._createdAt = ts; + return this; + } + + body(text) { + this._body = text; + return this; + } + + build() { + return { + id: this._id, + author: { + login: this._authorLogin, + avatarUrl: this._authorAvatarUrl, + }, + body: this._body, + path: this._path, + position: this._position, + createdAt: this._createdAt, + url: this._url, + }; + } +} + +class ReviewBuilder { + constructor() { + this.nextCommentID = 0; + this._id = 0; + this._comments = []; + } + + id(i) { + this._id = i; + return this; + } + + addComment(block = () => {}) { + const builder = new CommentBuilder(); + builder.id(this.nextCommentID); + this.nextCommentID++; + + block(builder); + this._comments.push(builder.build()); + + return this; + } + + build() { + return { + id: this._id, + comments: {nodes: this._comments}, + }; + } +} + +class PullRequestBuilder { + constructor() { + this.nextCommentID = 0; + this.nextReviewID = 0; + this._reviews = []; + } + + addReview(block = () => {}) { + const builder = new ReviewBuilder(); + builder.id(this.nextReviewID); + this.nextReviewID++; + + block(builder); + this._reviews.push(builder.build()); + return this; + } + + build() { + return { + reviews: {nodes: this._reviews}, + }; + } +} + +export function reviewBuilder() { + return new ReviewBuilder(); +} + +export function pullRequestBuilder() { + return new PullRequestBuilder(); +} diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js new file mode 100644 index 0000000000..36ab79dc61 --- /dev/null +++ b/test/views/pr-comments-view.test.js @@ -0,0 +1,33 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {multiFilePatchBuilder} from '../builder/patch'; +import {pullRequestBuilder} from '../builder/pr'; +import PrCommentsView from '../../lib/views/pr-comments-view'; + +describe('PrCommentsView', function() { + it('adjusts the position for comments after hunk headers', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('file.txt')); + fp.addHunk(h => h.oldRow(5).unchanged('1').added('2', '3', '4').unchanged('5')); + fp.addHunk(h => h.oldRow(20).unchanged('7').deleted('8', '9', '10').unchanged('11')); + fp.addHunk(h => h.oldRow(30).unchanged('13').added('14', '15').deleted('16').unchanged('17')); + }) + .build(); + + const pr = pullRequestBuilder() + .addReview(r => { + r.addComment(c => c.id(0).path('file.txt').position(2).body('one')); + r.addComment(c => c.id(1).path('file.txt').position(9).body('two')); + r.addComment(c => c.id(2).path('file.txt').position(15).body('three')); + }) + .build(); + + const wrapper = shallow(); + + assert.deepEqual(wrapper.find('Marker').at(0).prop('bufferRange').serialize(), [[1, 0], [1, 0]]); + assert.deepEqual(wrapper.find('Marker').at(1).prop('bufferRange').serialize(), [[7, 0], [7, 0]]); + assert.deepEqual(wrapper.find('Marker').at(2).prop('bufferRange').serialize(), [[12, 0], [12, 0]]); + }); +}); From 2ca9fa63d4c1dea775b12eca990c3cd1459d9ec0 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 21 Dec 2018 16:34:37 +0100 Subject: [PATCH 2408/4847] font is a bit large --- styles/pr-comment.less | 1 - 1 file changed, 1 deletion(-) diff --git a/styles/pr-comment.less b/styles/pr-comment.less index 7cb0e62654..427dd1a0b3 100644 --- a/styles/pr-comment.less +++ b/styles/pr-comment.less @@ -30,7 +30,6 @@ &-body { margin-left: @avatar-size + 4px; // avatar + margin - font-size: 1.15em; } } From ea4b7518a94597145df5b58156f061e27a8e63ed Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 21 Dec 2018 13:36:40 -0500 Subject: [PATCH 2409/4847] Don't re-invent the binary... tree... wheel? --- package-lock.json | 7 ++++++- package.json | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 712f5bcef8..b3a9b8401f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1623,6 +1623,11 @@ "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==", "dev": true }, + "bintrees": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", + "integrity": "sha1-SfiW1uhYpKSZ34XDj7OZua/4QPg=" + }, "bl": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", @@ -5132,7 +5137,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { diff --git a/package.json b/package.json index 6ab320fd1c..29c0508186 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", "babel-plugin-transform-object-rest-spread": "6.26.0", "babel-preset-react": "6.24.1", + "bintrees": "1.0.2", "bytes": "^3.0.0", "classnames": "2.2.6", "compare-sets": "1.0.1", From 3b89168b4c666702e6383943a545319a9503d326 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 21 Dec 2018 13:37:06 -0500 Subject: [PATCH 2410/4847] Compute buffer rows for diff positions, given as filename + diff row --- lib/models/patch/multi-file-patch.js | 31 ++++++-- test/models/patch/multi-file-patch.test.js | 82 ++++++++++++++++++++++ 2 files changed, 108 insertions(+), 5 deletions(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 7336ca1381..132573214d 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -1,4 +1,5 @@ import {TextBuffer, Range} from 'atom'; +import {RBTree} from 'bintrees'; export default class MultiFilePatch { constructor({buffer, layers, filePatches}) { @@ -16,10 +17,27 @@ export default class MultiFilePatch { this.filePatchesByMarker = new Map(); this.hunksByMarker = new Map(); + // Store a map of {diffRow, offset} for each FilePatch where offset is the number of Hunk headers within the current + // FilePatch that occur before this row in the original diff output. + this.diffRowOffsetIndices = new Map(); + for (const filePatch of this.filePatches) { this.filePatchesByMarker.set(filePatch.getMarker(), filePatch); - for (const hunk of filePatch.getHunks()) { + + let diffRow = 1; + const index = new RBTree((a, b) => a.diffRow - b.diffRow); + this.diffRowOffsetIndices.set(filePatch.getPath(), {startBufferRow: filePatch.getStartRange().start.row, index}); + + for (let hunkIndex = 0; hunkIndex < filePatch.getHunks().length; hunkIndex++) { + const hunk = filePatch.getHunks()[hunkIndex]; this.hunksByMarker.set(hunk.getMarker(), hunk); + + // Advance past the hunk body + diffRow += hunk.bufferRowCount(); + index.insert({diffRow, offset: hunkIndex + 1}); + + // Advance past the next hunk header + diffRow++; } } } @@ -71,10 +89,6 @@ export default class MultiFilePatch { return this.filePatches; } - getFilePatchByPath(path) { - return this.filePatches.find(filePatch => filePatch.getPath() === path); - } - getPathSet() { return this.getFilePatches().reduce((pathSet, filePatch) => { for (const file of [filePatch.getOldFile(), filePatch.getNewFile()]) { @@ -325,6 +339,13 @@ export default class MultiFilePatch { return false; } + getBufferRowForDiffPosition(fileName, diffRow) { + // TODO verify that this works on Windows + const {startBufferRow, index} = this.diffRowOffsetIndices.get(fileName); + const {offset} = index.lowerBound({diffRow}).data(); + return startBufferRow + diffRow - offset; + } + /* * Construct an apply-able patch String. */ diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index 123812b2c2..767b17e233 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -275,25 +275,31 @@ describe('MultiFilePatch', function() { it('adopts a buffer from a previous patch', function() { const {multiFilePatch: lastMultiPatch, buffer: lastBuffer, layers: lastLayers} = multiFilePatchBuilder() .addFilePatch(fp => { + fp.setOldFile(f => f.path('A0.txt')); fp.addHunk(h => h.unchanged('a0').added('a1').deleted('a2').unchanged('a3')); }) .addFilePatch(fp => { + fp.setOldFile(f => f.path('A1.txt')); fp.addHunk(h => h.unchanged('a4').deleted('a5').unchanged('a6')); fp.addHunk(h => h.unchanged('a7').added('a8').unchanged('a9')); }) .addFilePatch(fp => { + fp.setOldFile(f => f.path('A2.txt')); fp.addHunk(h => h.oldRow(99).deleted('7').noNewline()); }) .build(); const {multiFilePatch: nextMultiPatch, buffer: nextBuffer, layers: nextLayers} = multiFilePatchBuilder() .addFilePatch(fp => { + fp.setOldFile(f => f.path('B0.txt')); fp.addHunk(h => h.unchanged('b0', 'b1').added('b2').unchanged('b3', 'b4')); }) .addFilePatch(fp => { + fp.setOldFile(f => f.path('B1.txt')); fp.addHunk(h => h.unchanged('b5', 'b6').added('b7')); }) .addFilePatch(fp => { + fp.setOldFile(f => f.path('B2.txt')); fp.addHunk(h => h.unchanged('b8', 'b9').deleted('b10').unchanged('b11')); fp.addHunk(h => h.oldRow(99).deleted('b12').noNewline()); }) @@ -352,6 +358,9 @@ describe('MultiFilePatch', function() { assertMarkedLayerRanges(lastLayers.noNewline, [ [[13, 0], [13, 26]], ]); + + assert.strictEqual(nextMultiPatch.getBufferRowForDiffPosition('B0.txt', 1), 0); + assert.strictEqual(nextMultiPatch.getBufferRowForDiffPosition('B2.txt', 5), 12); }); describe('derived patch generation', function() { @@ -694,4 +703,77 @@ describe('MultiFilePatch', function() { assert.isTrue(multiFilePatch.spansMultipleFiles([6, 10])); }); }); + + describe('diff position translation', function() { + it('offsets rows in the first hunk by the first hunk header', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('file.txt')); + fp.addHunk(h => { + h.unchanged('1 (0)').added('2 (1)', '3 (2)').deleted('4 (3)', '5 (4)', '6 (5)').unchanged('7 (6)'); + }); + }) + .build(); + + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('file.txt', 1), 0); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('file.txt', 7), 6); + }); + + it('offsets rows by the number of hunks before the diff row', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('file.txt')); + fp.addHunk(h => h.unchanged('0 (1)').added('1 (2)', '2 (3)').deleted('3 (4)').unchanged('4 (5)')); + fp.addHunk(h => h.unchanged('5 (7)').added('6 (8)', '7 (9)', '8 (10)').unchanged('9 (11)')); + fp.addHunk(h => h.unchanged('10 (13)').deleted('11 (14)').unchanged('12 (15)')); + }) + .build(); + + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('file.txt', 7), 5); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('file.txt', 11), 9); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('file.txt', 13), 10); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('file.txt', 15), 12); + }); + + it('resets the offset at the start of each file patch', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('0.txt')); + fp.addHunk(h => h.unchanged('0 (1)').added('1 (2)', '2 (3)').unchanged('3 (4)')); // Offset +1 + fp.addHunk(h => h.unchanged('4 (6)').deleted('5 (7)', '6 (8)', '7 (9)').unchanged('8 (10)')); // Offset +2 + fp.addHunk(h => h.unchanged('9 (12)').deleted('10 (13)').unchanged('11 (14)')); // Offset +3 + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('1.txt')); + fp.addHunk(h => h.unchanged('12 (1)').added('13 (2)').unchanged('14 (3)')); // Offset +1 + fp.addHunk(h => h.unchanged('15 (5)').deleted('16 (6)', '17 (7)', '18 (8)').unchanged('19 (9)')); // Offset +2 + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('2.txt')); + fp.addHunk(h => h.unchanged('20 (1)').added('21 (2)', '22 (3)', '23 (4)', '24 (5)').unchanged('25 (6)')); // Offset +1 + fp.addHunk(h => h.unchanged('26 (8)').deleted('27 (9)', '28 (10)').unchanged('29 (11)')); // Offset +2 + fp.addHunk(h => h.unchanged('30 (13)').added('31 (14)').unchanged('32 (15)')); // Offset +3 + }) + .build(); + + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('0.txt', 1), 0); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('0.txt', 4), 3); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('0.txt', 6), 4); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('0.txt', 10), 8); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('0.txt', 12), 9); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('0.txt', 14), 11); + + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('1.txt', 1), 12); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('1.txt', 3), 14); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('1.txt', 5), 15); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('1.txt', 9), 19); + + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('2.txt', 1), 20); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('2.txt', 6), 25); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('2.txt', 8), 26); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('2.txt', 11), 29); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('2.txt', 13), 30); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('2.txt', 15), 32); + }); + }); }); From ffbf81a887cb56430c6cb74c1d4da4ca5b3a2730 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 21 Dec 2018 13:50:53 -0500 Subject: [PATCH 2411/4847] Use `getBufferRowForDiffPosition` to position review comments --- lib/views/pr-comments-view.js | 29 ++++++++++++++++------------- test/views/pr-comments-view.test.js | 25 ++++++++++++++++--------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index 64750796b1..715376c371 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -2,12 +2,12 @@ import React from 'react'; import PropTypes from 'prop-types'; import {Point, Range} from 'atom'; +import {toNativePathSep} from '../helpers'; import Marker from '../atom/marker'; import Decoration from '../atom/decoration'; import GithubDotcomMarkdown from './github-dotcom-markdown'; import Timeago from './timeago'; - export default class PullRequestCommentsView extends React.Component { render() { if (!this.props.reviews) { @@ -16,19 +16,22 @@ export default class PullRequestCommentsView extends React.Component { return this.props.reviews.nodes.map(review => { return review.comments.nodes.map(comment => { - if (comment.position !== null) { - const filePatch = this.props.multiFilePatch.getFilePatchByPath(comment.path); - const commentStartPoint = filePatch.getStartRange().start.translate(new Point(comment.position, 0)); - const range = new Range(commentStartPoint, commentStartPoint); - return ( - - - - - - ); + if (!comment.position) { + return null; } - return null; + + const nativePath = toNativePathSep(comment.path); + const row = this.props.multiFilePatch.getBufferRowForDiffPosition(nativePath, comment.position); + const point = new Point(row, 0); + const range = new Range(point, point); + + return ( + + + + + + ); }); }); } diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index 36ab79dc61..13089158f3 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -9,25 +9,32 @@ describe('PrCommentsView', function() { it('adjusts the position for comments after hunk headers', function() { const {multiFilePatch} = multiFilePatchBuilder() .addFilePatch(fp => { - fp.setOldFile(f => f.path('file.txt')); - fp.addHunk(h => h.oldRow(5).unchanged('1').added('2', '3', '4').unchanged('5')); - fp.addHunk(h => h.oldRow(20).unchanged('7').deleted('8', '9', '10').unchanged('11')); - fp.addHunk(h => h.oldRow(30).unchanged('13').added('14', '15').deleted('16').unchanged('17')); + fp.setOldFile(f => f.path('file0.txt')); + fp.addHunk(h => h.oldRow(5).unchanged('0 (1)').added('1 (2)', '2 (3)', '3 (4)').unchanged('4 (5)')); + fp.addHunk(h => h.oldRow(20).unchanged('5 (7)').deleted('6 (8)', '7 (9)', '8 (10)').unchanged('9 (11)')); + fp.addHunk(h => { + h.oldRow(30).unchanged('10 (13)').added('11 (14)', '12 (15)').deleted('13 (16)').unchanged('14 (17)'); + }); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('file1.txt')); + fp.addHunk(h => h.oldRow(5).unchanged('15 (1)').added('16 (2)').unchanged('17 (3)')); + fp.addHunk(h => h.oldRow(20).unchanged('18 (5)').deleted('19 (6)', '20 (7)', '21 (8)').unchanged('22 (9)')); }) .build(); const pr = pullRequestBuilder() .addReview(r => { - r.addComment(c => c.id(0).path('file.txt').position(2).body('one')); - r.addComment(c => c.id(1).path('file.txt').position(9).body('two')); - r.addComment(c => c.id(2).path('file.txt').position(15).body('three')); + r.addComment(c => c.id(0).path('file0.txt').position(2).body('one')); + r.addComment(c => c.id(1).path('file0.txt').position(15).body('three')); + r.addComment(c => c.id(1).path('file1.txt').position(7).body('three')); }) .build(); const wrapper = shallow(); assert.deepEqual(wrapper.find('Marker').at(0).prop('bufferRange').serialize(), [[1, 0], [1, 0]]); - assert.deepEqual(wrapper.find('Marker').at(1).prop('bufferRange').serialize(), [[7, 0], [7, 0]]); - assert.deepEqual(wrapper.find('Marker').at(2).prop('bufferRange').serialize(), [[12, 0], [12, 0]]); + assert.deepEqual(wrapper.find('Marker').at(1).prop('bufferRange').serialize(), [[12, 0], [12, 0]]); + assert.deepEqual(wrapper.find('Marker').at(2).prop('bufferRange').serialize(), [[20, 0], [20, 0]]); }); }); From 8984cbcf71c4352f0b0de56b2023e7ba01cc33b1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 21 Dec 2018 13:56:29 -0500 Subject: [PATCH 2412/4847] Position the decoration after its marker, not before --- lib/views/pr-comments-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index 715376c371..34cd615bfd 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -27,7 +27,7 @@ export default class PullRequestCommentsView extends React.Component { return ( - + From a00dbab2c2260a2b7ead93d623fc5cc3a0927603 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 27 Dec 2018 10:47:10 -0800 Subject: [PATCH 2413/4847] fix `IssueishDetailContainer` tests Co-Authored-By: Katrina Uychaco --- test/containers/issueish-detail-container.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/containers/issueish-detail-container.test.js b/test/containers/issueish-detail-container.test.js index 10728075c7..934f24df9f 100644 --- a/test/containers/issueish-detail-container.test.js +++ b/test/containers/issueish-detail-container.test.js @@ -30,6 +30,8 @@ describe('IssueishDetailContainer', function() { timelineCursor: null, commitCount: 100, commitCursor: null, + commentCount: 100, + commentCursor: null, }, }, { repository: { From 3f6123bfa32b2ff44994f12a9cebe1556e13982b Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 27 Dec 2018 10:59:19 -0800 Subject: [PATCH 2414/4847] fix console prop type warnings Co-Authored-By: Katrina Uychaco --- test/fixtures/props/issueish-pane-props.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/fixtures/props/issueish-pane-props.js b/test/fixtures/props/issueish-pane-props.js index 0224a05577..cabc7e4140 100644 --- a/test/fixtures/props/issueish-pane-props.js +++ b/test/fixtures/props/issueish-pane-props.js @@ -27,6 +27,15 @@ export function issueishDetailContainerProps(overrides = {}) { switchToIssueish: () => {}, onTitleChange: () => {}, + workspace: {}, + commands: {}, + keymaps: {}, + tooltips: {}, + config: {}, + destroy: () => {}, + + itemType: IssueishDetailItem, + ...overrides, }; } From baf6e6d04d437602454eb7a876eb23db51ef19a1 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 27 Dec 2018 11:05:23 -0800 Subject: [PATCH 2415/4847] fix integration tests for checking out a pr --- test/integration/checkout-pr.test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/integration/checkout-pr.test.js b/test/integration/checkout-pr.test.js index 6a0c6aa407..2fcfcdcec7 100644 --- a/test/integration/checkout-pr.test.js +++ b/test/integration/checkout-pr.test.js @@ -8,7 +8,7 @@ import {createRepositoryResult} from '../fixtures/factories/repository-result'; import IDGenerator from '../fixtures/factories/id-generator'; import {createPullRequestsResult, createPullRequestDetailResult} from '../fixtures/factories/pull-request-result'; -describe('integration: check out a pull request', function() { +describe.only('integration: check out a pull request', function() { let context, wrapper, atomEnv, workspaceElement, git, idGen, repositoryID; beforeEach(async function() { @@ -140,6 +140,8 @@ describe('integration: check out a pull request', function() { timelineCursor: null, commitCount: 100, commitCursor: null, + commentCount: 100, + commentCursor: null, }, }, result); } From 8e95936f2add649f385a0df87322c9eebb40e612 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 27 Dec 2018 11:07:11 -0800 Subject: [PATCH 2416/4847] never did get that git hook to work for stupid .only calls --- test/integration/checkout-pr.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/checkout-pr.test.js b/test/integration/checkout-pr.test.js index 2fcfcdcec7..a15a1adced 100644 --- a/test/integration/checkout-pr.test.js +++ b/test/integration/checkout-pr.test.js @@ -8,7 +8,7 @@ import {createRepositoryResult} from '../fixtures/factories/repository-result'; import IDGenerator from '../fixtures/factories/id-generator'; import {createPullRequestsResult, createPullRequestDetailResult} from '../fixtures/factories/pull-request-result'; -describe.only('integration: check out a pull request', function() { +describe('integration: check out a pull request', function() { let context, wrapper, atomEnv, workspaceElement, git, idGen, repositoryID; beforeEach(async function() { From 8055ee33d996db40c073bcca569a100ca757abc8 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 27 Dec 2018 11:46:57 -0800 Subject: [PATCH 2417/4847] add test for comment with position: null --- test/views/pr-comments-view.test.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index 13089158f3..ca71a0d31c 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -37,4 +37,29 @@ describe('PrCommentsView', function() { assert.deepEqual(wrapper.find('Marker').at(1).prop('bufferRange').serialize(), [[12, 0], [12, 0]]); assert.deepEqual(wrapper.find('Marker').at(2).prop('bufferRange').serialize(), [[20, 0], [20, 0]]); }); + it('does not render comment if position is null', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('file0.txt')); + fp.addHunk(h => h.oldRow(5).unchanged('0 (1)').added('1 (2)', '2 (3)', '3 (4)').unchanged('4 (5)')); + fp.addHunk(h => h.oldRow(20).unchanged('5 (7)').deleted('6 (8)', '7 (9)', '8 (10)').unchanged('9 (11)')); + fp.addHunk(h => { + h.oldRow(30).unchanged('10 (13)').added('11 (14)', '12 (15)').deleted('13 (16)').unchanged('14 (17)'); + }); + }) + .build(); + + const pr = pullRequestBuilder() + .addReview(r => { + r.addComment(c => c.id(0).path('file0.txt').position(2).body('one')); + r.addComment(c => c.id(1).path('file0.txt').position(null).body('three')); + }) + .build(); + + const wrapper = shallow(); + + const comments = wrapper.find('PullRequestCommentView'); + assert.lengthOf(comments, 1); + assert.strictEqual(comments.at(0).prop('comment').body, 'one'); + }); }); From 12301c43d7765631428f362178126279b3b95743 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 27 Dec 2018 11:51:20 -0800 Subject: [PATCH 2418/4847] let's call it `PullRequestCommentView` just to be consistent --- test/views/pr-comments-view.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index ca71a0d31c..5617c02120 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -3,9 +3,9 @@ import {shallow} from 'enzyme'; import {multiFilePatchBuilder} from '../builder/patch'; import {pullRequestBuilder} from '../builder/pr'; -import PrCommentsView from '../../lib/views/pr-comments-view'; +import PullRequestCommentsView from '../../lib/views/pr-comments-view'; -describe('PrCommentsView', function() { +describe('PullRequestCommentsView', function() { it('adjusts the position for comments after hunk headers', function() { const {multiFilePatch} = multiFilePatchBuilder() .addFilePatch(fp => { @@ -31,7 +31,7 @@ describe('PrCommentsView', function() { }) .build(); - const wrapper = shallow(); + const wrapper = shallow(); assert.deepEqual(wrapper.find('Marker').at(0).prop('bufferRange').serialize(), [[1, 0], [1, 0]]); assert.deepEqual(wrapper.find('Marker').at(1).prop('bufferRange').serialize(), [[12, 0], [12, 0]]); @@ -56,7 +56,7 @@ describe('PrCommentsView', function() { }) .build(); - const wrapper = shallow(); + const wrapper = shallow(); const comments = wrapper.find('PullRequestCommentView'); assert.lengthOf(comments, 1); From 7dd8376dbfe9a3324a27826d497f2be4f4dce6ba Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 27 Dec 2018 11:03:18 -0800 Subject: [PATCH 2419/4847] WIP sort comments in correct order. Red herring. seems like they're coming back sorted, but rendering in the wrong order # 50-character subject line # # 72-character wrapped longer description. This should answer: # # * Why was this change necessary? # * How does it address the problem? # * Are there any side effects? # # Include a link to the ticket, if any. # # Don't forget the following emoji: # # * :art: `:art:` when improving the format/structure of the code # * :racehorse: `:racehorse:` when improving performance # * :non-potable_water: `:non-potable_water:` when plugging memory leaks # * :memo: `:memo:` when writing docs # * :penguin: `:penguin:` when fixing something on Linux # * :apple: `:apple:` when fixing something on Mac OS # * :checkered_flag: `:checkered_flag:` when fixing something on Windows # * :bug: `:bug:` when fixing a bug # * :fire: `:fire:` when removing code or files # * :green_heart: `:green_heart:` when fixing the CI build # * :white_check_mark: `:white_check_mark:` when adding tests # * :lock: `:lock:` when dealing with security # * :arrow_up: `:arrow_up:` when upgrading dependencies # * :arrow_down: `:arrow_down:` when downgrading dependencies # * :shirt: `:shirt:` when removing linter warnings --- lib/views/pr-comments-view.js | 48 ++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index 34cd615bfd..e91417339b 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -14,14 +14,31 @@ export default class PullRequestCommentsView extends React.Component { return null; } - return this.props.reviews.nodes.map(review => { - return review.comments.nodes.map(comment => { + const commentsByPosition = new Map(); + this.props.reviews.nodes.forEach(review => { + review.comments.nodes.forEach(comment => { + const nativePath = toNativePathSep(comment.path); + const row = this.props.multiFilePatch.getBufferRowForDiffPosition(nativePath, comment.position); + const commentsAtRow = commentsByPosition.get(row); + if (commentsAtRow) { + commentsAtRow.add(comment); + } else { + commentsByPosition.set(row, new Set([comment])); + } + }); + }); + + return [...commentsByPosition].map(([row, comments]) => { + const getUnixTime = epoch => new Date(epoch).getTime() / 1000; + console.log([...comments]); + const sortedComments = [...comments].sort((a, b) => getUnixTime(a.createdAt) - getUnixTime(b.createdAt)); + + console.log(sortedComments); + return sortedComments.map(comment => { if (!comment.position) { return null; } - const nativePath = toNativePathSep(comment.path); - const row = this.props.multiFilePatch.getBufferRowForDiffPosition(nativePath, comment.position); const point = new Point(row, 0); const range = new Range(point, point); @@ -34,6 +51,29 @@ export default class PullRequestCommentsView extends React.Component { ); }); }); + + // debugger; + // + // return this.props.reviews.nodes.map(review => { + // return review.comments.nodes.map(comment => { + // if (!comment.position) { + // return null; + // } + // + // const nativePath = toNativePathSep(comment.path); + // const row = this.props.multiFilePatch.getBufferRowForDiffPosition(nativePath, comment.position); + // const point = new Point(row, 0); + // const range = new Range(point, point); + // + // return ( + // + // + // + // + // + // ); + // }); + // }); } } From 7b7d6cdac4da27c1ada6878dc67f14d405011b7c Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 27 Dec 2018 13:46:59 -0800 Subject: [PATCH 2420/4847] Separate out comments by thread, and render them in correct order # 50-character subject line # # 72-character wrapped longer description. This should answer: # # * Why was this change necessary? # * How does it address the problem? # * Are there any side effects? # # Include a link to the ticket, if any. # # Don't forget the following emoji: # # * :art: `:art:` when improving the format/structure of the code # * :racehorse: `:racehorse:` when improving performance # * :non-potable_water: `:non-potable_water:` when plugging memory leaks # * :memo: `:memo:` when writing docs # * :penguin: `:penguin:` when fixing something on Linux # * :apple: `:apple:` when fixing something on Mac OS # * :checkered_flag: `:checkered_flag:` when fixing something on Windows # * :bug: `:bug:` when fixing a bug # * :fire: `:fire:` when removing code or files # * :green_heart: `:green_heart:` when fixing the CI build # * :white_check_mark: `:white_check_mark:` when adding tests # * :lock: `:lock:` when dealing with security # * :arrow_up: `:arrow_up:` when upgrading dependencies # * :arrow_down: `:arrow_down:` when downgrading dependencies # * :shirt: `:shirt:` when removing linter warnings --- lib/views/pr-comments-view.js | 77 ++++++++++++----------------------- 1 file changed, 27 insertions(+), 50 deletions(-) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index e91417339b..1bb8b479c7 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -14,66 +14,43 @@ export default class PullRequestCommentsView extends React.Component { return null; } - const commentsByPosition = new Map(); + const commentsByRootCommentId = new Map(); + this.props.reviews.nodes.forEach(review => { review.comments.nodes.forEach(comment => { - const nativePath = toNativePathSep(comment.path); - const row = this.props.multiFilePatch.getBufferRowForDiffPosition(nativePath, comment.position); - const commentsAtRow = commentsByPosition.get(row); - if (commentsAtRow) { - commentsAtRow.add(comment); + if (!comment.replyTo) { + commentsByRootCommentId.set(comment.id, [comment]); } else { - commentsByPosition.set(row, new Set([comment])); + commentsByRootCommentId.get(comment.replyTo.id).push(comment); } }); }); - return [...commentsByPosition].map(([row, comments]) => { - const getUnixTime = epoch => new Date(epoch).getTime() / 1000; - console.log([...comments]); - const sortedComments = [...comments].sort((a, b) => getUnixTime(a.createdAt) - getUnixTime(b.createdAt)); - - console.log(sortedComments); - return sortedComments.map(comment => { - if (!comment.position) { - return null; - } - const point = new Point(row, 0); - const range = new Range(point, point); + return [...commentsByRootCommentId].reverse().map(([rootCommentId, comments]) => { + const rootComment = comments[0]; + if (!rootComment.position) { + return null; + } - return ( - - - - - - ); - }); + const nativePath = toNativePathSep(rootComment.path); + const row = this.props.multiFilePatch.getBufferRowForDiffPosition(nativePath, rootComment.position); + const point = new Point(row, 0); + const range = new Range(point, point); + return ( + + + {comments.map(comment => + , + )} + + + ); }); - - // debugger; - // - // return this.props.reviews.nodes.map(review => { - // return review.comments.nodes.map(comment => { - // if (!comment.position) { - // return null; - // } - // - // const nativePath = toNativePathSep(comment.path); - // const row = this.props.multiFilePatch.getBufferRowForDiffPosition(nativePath, comment.position); - // const point = new Point(row, 0); - // const range = new Range(point, point); - // - // return ( - // - // - // - // - // - // ); - // }); - // }); } } From 97f22e628a952c440bebd80694779ae507a1d39a Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 27 Dec 2018 14:01:48 -0800 Subject: [PATCH 2421/4847] add tests for `PullRequestCommentView` --- lib/views/pr-comments-view.js | 7 ++-- test/views/pr-comments-view.test.js | 56 ++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index 1bb8b479c7..a1beeb9d72 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -54,14 +54,15 @@ export default class PullRequestCommentsView extends React.Component { } } -class PullRequestCommentView extends React.Component { +export class PullRequestCommentView extends React.Component { render() { const author = this.props.comment.author; + const login = author ? author.login : 'someone'; return (
    - {author.login} - {author ? author.login : 'someone'} commented{' '} + {login} + {login} commented{' '} diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index 5617c02120..ccb7b78673 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -3,7 +3,7 @@ import {shallow} from 'enzyme'; import {multiFilePatchBuilder} from '../builder/patch'; import {pullRequestBuilder} from '../builder/pr'; -import PullRequestCommentsView from '../../lib/views/pr-comments-view'; +import PullRequestCommentsView, {PullRequestCommentView} from '../../lib/views/pr-comments-view'; describe('PullRequestCommentsView', function() { it('adjusts the position for comments after hunk headers', function() { @@ -63,3 +63,57 @@ describe('PullRequestCommentsView', function() { assert.strictEqual(comments.at(0).prop('comment').body, 'one'); }); }); + +describe('PullRequestCommentView', function() { + const avatarUrl = 'https://avatars3.githubusercontent.com/u/3781742?s=40&v=4'; + const login = 'annthurium'; + const commentUrl = 'https://github.com/kuychaco/test-repo/pull/4#discussion_r244214873'; + const createdAt = '2018-12-27T17:51:17Z'; + const bodyHTML = '
    yo yo
    '; + const switchToIssueish = () => {}; + + function buildApp(overrideProps = {}, opts = {}) { + const props = { + comment: { + bodyHTML, + url: commentUrl, + createdAt, + author: { + avatarUrl, + login, + }, + ...overrideProps, + }, + switchToIssueish, + ...opts, + }; + + return ( + + ); + } + it('renders the PullRequestCommentReview information', function() { + const wrapper = shallow(buildApp()); + const avatar = wrapper.find('.github-PrComment-avatar'); + + assert.strictEqual(avatar.getElement('src').props.src, avatarUrl); + assert.strictEqual(avatar.getElement('alt').props.alt, login); + + assert.isTrue(wrapper.text().includes(`${login} commented`)); + + const a = wrapper.find('.github-PrComment-timeAgo'); + assert.strictEqual(a.getElement('href').props.href, commentUrl); + + const timeAgo = wrapper.find('Timeago'); + assert.strictEqual(timeAgo.prop('time'), createdAt); + + const githubDotcomMarkdown = wrapper.find('GithubDotcomMarkdown'); + assert.strictEqual(githubDotcomMarkdown.prop('html'), bodyHTML); + assert.strictEqual(githubDotcomMarkdown.prop('switchToIssueish'), switchToIssueish); + }); + + it('contains the text `someone commented` for null authors', function() { + const wrapper = shallow(buildApp({author: null})); + assert.isTrue(wrapper.text().includes('someone commented')); + }); +}); From ed7d0a5c5b42435ea51de16ff680551effe22dfb Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 27 Dec 2018 15:36:24 -0800 Subject: [PATCH 2422/4847] WIP create PrReviewsContainer to lay foundation for pagination Move query from PrDetailView to this container Co-Authored-By: Tilde Ann Thurium --- .../issueishDetailContainerQuery.graphql.js | 467 +++++++------- .../prReviewsContainerQuery.graphql.js | 503 +++++++++++++++ .../prReviewsContainer_pullRequest.graphql.js | 354 +++++++++++ lib/containers/issueish-detail-container.js | 6 + lib/containers/pr-reviews-container.js | 92 +++ .../prDetailViewRefetchQuery.graphql.js | 587 +++++++++--------- .../prDetailView_pullRequest.graphql.js | 447 +++---------- lib/views/multi-file-patch-view.js | 4 +- lib/views/pr-comments-view.js | 2 +- lib/views/pr-detail-view.js | 78 +-- 10 files changed, 1548 insertions(+), 992 deletions(-) create mode 100644 lib/containers/__generated__/prReviewsContainerQuery.graphql.js create mode 100644 lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js create mode 100644 lib/containers/pr-reviews-container.js diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 55b80a18d2..ea0f609242 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 063056b23fdd8f4f06939894757d5382 + * @relayHash 615fe759e1fcacb3ed5561310f21f8ed */ /* eslint-disable */ @@ -20,6 +20,8 @@ export type issueishDetailContainerQueryVariables = {| commitCursor?: ?string, commentCount: number, commentCursor?: ?string, + reviewCount?: ?number, + reviewCursor?: ?string, |}; export type issueishDetailContainerQueryResponse = {| +repository: ?{| @@ -44,12 +46,12 @@ query issueishDetailContainerQuery( $commitCursor: String ) { repository(owner: $repoOwner, name: $repoName) { - ...issueishDetailController_repository_2LgaQ1 + ...issueishDetailController_repository_y3nHF id } } -fragment issueishDetailController_repository_2LgaQ1 on Repository { +fragment issueishDetailController_repository_y3nHF on Repository { ...issueDetailView_repository ...prDetailView_repository name @@ -158,87 +160,7 @@ fragment prDetailView_pullRequest_1Etigl on PullRequest { } isCrossRepository changedFiles - comments { - totalCount - } - reviews(first: 100) { - pageInfo { - hasNextPage - endCursor - } - nodes { - id - body - commitId: commit { - oid - id - } - state - submittedAt - login: author { - __typename - login - ... on Node { - id - } - } - author { - __typename - avatarUrl - ... on Node { - id - } - } - comments(first: 100) { - pageInfo { - hasNextPage - endCursor - } - nodes { - id - pullRequestId: pullRequest { - number - id - } - databaseId - login: author { - __typename - login - ... on Node { - id - } - } - author { - __typename - avatarUrl - login - ... on Node { - id - } - } - body - bodyHTML - path - commitSha: commit { - oid - id - } - diffHunk - position - originalPosition - originalCommitId: originalCommit { - oid - id - } - replyTo { - id - } - createdAt - url - } - } - } - } + ...prReviewsContainer_pullRequest_3CUNoW ...prCommitsView_pullRequest_38TpXw countedCommits: commits { totalCount @@ -278,6 +200,69 @@ fragment prDetailView_pullRequest_1Etigl on PullRequest { } } +fragment prReviewsContainer_pullRequest_3CUNoW on PullRequest { + url + reviews { + pageInfo { + hasNextPage + endCursor + } + edges { + cursor + node { + id + body + commitId: commit { + oid + id + } + state + submittedAt + login: author { + __typename + login + ... on Node { + id + } + } + author { + __typename + avatarUrl + ... on Node { + id + } + } + comments(first: 100) { + pageInfo { + hasNextPage + endCursor + } + nodes { + id + author { + __typename + avatarUrl + login + ... on Node { + id + } + } + bodyHTML + path + position + replyTo { + id + } + createdAt + url + } + } + __typename + } + } + } +} + fragment prCommitsView_pullRequest_38TpXw on PullRequest { url commits(first: $commitCount, after: $commitCursor) { @@ -651,6 +636,18 @@ var v0 = [ "name": "commentCursor", "type": "String", "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCount", + "type": "Int", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCursor", + "type": "String", + "defaultValue": null } ], v1 = [ @@ -1106,15 +1103,7 @@ v34 = [ "type": "Int" } ], -v35 = [ - { - "kind": "Literal", - "name": "first", - "value": 100, - "type": "Int" - } -], -v36 = { +v35 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -1127,14 +1116,7 @@ v36 = { v18 ] }, -v37 = { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null -}, -v38 = [ +v36 = [ { "kind": "ScalarField", "alias": null, @@ -1144,31 +1126,29 @@ v38 = [ }, v2 ], -v39 = { - "kind": "LinkedField", - "alias": "login", - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": v6 -}, -v40 = { +v37 = [ + { + "kind": "Literal", + "name": "first", + "value": 100, + "type": "Int" + } +], +v38 = { "kind": "ScalarField", "alias": null, "name": "path", "args": null, "storageKey": null }, -v41 = { +v39 = { "kind": "ScalarField", "alias": null, "name": "position", "args": null, "storageKey": null }, -v42 = { +v40 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -1176,9 +1156,9 @@ v42 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v38 + "selections": v36 }, -v43 = { +v41 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -1193,7 +1173,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_2LgaQ1\n id\n }\n}\n\nfragment issueishDetailController_repository_2LgaQ1 on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_1Etigl\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_1Etigl\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_3CUNoW\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_3CUNoW on PullRequest {\n url\n reviews {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1245,6 +1225,18 @@ return { "variableName": "issueishNumber", "type": null }, + { + "kind": "Variable", + "name": "reviewCount", + "variableName": "reviewCount", + "type": null + }, + { + "kind": "Variable", + "name": "reviewCursor", + "variableName": "reviewCursor", + "type": null + }, { "kind": "Variable", "name": "timelineCount", @@ -1509,173 +1501,144 @@ return { "args": null, "storageKey": null }, + v14, { "kind": "LinkedField", "alias": null, - "name": "comments", + "name": "reviews", "storageKey": null, "args": null, - "concreteType": "IssueCommentConnection", - "plural": false, - "selections": v32 - }, - { - "kind": "LinkedField", - "alias": null, - "name": "reviews", - "storageKey": "reviews(first:100)", - "args": v35, "concreteType": "PullRequestReviewConnection", "plural": false, "selections": [ - v36, + v35, { "kind": "LinkedField", "alias": null, - "name": "nodes", + "name": "edges", "storageKey": null, "args": null, - "concreteType": "PullRequestReview", + "concreteType": "PullRequestReviewEdge", "plural": true, "selections": [ - v2, - v37, - { - "kind": "LinkedField", - "alias": "commitId", - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v38 - }, - v11, - { - "kind": "ScalarField", - "alias": null, - "name": "submittedAt", - "args": null, - "storageKey": null - }, - v39, + v21, { "kind": "LinkedField", "alias": null, - "name": "author", + "name": "node", "storageKey": null, "args": null, - "concreteType": null, + "concreteType": "PullRequestReview", "plural": false, "selections": [ - v4, - v13, - v2 - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "comments", - "storageKey": "comments(first:100)", - "args": v35, - "concreteType": "PullRequestReviewCommentConnection", - "plural": false, - "selections": [ - v36, + v2, + { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "commitId", + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v36 + }, + v11, + { + "kind": "ScalarField", + "alias": null, + "name": "submittedAt", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "login", + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": v6 + }, { "kind": "LinkedField", "alias": null, - "name": "nodes", + "name": "author", "storageKey": null, "args": null, - "concreteType": "PullRequestReviewComment", - "plural": true, + "concreteType": null, + "plural": false, "selections": [ - { - "kind": "LinkedField", - "alias": "commitSha", - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v38 - }, - v2, - { - "kind": "ScalarField", - "alias": null, - "name": "databaseId", - "args": null, - "storageKey": null - }, - v39, - v26, - v37, - v12, - v40, - { - "kind": "LinkedField", - "alias": "pullRequestId", - "name": "pullRequest", - "storageKey": null, - "args": null, - "concreteType": "PullRequest", - "plural": false, - "selections": [ - v10, - v2 - ] - }, - { - "kind": "ScalarField", - "alias": null, - "name": "diffHunk", - "args": null, - "storageKey": null - }, - v41, - { - "kind": "ScalarField", - "alias": null, - "name": "originalPosition", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": "originalCommitId", - "name": "originalCommit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v38 - }, + v4, + v13, + v2 + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": "comments(first:100)", + "args": v37, + "concreteType": "PullRequestReviewCommentConnection", + "plural": false, + "selections": [ + v35, { "kind": "LinkedField", "alias": null, - "name": "replyTo", + "name": "nodes", "storageKey": null, "args": null, "concreteType": "PullRequestReviewComment", - "plural": false, + "plural": true, "selections": [ - v2 + v2, + v26, + v12, + v38, + v39, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v2 + ] + }, + v27, + v14 ] - }, - v27, - v14 + } ] - } + }, + v4 ] } ] } ] }, - v14, + { + "kind": "LinkedHandle", + "alias": null, + "name": "reviews", + "args": null, + "handle": "connection", + "key": "prReviewsContainer_reviews", + "filters": null + }, v10, { "kind": "LinkedField", @@ -1856,13 +1819,13 @@ return { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v42, + v40, { "kind": "LinkedField", "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v35, + "args": v37, "concreteType": "CommitCommentConnection", "plural": false, "selections": [ @@ -1895,11 +1858,11 @@ return { "plural": false, "selections": v23 }, - v42, + v40, v12, v27, - v40, - v41 + v38, + v39 ] } ] @@ -1912,7 +1875,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v43, + v41, { "kind": "LinkedField", "alias": null, @@ -1921,7 +1884,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v38 + "selections": v36 }, { "kind": "LinkedField", @@ -1931,7 +1894,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v38 + "selections": v36 }, v27 ] @@ -1940,8 +1903,8 @@ return { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v43, - v42, + v41, + v40, { "kind": "ScalarField", "alias": null, @@ -1981,5 +1944,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'b749679230ad5e75455f1923ba78b425'; +(node/*: any*/).hash = 'e4903c4025a67651b3086652adb8aa06'; module.exports = node; diff --git a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js new file mode 100644 index 0000000000..8f1deb1224 --- /dev/null +++ b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js @@ -0,0 +1,503 @@ +/** + * @flow + * @relayHash dc9158ed713eb5e8c4c725dd4bfc9e00 + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest } from 'relay-runtime'; +type prReviewsContainer_pullRequest$ref = any; +export type prReviewsContainerQueryVariables = {| + reviewCount?: ?number, + reviewCursor?: ?string, + url: any, +|}; +export type prReviewsContainerQueryResponse = {| + +resource: ?{| + +$fragmentRefs: prReviewsContainer_pullRequest$ref + |} +|}; +export type prReviewsContainerQuery = {| + variables: prReviewsContainerQueryVariables, + response: prReviewsContainerQueryResponse, +|}; +*/ + + +/* +query prReviewsContainerQuery( + $reviewCount: Int + $reviewCursor: String + $url: URI! +) { + resource(url: $url) { + __typename + ... on PullRequest { + ...prReviewsContainer_pullRequest_2zzc96 + } + ... on Node { + id + } + } +} + +fragment prReviewsContainer_pullRequest_2zzc96 on PullRequest { + url + reviews(first: $reviewCount, after: $reviewCursor) { + pageInfo { + hasNextPage + endCursor + } + edges { + cursor + node { + id + body + commitId: commit { + oid + id + } + state + submittedAt + login: author { + __typename + login + ... on Node { + id + } + } + author { + __typename + avatarUrl + ... on Node { + id + } + } + comments(first: 100) { + pageInfo { + hasNextPage + endCursor + } + nodes { + id + author { + __typename + avatarUrl + login + ... on Node { + id + } + } + bodyHTML + path + position + replyTo { + id + } + createdAt + url + } + } + __typename + } + } + } +} +*/ + +const node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "LocalArgument", + "name": "reviewCount", + "type": "Int", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCursor", + "type": "String", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "url", + "type": "URI!", + "defaultValue": null + } +], +v1 = [ + { + "kind": "Variable", + "name": "url", + "variableName": "url", + "type": "URI!" + } +], +v2 = { + "kind": "ScalarField", + "alias": null, + "name": "__typename", + "args": null, + "storageKey": null +}, +v3 = { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null +}, +v4 = { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null +}, +v5 = [ + { + "kind": "Variable", + "name": "after", + "variableName": "reviewCursor", + "type": "String" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "reviewCount", + "type": "Int" + } +], +v6 = { + "kind": "LinkedField", + "alias": null, + "name": "pageInfo", + "storageKey": null, + "args": null, + "concreteType": "PageInfo", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "hasNextPage", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "endCursor", + "args": null, + "storageKey": null + } + ] +}, +v7 = { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null +}, +v8 = { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null +}; +return { + "kind": "Request", + "operationKind": "query", + "name": "prReviewsContainerQuery", + "id": null, + "text": "query prReviewsContainerQuery(\n $reviewCount: Int\n $reviewCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_2zzc96\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n", + "metadata": {}, + "fragment": { + "kind": "Fragment", + "name": "prReviewsContainerQuery", + "type": "Query", + "metadata": null, + "argumentDefinitions": v0, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "resource", + "storageKey": null, + "args": v1, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "InlineFragment", + "type": "PullRequest", + "selections": [ + { + "kind": "FragmentSpread", + "name": "prReviewsContainer_pullRequest", + "args": [ + { + "kind": "Variable", + "name": "reviewCount", + "variableName": "reviewCount", + "type": null + }, + { + "kind": "Variable", + "name": "reviewCursor", + "variableName": "reviewCursor", + "type": null + } + ] + } + ] + } + ] + } + ] + }, + "operation": { + "kind": "Operation", + "name": "prReviewsContainerQuery", + "argumentDefinitions": v0, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "resource", + "storageKey": null, + "args": v1, + "concreteType": null, + "plural": false, + "selections": [ + v2, + v3, + { + "kind": "InlineFragment", + "type": "PullRequest", + "selections": [ + v4, + { + "kind": "LinkedField", + "alias": null, + "name": "reviews", + "storageKey": null, + "args": v5, + "concreteType": "PullRequestReviewConnection", + "plural": false, + "selections": [ + v6, + { + "kind": "LinkedField", + "alias": null, + "name": "edges", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewEdge", + "plural": true, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "cursor", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "node", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReview", + "plural": false, + "selections": [ + v3, + { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "commitId", + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "oid", + "args": null, + "storageKey": null + }, + v3 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "state", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "submittedAt", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "login", + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v2, + v7, + v3 + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v2, + v8, + v3 + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": "comments(first:100)", + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 100, + "type": "Int" + } + ], + "concreteType": "PullRequestReviewCommentConnection", + "plural": false, + "selections": [ + v6, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": true, + "selections": [ + v3, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v2, + v8, + v7, + v3 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "bodyHTML", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "path", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "position", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v3 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + v4 + ] + } + ] + }, + v2 + ] + } + ] + } + ] + }, + { + "kind": "LinkedHandle", + "alias": null, + "name": "reviews", + "args": v5, + "handle": "connection", + "key": "prReviewsContainer_reviews", + "filters": null + } + ] + } + ] + } + ] + } +}; +})(); +// prettier-ignore +(node/*: any*/).hash = '29e5b225e2d3999e4cd475edc354015d'; +module.exports = node; diff --git a/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js new file mode 100644 index 0000000000..192298ed34 --- /dev/null +++ b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js @@ -0,0 +1,354 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +export type PullRequestReviewState = "APPROVED" | "CHANGES_REQUESTED" | "COMMENTED" | "DISMISSED" | "PENDING" | "%future added value"; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type prReviewsContainer_pullRequest$ref: FragmentReference; +export type prReviewsContainer_pullRequest = {| + +url: any, + +reviews: ?{| + +pageInfo: {| + +hasNextPage: boolean, + +endCursor: ?string, + |}, + +edges: ?$ReadOnlyArray, + |}, + |}, + |}>, + |}, + +$refType: prReviewsContainer_pullRequest$ref, +|}; +*/ + + +const node/*: ConcreteFragment*/ = (function(){ +var v0 = { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null +}, +v1 = { + "kind": "LinkedField", + "alias": null, + "name": "pageInfo", + "storageKey": null, + "args": null, + "concreteType": "PageInfo", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "hasNextPage", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "endCursor", + "args": null, + "storageKey": null + } + ] +}, +v2 = { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null +}, +v3 = { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null +}, +v4 = { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null +}; +return { + "kind": "Fragment", + "name": "prReviewsContainer_pullRequest", + "type": "PullRequest", + "metadata": { + "connection": [ + { + "count": "reviewCount", + "cursor": "reviewCursor", + "direction": "forward", + "path": [ + "reviews" + ] + } + ] + }, + "argumentDefinitions": [ + { + "kind": "LocalArgument", + "name": "reviewCount", + "type": "Int", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCursor", + "type": "String", + "defaultValue": null + } + ], + "selections": [ + v0, + { + "kind": "LinkedField", + "alias": "reviews", + "name": "__prReviewsContainer_reviews_connection", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewConnection", + "plural": false, + "selections": [ + v1, + { + "kind": "LinkedField", + "alias": null, + "name": "edges", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewEdge", + "plural": true, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "cursor", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "node", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReview", + "plural": false, + "selections": [ + v2, + { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "commitId", + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "oid", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "state", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "submittedAt", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "login", + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v3 + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v4 + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": "comments(first:100)", + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 100, + "type": "Int" + } + ], + "concreteType": "PullRequestReviewCommentConnection", + "plural": false, + "selections": [ + v1, + { + "kind": "LinkedField", + "alias": null, + "name": "nodes", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": true, + "selections": [ + v2, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v4, + v3 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "bodyHTML", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "path", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "position", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v2 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + v0 + ] + } + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "__typename", + "args": null, + "storageKey": null + } + ] + } + ] + } + ] + } + ] +}; +})(); +// prettier-ignore +(node/*: any*/).hash = 'd22654576b18d8a49cff9628b69d7b17'; +module.exports = node; diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index 2f8a2e40f1..ecb33175e9 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -124,6 +124,8 @@ export default class IssueishDetailContainer extends React.Component { $commitCursor: String, $commentCount: Int!, $commentCursor: String, + $reviewCount: Int, + $reviewCursor: String, ) { repository(owner: $repoOwner, name: $repoName) { ...issueishDetailController_repository @arguments( @@ -134,6 +136,8 @@ export default class IssueishDetailContainer extends React.Component { commitCursor: $commitCursor, commentCount: $commentCount, commentCursor: $commentCursor, + reviewCount: $reviewCount, + reviewCursor: $reviewCursor, ) } } @@ -148,6 +152,8 @@ export default class IssueishDetailContainer extends React.Component { commitCursor: null, commentCount: 100, commentCursor: null, + reviewCount: 3, + reviewCursor: null, }; return ( diff --git a/lib/containers/pr-reviews-container.js b/lib/containers/pr-reviews-container.js new file mode 100644 index 0000000000..d4f6992ee6 --- /dev/null +++ b/lib/containers/pr-reviews-container.js @@ -0,0 +1,92 @@ +import {graphql, createPaginationContainer} from 'react-relay'; + +import PullRequestReviewsView from '../views/pr-comments-view'; + +export default createPaginationContainer(PullRequestReviewsView, { + pullRequest: graphql` + fragment prReviewsContainer_pullRequest on PullRequest + @argumentDefinitions( + reviewCount: {type: "Int"}, + reviewCursor: {type: "String"} + ) { + ... on PullRequest { + url + reviews(first: $reviewCount, after: $reviewCursor) @connection(key: "prReviewsContainer_reviews") { + pageInfo { + hasNextPage + endCursor + } + + edges { + cursor + node { + id + body + commitId: commit { + oid + } + state + submittedAt + login: author { + login + } + author { + avatarUrl + } + comments(first: 100) { + pageInfo { + hasNextPage + endCursor + } + nodes { + id + author { + avatarUrl + login + } + bodyHTML + path + position + replyTo { + id + } + createdAt + url + } + } + } + } + } + } + } + `, +}, { + direction: 'forward', + getConnectionFromProps(props) { + console.log(props.pullRequest); + return props.pullRequest.reviews; + }, + getFragmentVariables(prevVars, totalCount) { + return { + ...prevVars, + reviewCount: totalCount, + }; + }, + getVariables(props, {count, cursor}, fragmentVariables) { + console.log(props.pullRequest); + return { + url: props.pullRequest.url, + reviewCount: count, + reviewCursor: cursor, + }; + }, + query: graphql` + query prReviewsContainerQuery($reviewCount: Int, $reviewCursor: String, $url: URI!) { + resource(url: $url) { + ... on PullRequest { + ...prReviewsContainer_pullRequest @arguments(reviewCount: $reviewCount, reviewCursor: $reviewCursor) + } + } + } + `, +}); diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index 34aff4255d..c82a1a5e27 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 83a0f29490df40e31d9f5aee5cdbae2f + * @relayHash b8344287c886583940c118565aa06547 */ /* eslint-disable */ @@ -20,6 +20,8 @@ export type prDetailViewRefetchQueryVariables = {| commitCursor?: ?string, commentCount: number, commentCursor?: ?string, + reviewCount?: ?number, + reviewCursor?: ?string, |}; export type prDetailViewRefetchQueryResponse = {| +repository: ?{| @@ -44,6 +46,8 @@ query prDetailViewRefetchQuery( $timelineCursor: String $commitCount: Int! $commitCursor: String + $reviewCount: Int + $reviewCursor: String ) { repository: node(id: $repoId) { __typename @@ -52,7 +56,7 @@ query prDetailViewRefetchQuery( } pullRequest: node(id: $issueishId) { __typename - ...prDetailView_pullRequest_1Etigl + ...prDetailView_pullRequest_2qM2KL id } } @@ -67,94 +71,14 @@ fragment prDetailView_repository_3D8CP9 on Repository { } } -fragment prDetailView_pullRequest_1Etigl on PullRequest { +fragment prDetailView_pullRequest_2qM2KL on PullRequest { __typename ... on Node { id } isCrossRepository changedFiles - comments { - totalCount - } - reviews(first: 100) { - pageInfo { - hasNextPage - endCursor - } - nodes { - id - body - commitId: commit { - oid - id - } - state - submittedAt - login: author { - __typename - login - ... on Node { - id - } - } - author { - __typename - avatarUrl - ... on Node { - id - } - } - comments(first: 100) { - pageInfo { - hasNextPage - endCursor - } - nodes { - id - pullRequestId: pullRequest { - number - id - } - databaseId - login: author { - __typename - login - ... on Node { - id - } - } - author { - __typename - avatarUrl - login - ... on Node { - id - } - } - body - bodyHTML - path - commitSha: commit { - oid - id - } - diffHunk - position - originalPosition - originalCommitId: originalCommit { - oid - id - } - replyTo { - id - } - createdAt - url - } - } - } - } + ...prReviewsContainer_pullRequest_2zzc96 ...prCommitsView_pullRequest_38TpXw countedCommits: commits { totalCount @@ -194,6 +118,69 @@ fragment prDetailView_pullRequest_1Etigl on PullRequest { } } +fragment prReviewsContainer_pullRequest_2zzc96 on PullRequest { + url + reviews(first: $reviewCount, after: $reviewCursor) { + pageInfo { + hasNextPage + endCursor + } + edges { + cursor + node { + id + body + commitId: commit { + oid + id + } + state + submittedAt + login: author { + __typename + login + ... on Node { + id + } + } + author { + __typename + avatarUrl + ... on Node { + id + } + } + comments(first: 100) { + pageInfo { + hasNextPage + endCursor + } + nodes { + id + author { + __typename + avatarUrl + login + ... on Node { + id + } + } + bodyHTML + path + position + replyTo { + id + } + createdAt + url + } + } + __typename + } + } + } +} + fragment prCommitsView_pullRequest_38TpXw on PullRequest { url commits(first: $commitCount, after: $commitCursor) { @@ -539,6 +526,18 @@ var v0 = [ "name": "commentCursor", "type": "String", "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCount", + "type": "Int", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCursor", + "type": "String", + "defaultValue": null } ], v1 = [ @@ -615,7 +614,7 @@ v10 = { v11 = { "kind": "ScalarField", "alias": null, - "name": "state", + "name": "number", "args": null, "storageKey": null }, @@ -626,20 +625,24 @@ v12 = { "args": null, "storageKey": null }, -v13 = [ - { - "kind": "ScalarField", - "alias": null, - "name": "totalCount", - "args": null, - "storageKey": null - } -], +v13 = { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null +}, v14 = [ { - "kind": "Literal", + "kind": "Variable", + "name": "after", + "variableName": "reviewCursor", + "type": "String" + }, + { + "kind": "Variable", "name": "first", - "value": 100, + "variableName": "reviewCount", "type": "Int" } ], @@ -673,7 +676,7 @@ v17 = { v18 = { "kind": "ScalarField", "alias": null, - "name": "body", + "name": "cursor", "args": null, "storageKey": null }, @@ -688,14 +691,11 @@ v19 = [ v6 ], v20 = { - "kind": "LinkedField", - "alias": "login", - "name": "author", - "storageKey": null, + "kind": "ScalarField", + "alias": null, + "name": "state", "args": null, - "concreteType": null, - "plural": false, - "selections": v9 + "storageKey": null }, v21 = { "kind": "ScalarField", @@ -705,12 +705,20 @@ v21 = { "storageKey": null }, v22 = [ + { + "kind": "Literal", + "name": "first", + "value": 100, + "type": "Int" + } +], +v23 = [ v5, v21, v8, v6 ], -v23 = { +v24 = { "kind": "LinkedField", "alias": null, "name": "author", @@ -718,26 +726,19 @@ v23 = { "args": null, "concreteType": null, "plural": false, - "selections": v22 -}, -v24 = { - "kind": "ScalarField", - "alias": null, - "name": "bodyHTML", - "args": null, - "storageKey": null + "selections": v23 }, v25 = { "kind": "ScalarField", "alias": null, - "name": "path", + "name": "bodyHTML", "args": null, "storageKey": null }, v26 = { "kind": "ScalarField", "alias": null, - "name": "number", + "name": "path", "args": null, "storageKey": null }, @@ -755,14 +756,7 @@ v28 = { "args": null, "storageKey": null }, -v29 = { - "kind": "ScalarField", - "alias": null, - "name": "url", - "args": null, - "storageKey": null -}, -v30 = [ +v29 = [ { "kind": "Variable", "name": "after", @@ -776,7 +770,7 @@ v30 = [ "type": "Int" } ], -v31 = { +v30 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -789,31 +783,33 @@ v31 = { v15 ] }, -v32 = { - "kind": "ScalarField", - "alias": null, - "name": "cursor", - "args": null, - "storageKey": null -}, -v33 = { +v31 = { "kind": "ScalarField", "alias": "sha", "name": "oid", "args": null, "storageKey": null }, -v34 = { +v32 = [ + { + "kind": "ScalarField", + "alias": null, + "name": "totalCount", + "args": null, + "storageKey": null + } +], +v33 = { "kind": "ScalarField", "alias": null, "name": "title", "args": null, "storageKey": null }, -v35 = [ - v29 +v34 = [ + v13 ], -v36 = [ +v35 = [ { "kind": "Variable", "name": "after", @@ -827,13 +823,13 @@ v36 = [ "type": "Int" } ], -v37 = [ +v36 = [ v5, v8, v21, v6 ], -v38 = { +v37 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -843,7 +839,7 @@ v38 = { "plural": false, "selections": v19 }, -v39 = { +v38 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -851,9 +847,9 @@ v39 = { "args": null, "concreteType": null, "plural": false, - "selections": v22 + "selections": v23 }, -v40 = { +v39 = { "kind": "LinkedField", "alias": null, "name": "user", @@ -871,7 +867,7 @@ return { "operationKind": "query", "name": "prDetailViewRefetchQuery", "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_1Etigl\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n comments {\n totalCount\n }\n reviews(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n pullRequestId: pullRequest {\n number\n id\n }\n databaseId\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n commitSha: commit {\n oid\n id\n }\n diffHunk\n position\n originalPosition\n originalCommitId: originalCommit {\n oid\n id\n }\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n }\n }\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int\n $reviewCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_2zzc96\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -936,6 +932,18 @@ return { "variableName": "commitCursor", "type": null }, + { + "kind": "Variable", + "name": "reviewCount", + "variableName": "reviewCount", + "type": null + }, + { + "kind": "Variable", + "name": "reviewCursor", + "variableName": "reviewCursor", + "type": null + }, v2, v3 ] @@ -995,21 +1003,12 @@ return { "args": null, "storageKey": null }, - { - "kind": "LinkedField", - "alias": null, - "name": "comments", - "storageKey": null, - "args": null, - "concreteType": "IssueCommentConnection", - "plural": false, - "selections": v13 - }, + v13, { "kind": "LinkedField", "alias": null, "name": "reviews", - "storageKey": "reviews(first:100)", + "storageKey": null, "args": v14, "concreteType": "PullRequestReviewConnection", "plural": false, @@ -1018,160 +1017,140 @@ return { { "kind": "LinkedField", "alias": null, - "name": "nodes", + "name": "edges", "storageKey": null, "args": null, - "concreteType": "PullRequestReview", + "concreteType": "PullRequestReviewEdge", "plural": true, "selections": [ - v6, v18, - { - "kind": "LinkedField", - "alias": "commitId", - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v19 - }, - v11, - { - "kind": "ScalarField", - "alias": null, - "name": "submittedAt", - "args": null, - "storageKey": null - }, - v20, { "kind": "LinkedField", "alias": null, - "name": "author", + "name": "node", "storageKey": null, "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v5, - v21, - v6 - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "comments", - "storageKey": "comments(first:100)", - "args": v14, - "concreteType": "PullRequestReviewCommentConnection", + "concreteType": "PullRequestReview", "plural": false, "selections": [ - v17, + v6, + { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "commitId", + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": v19 + }, + v20, + { + "kind": "ScalarField", + "alias": null, + "name": "submittedAt", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "login", + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": v9 + }, { "kind": "LinkedField", "alias": null, - "name": "nodes", + "name": "author", "storageKey": null, "args": null, - "concreteType": "PullRequestReviewComment", - "plural": true, + "concreteType": null, + "plural": false, "selections": [ - { - "kind": "LinkedField", - "alias": "commitSha", - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v19 - }, - v6, - { - "kind": "ScalarField", - "alias": null, - "name": "databaseId", - "args": null, - "storageKey": null - }, - v20, - v23, - v18, - v24, - v25, - { - "kind": "LinkedField", - "alias": "pullRequestId", - "name": "pullRequest", - "storageKey": null, - "args": null, - "concreteType": "PullRequest", - "plural": false, - "selections": [ - v26, - v6 - ] - }, - { - "kind": "ScalarField", - "alias": null, - "name": "diffHunk", - "args": null, - "storageKey": null - }, - v27, - { - "kind": "ScalarField", - "alias": null, - "name": "originalPosition", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": "originalCommitId", - "name": "originalCommit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v19 - }, + v5, + v21, + v6 + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": "comments(first:100)", + "args": v22, + "concreteType": "PullRequestReviewCommentConnection", + "plural": false, + "selections": [ + v17, { "kind": "LinkedField", "alias": null, - "name": "replyTo", + "name": "nodes", "storageKey": null, "args": null, "concreteType": "PullRequestReviewComment", - "plural": false, + "plural": true, "selections": [ - v6 + v6, + v24, + v25, + v26, + v27, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v6 + ] + }, + v28, + v13 ] - }, - v28, - v29 + } ] - } + }, + v5 ] } ] } ] }, - v29, + { + "kind": "LinkedHandle", + "alias": null, + "name": "reviews", + "args": v14, + "handle": "connection", + "key": "prReviewsContainer_reviews", + "filters": null + }, { "kind": "LinkedField", "alias": null, "name": "commits", "storageKey": null, - "args": v30, + "args": v29, "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ - v31, + v30, { "kind": "LinkedField", "alias": null, @@ -1181,7 +1160,7 @@ return { "concreteType": "PullRequestCommitEdge", "plural": true, "selections": [ - v32, + v18, { "kind": "LinkedField", "alias": null, @@ -1242,8 +1221,8 @@ return { "args": null, "storageKey": null }, - v33, - v29 + v31, + v13 ] }, v6, @@ -1258,7 +1237,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v30, + "args": v29, "handle": "connection", "key": "prCommitsView_commits", "filters": null @@ -1271,7 +1250,7 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v13 + "selections": v32 }, { "kind": "LinkedField", @@ -1325,7 +1304,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v11, + v20, { "kind": "LinkedField", "alias": null, @@ -1336,7 +1315,7 @@ return { "plural": true, "selections": [ v6, - v11, + v20, { "kind": "ScalarField", "alias": null, @@ -1373,9 +1352,9 @@ return { } ] }, - v26, - v34, - v24, + v20, + v33, + v25, { "kind": "ScalarField", "alias": null, @@ -1406,12 +1385,12 @@ return { { "kind": "InlineFragment", "type": "Bot", - "selections": v35 + "selections": v34 }, { "kind": "InlineFragment", "type": "User", - "selections": v35 + "selections": v34 } ] }, @@ -1443,11 +1422,11 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": v36, + "args": v35, "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v31, + v30, { "kind": "LinkedField", "alias": null, @@ -1457,7 +1436,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v32, + v18, { "kind": "LinkedField", "alias": null, @@ -1489,7 +1468,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v37 + "selections": v36 }, { "kind": "LinkedField", @@ -1527,9 +1506,9 @@ return { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v26, - v34, - v29, + v11, + v33, + v13, { "kind": "ScalarField", "alias": "prState", @@ -1543,9 +1522,9 @@ return { "kind": "InlineFragment", "type": "Issue", "selections": [ - v26, - v34, - v29, + v11, + v33, + v13, { "kind": "ScalarField", "alias": "issueState", @@ -1563,13 +1542,13 @@ return { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v38, + v37, { "kind": "LinkedField", "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v14, + "args": v22, "concreteType": "CommitCommentConnection", "plural": false, "selections": [ @@ -1600,12 +1579,12 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v37 + "selections": v36 }, - v38, - v24, - v28, + v37, v25, + v28, + v26, v27 ] } @@ -1619,7 +1598,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v39, + v38, { "kind": "LinkedField", "alias": null, @@ -1647,8 +1626,8 @@ return { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v39, v38, + v37, { "kind": "ScalarField", "alias": null, @@ -1663,10 +1642,10 @@ return { "kind": "InlineFragment", "type": "IssueComment", "selections": [ - v23, v24, + v25, v28, - v29 + v13 ] }, { @@ -1683,7 +1662,7 @@ return { "plural": false, "selections": [ v7, - v40, + v39, v21 ] }, @@ -1698,7 +1677,7 @@ return { "selections": [ v7, v21, - v40 + v39 ] }, { @@ -1708,7 +1687,7 @@ return { "args": null, "storageKey": null }, - v33, + v31, { "kind": "ScalarField", "alias": null, @@ -1742,7 +1721,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v36, + "args": v35, "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null @@ -1771,7 +1750,7 @@ return { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v13 + "selections": v32 } ] } @@ -1784,5 +1763,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'f928e12221da7ed9e70170512e98cbb2'; +(node/*: any*/).hash = '443d5e2812d4ab3aca1a33b1e95e1d14'; module.exports = node; diff --git a/lib/views/__generated__/prDetailView_pullRequest.graphql.js b/lib/views/__generated__/prDetailView_pullRequest.graphql.js index e98a5c4a5f..331dbe1566 100644 --- a/lib/views/__generated__/prDetailView_pullRequest.graphql.js +++ b/lib/views/__generated__/prDetailView_pullRequest.graphql.js @@ -9,9 +9,9 @@ /*:: import type { ConcreteFragment } from 'relay-runtime'; type prCommitsView_pullRequest$ref = any; +type prReviewsContainer_pullRequest$ref = any; type prStatusesView_pullRequest$ref = any; type prTimelineController_pullRequest$ref = any; -export type PullRequestReviewState = "APPROVED" | "CHANGES_REQUESTED" | "COMMENTED" | "DISMISSED" | "PENDING" | "%future added value"; export type PullRequestState = "CLOSED" | "MERGED" | "OPEN" | "%future added value"; export type ReactionContent = "CONFUSED" | "HEART" | "HOORAY" | "LAUGH" | "THUMBS_DOWN" | "THUMBS_UP" | "%future added value"; import type { FragmentReference } from "relay-runtime"; @@ -20,67 +20,6 @@ export type prDetailView_pullRequest = {| +id?: string, +isCrossRepository: boolean, +changedFiles: number, - +comments: {| - +totalCount: number - |}, - +reviews: ?{| - +pageInfo: {| - +hasNextPage: boolean, - +endCursor: ?string, - |}, - +nodes: ?$ReadOnlyArray, - |}, - |}>, - |}, +countedCommits: {| +totalCount: number |}, @@ -103,21 +42,14 @@ export type prDetailView_pullRequest = {| |}, |}>, +__typename: "PullRequest", - +$fragmentRefs: prCommitsView_pullRequest$ref & prStatusesView_pullRequest$ref & prTimelineController_pullRequest$ref, + +$fragmentRefs: prReviewsContainer_pullRequest$ref & prCommitsView_pullRequest$ref & prStatusesView_pullRequest$ref & prTimelineController_pullRequest$ref, +$refType: prDetailView_pullRequest$ref, |}; */ const node/*: ConcreteFragment*/ = (function(){ -var v0 = { - "kind": "ScalarField", - "alias": null, - "name": "state", - "args": null, - "storageKey": null -}, -v1 = [ +var v0 = [ { "kind": "ScalarField", "alias": null, @@ -126,111 +58,15 @@ v1 = [ "storageKey": null } ], -v2 = [ - { - "kind": "Literal", - "name": "first", - "value": 100, - "type": "Int" - } -], -v3 = { - "kind": "LinkedField", - "alias": null, - "name": "pageInfo", - "storageKey": null, - "args": null, - "concreteType": "PageInfo", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "hasNextPage", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "endCursor", - "args": null, - "storageKey": null - } - ] -}, -v4 = { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null -}, -v5 = { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null -}, -v6 = [ - { - "kind": "ScalarField", - "alias": null, - "name": "oid", - "args": null, - "storageKey": null - } -], -v7 = { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null -}, -v8 = { - "kind": "LinkedField", - "alias": "login", - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v7 - ] -}, -v9 = { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null -}, -v10 = { - "kind": "ScalarField", - "alias": null, - "name": "bodyHTML", - "args": null, - "storageKey": null -}, -v11 = { - "kind": "ScalarField", - "alias": null, - "name": "number", - "args": null, - "storageKey": null -}, -v12 = { +v1 = { "kind": "ScalarField", "alias": null, "name": "url", "args": null, "storageKey": null }, -v13 = [ - v12 +v2 = [ + v1 ]; return { "kind": "Fragment", @@ -273,221 +109,64 @@ return { "name": "commentCursor", "type": "String", "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCount", + "type": "Int", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCursor", + "type": "String", + "defaultValue": null } ], "selections": [ - v0, { "kind": "ScalarField", "alias": null, - "name": "__typename", + "name": "number", "args": null, "storageKey": null }, { "kind": "ScalarField", "alias": null, - "name": "isCrossRepository", + "name": "__typename", "args": null, "storageKey": null }, { "kind": "ScalarField", "alias": null, - "name": "changedFiles", + "name": "isCrossRepository", "args": null, "storageKey": null }, { - "kind": "LinkedField", + "kind": "ScalarField", "alias": null, - "name": "comments", - "storageKey": null, + "name": "changedFiles", "args": null, - "concreteType": "IssueCommentConnection", - "plural": false, - "selections": v1 + "storageKey": null }, { - "kind": "LinkedField", - "alias": null, - "name": "reviews", - "storageKey": "reviews(first:100)", - "args": v2, - "concreteType": "PullRequestReviewConnection", - "plural": false, - "selections": [ - v3, + "kind": "FragmentSpread", + "name": "prReviewsContainer_pullRequest", + "args": [ { - "kind": "LinkedField", - "alias": null, - "name": "nodes", - "storageKey": null, - "args": null, - "concreteType": "PullRequestReview", - "plural": true, - "selections": [ - v4, - v5, - { - "kind": "LinkedField", - "alias": "commitId", - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v6 - }, - v0, - { - "kind": "ScalarField", - "alias": null, - "name": "submittedAt", - "args": null, - "storageKey": null - }, - v8, - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v9 - ] - }, - { - "kind": "LinkedField", - "alias": null, - "name": "comments", - "storageKey": "comments(first:100)", - "args": v2, - "concreteType": "PullRequestReviewCommentConnection", - "plural": false, - "selections": [ - v3, - { - "kind": "LinkedField", - "alias": null, - "name": "nodes", - "storageKey": null, - "args": null, - "concreteType": "PullRequestReviewComment", - "plural": true, - "selections": [ - { - "kind": "LinkedField", - "alias": "commitSha", - "name": "commit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v6 - }, - v4, - { - "kind": "ScalarField", - "alias": null, - "name": "databaseId", - "args": null, - "storageKey": null - }, - v8, - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v9, - v7 - ] - }, - v5, - v10, - { - "kind": "ScalarField", - "alias": null, - "name": "path", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": "pullRequestId", - "name": "pullRequest", - "storageKey": null, - "args": null, - "concreteType": "PullRequest", - "plural": false, - "selections": [ - v11 - ] - }, - { - "kind": "ScalarField", - "alias": null, - "name": "diffHunk", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "position", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "originalPosition", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": "originalCommitId", - "name": "originalCommit", - "storageKey": null, - "args": null, - "concreteType": "Commit", - "plural": false, - "selections": v6 - }, - { - "kind": "LinkedField", - "alias": null, - "name": "replyTo", - "storageKey": null, - "args": null, - "concreteType": "PullRequestReviewComment", - "plural": false, - "selections": [ - v4 - ] - }, - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - }, - v12 - ] - } - ] - } - ] + "kind": "Variable", + "name": "reviewCount", + "variableName": "reviewCount", + "type": null + }, + { + "kind": "Variable", + "name": "reviewCursor", + "variableName": "reviewCursor", + "type": null } ] }, @@ -517,15 +196,27 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v1 + "selections": v0 }, { "kind": "FragmentSpread", "name": "prStatusesView_pullRequest", "args": null }, - v4, - v11, + { + "kind": "ScalarField", + "alias": null, + "name": "state", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null + }, { "kind": "ScalarField", "alias": null, @@ -533,7 +224,13 @@ return { "args": null, "storageKey": null }, - v10, + { + "kind": "ScalarField", + "alias": null, + "name": "bodyHTML", + "args": null, + "storageKey": null + }, { "kind": "ScalarField", "alias": null, @@ -557,17 +254,29 @@ return { "concreteType": null, "plural": false, "selections": [ - v7, - v9, + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + }, { "kind": "InlineFragment", "type": "Bot", - "selections": v13 + "selections": v2 }, { "kind": "InlineFragment", "type": "User", - "selections": v13 + "selections": v2 } ] }, @@ -589,7 +298,7 @@ return { } ] }, - v12, + v1, { "kind": "LinkedField", "alias": null, @@ -614,7 +323,7 @@ return { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v1 + "selections": v0 } ] } @@ -622,5 +331,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'ab20ccdc3ccc10843176a48cd07d03ae'; +(node/*: any*/).hash = 'e4e973dd4a21d8051d6908ff6844245a'; module.exports = node; diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 7768d9d5e1..c82b530b19 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -15,7 +15,7 @@ import Commands, {Command} from '../atom/commands'; import FilePatchHeaderView from './file-patch-header-view'; import FilePatchMetaView from './file-patch-meta-view'; import HunkHeaderView from './hunk-header-view'; -import PullRequestCommentsView from './pr-comments-view'; +import PullRequestsReviewsContainer from '../containers/pr-reviews-container'; import RefHolder from '../models/ref-holder'; import ChangedFileItem from '../items/changed-file-item'; import CommitDetailItem from '../items/commit-detail-item'; @@ -281,7 +281,7 @@ export default class MultiFilePatchView extends React.Component { /> )} - + {this.props.multiFilePatch.getFilePatches().map(this.renderFilePatchDecorations)} {this.renderLineDecorations( diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index a1beeb9d72..c58233785d 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -16,7 +16,7 @@ export default class PullRequestCommentsView extends React.Component { const commentsByRootCommentId = new Map(); - this.props.reviews.nodes.forEach(review => { + this.props.reviews.edges.forEach(review => { review.comments.nodes.forEach(comment => { if (!comment.replyTo) { commentsByRootCommentId.set(comment.id, [comment]); diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index 44560797bf..e87e40600a 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -351,6 +351,8 @@ export class BarePullRequestDetailView extends React.Component { timelineCursor: null, commitCount: 100, commitCursor: null, + reviewCount: 3, + reviewCursor: null, }, null, () => { this.setState({refreshing: false}); }, {force: true}); @@ -376,7 +378,9 @@ export default createRefetchContainer(BarePullRequestDetailView, { commitCount: {type: "Int!"}, commitCursor: {type: "String"}, commentCount: {type: "Int!"}, - commentCursor: {type: "String"} + commentCursor: {type: "String"}, + reviewCount: {type: "Int"}, + reviewCursor: {type: "String"} ) { __typename @@ -387,67 +391,9 @@ export default createRefetchContainer(BarePullRequestDetailView, { ... on PullRequest { isCrossRepository changedFiles - comments { - totalCount - } - reviews(first: 100) { - pageInfo { - hasNextPage - endCursor - } - nodes { - id - body - commitId: commit { - oid - } - state - submittedAt - login: author { - login - } - author { - avatarUrl - } - comments(first: 100) { - pageInfo { - hasNextPage - endCursor - } - nodes { - id - pullRequestId: pullRequest { - number - } - databaseId - login: author { - login - } - author { - avatarUrl - login - } - body - bodyHTML - path - commitSha: commit { - oid - } - diffHunk - position - originalPosition - originalCommitId: originalCommit { - oid - } - replyTo { - id - } - createdAt - url - } - } - } - } + + ...prReviewsContainer_pullRequest @arguments(reviewCount: $reviewCount, reviewCursor: $reviewCursor) + ...prCommitsView_pullRequest @arguments(commitCount: $commitCount, commitCursor: $commitCursor) countedCommits: commits { totalCount @@ -482,7 +428,9 @@ export default createRefetchContainer(BarePullRequestDetailView, { $commitCount: Int!, $commitCursor: String, $commentCount: Int!, - $commentCursor: String + $commentCursor: String, + $reviewCount: Int, + $reviewCursor: String ) { repository:node(id: $repoId) { ...prDetailView_repository @arguments( @@ -498,7 +446,9 @@ export default createRefetchContainer(BarePullRequestDetailView, { commitCount: $commitCount, commitCursor: $commitCursor, commentCount: $commentCount, - commentCursor: $commentCursor + commentCursor: $commentCursor, + reviewCount: $reviewCount, + reviewCursor: $reviewCursor ) } } From 498d5ab261b4ce13e1fa6af9903c0bee96dc92db Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 27 Dec 2018 16:57:51 -0800 Subject: [PATCH 2423/4847] Got reviews rendering again Only redner PullRequestReviewsContainer if itemType is IssueishDetailItem Co-Authored-By: Tilde Ann Thurium --- .../issueishDetailContainerQuery.graphql.js | 80 ++++++++++-------- .../prReviewsContainerQuery.graphql.js | 4 +- .../prReviewsContainer_pullRequest.graphql.js | 4 +- lib/containers/pr-reviews-container.js | 81 +++++++++---------- ...eishDetailController_repository.graphql.js | 26 +++++- lib/controllers/issueish-detail-controller.js | 4 + .../prDetailViewRefetchQuery.graphql.js | 4 +- lib/views/multi-file-patch-view.js | 11 ++- lib/views/pr-comments-view.js | 20 ++++- lib/views/pr-detail-view.js | 3 +- 10 files changed, 153 insertions(+), 84 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index ea0f609242..19a08b76f5 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 615fe759e1fcacb3ed5561310f21f8ed + * @relayHash e6b8ab56b47c1e91cd699080eeb040fa */ /* eslint-disable */ @@ -44,6 +44,8 @@ query issueishDetailContainerQuery( $timelineCursor: String $commitCount: Int! $commitCursor: String + $reviewCount: Int + $reviewCursor: String ) { repository(owner: $repoOwner, name: $repoName) { ...issueishDetailController_repository_y3nHF @@ -88,7 +90,7 @@ fragment issueishDetailController_repository_y3nHF on Repository { sshUrl id } - ...prDetailView_pullRequest_1Etigl + ...prDetailView_pullRequest_2qM2KL } ... on Node { id @@ -153,14 +155,14 @@ fragment issueDetailView_issue_4cAEh0 on Issue { } } -fragment prDetailView_pullRequest_1Etigl on PullRequest { +fragment prDetailView_pullRequest_2qM2KL on PullRequest { __typename ... on Node { id } isCrossRepository changedFiles - ...prReviewsContainer_pullRequest_3CUNoW + ...prReviewsContainer_pullRequest_2zzc96 ...prCommitsView_pullRequest_38TpXw countedCommits: commits { totalCount @@ -200,9 +202,9 @@ fragment prDetailView_pullRequest_1Etigl on PullRequest { } } -fragment prReviewsContainer_pullRequest_3CUNoW on PullRequest { +fragment prReviewsContainer_pullRequest_2zzc96 on PullRequest { url - reviews { + reviews(first: $reviewCount, after: $reviewCursor) { pageInfo { hasNextPage endCursor @@ -1103,7 +1105,21 @@ v34 = [ "type": "Int" } ], -v35 = { +v35 = [ + { + "kind": "Variable", + "name": "after", + "variableName": "reviewCursor", + "type": "String" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "reviewCount", + "type": "Int" + } +], +v36 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -1116,7 +1132,7 @@ v35 = { v18 ] }, -v36 = [ +v37 = [ { "kind": "ScalarField", "alias": null, @@ -1126,7 +1142,7 @@ v36 = [ }, v2 ], -v37 = [ +v38 = [ { "kind": "Literal", "name": "first", @@ -1134,21 +1150,21 @@ v37 = [ "type": "Int" } ], -v38 = { +v39 = { "kind": "ScalarField", "alias": null, "name": "path", "args": null, "storageKey": null }, -v39 = { +v40 = { "kind": "ScalarField", "alias": null, "name": "position", "args": null, "storageKey": null }, -v40 = { +v41 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -1156,9 +1172,9 @@ v40 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v36 + "selections": v37 }, -v41 = { +v42 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -1173,7 +1189,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_1Etigl\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_1Etigl on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_3CUNoW\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_3CUNoW on PullRequest {\n url\n reviews {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int\n $reviewCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_2zzc96\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1507,11 +1523,11 @@ return { "alias": null, "name": "reviews", "storageKey": null, - "args": null, + "args": v35, "concreteType": "PullRequestReviewConnection", "plural": false, "selections": [ - v35, + v36, { "kind": "LinkedField", "alias": null, @@ -1547,7 +1563,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v36 + "selections": v37 }, v11, { @@ -1586,11 +1602,11 @@ return { "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v37, + "args": v38, "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ - v35, + v36, { "kind": "LinkedField", "alias": null, @@ -1603,8 +1619,8 @@ return { v2, v26, v12, - v38, v39, + v40, { "kind": "LinkedField", "alias": null, @@ -1634,9 +1650,9 @@ return { "kind": "LinkedHandle", "alias": null, "name": "reviews", - "args": null, + "args": v35, "handle": "connection", - "key": "prReviewsContainer_reviews", + "key": "PrReviewsContainer_reviews", "filters": null }, v10, @@ -1819,13 +1835,13 @@ return { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v40, + v41, { "kind": "LinkedField", "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v37, + "args": v38, "concreteType": "CommitCommentConnection", "plural": false, "selections": [ @@ -1858,11 +1874,11 @@ return { "plural": false, "selections": v23 }, - v40, + v41, v12, v27, - v38, - v39 + v39, + v40 ] } ] @@ -1875,7 +1891,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v41, + v42, { "kind": "LinkedField", "alias": null, @@ -1884,7 +1900,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v36 + "selections": v37 }, { "kind": "LinkedField", @@ -1894,7 +1910,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v36 + "selections": v37 }, v27 ] @@ -1903,8 +1919,8 @@ return { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ + v42, v41, - v40, { "kind": "ScalarField", "alias": null, diff --git a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js index 8f1deb1224..853f2b03ed 100644 --- a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash dc9158ed713eb5e8c4c725dd4bfc9e00 + * @relayHash 78ed01f06235641c5292e2ee9fab3f03 */ /* eslint-disable */ @@ -487,7 +487,7 @@ return { "name": "reviews", "args": v5, "handle": "connection", - "key": "prReviewsContainer_reviews", + "key": "PrReviewsContainer_reviews", "filters": null } ] diff --git a/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js index 192298ed34..502c34a9b2 100644 --- a/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js +++ b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js @@ -152,7 +152,7 @@ return { { "kind": "LinkedField", "alias": "reviews", - "name": "__prReviewsContainer_reviews_connection", + "name": "__PrReviewsContainer_reviews_connection", "storageKey": null, "args": null, "concreteType": "PullRequestReviewConnection", @@ -350,5 +350,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'd22654576b18d8a49cff9628b69d7b17'; +(node/*: any*/).hash = 'd9ac6d62742b887f30bdeac72bbafefb'; module.exports = node; diff --git a/lib/containers/pr-reviews-container.js b/lib/containers/pr-reviews-container.js index d4f6992ee6..7897d2544e 100644 --- a/lib/containers/pr-reviews-container.js +++ b/lib/containers/pr-reviews-container.js @@ -9,50 +9,51 @@ export default createPaginationContainer(PullRequestReviewsView, { reviewCount: {type: "Int"}, reviewCursor: {type: "String"} ) { - ... on PullRequest { - url - reviews(first: $reviewCount, after: $reviewCursor) @connection(key: "prReviewsContainer_reviews") { - pageInfo { - hasNextPage - endCursor - } + url + reviews( + first: $reviewCount, + after: $reviewCursor + ) @connection(key: "PrReviewsContainer_reviews") { + pageInfo { + hasNextPage + endCursor + } - edges { - cursor - node { - id - body - commitId: commit { - oid - } - state - submittedAt - login: author { - login - } - author { - avatarUrl + edges { + cursor + node { + id + body + commitId: commit { + oid + } + state + submittedAt + login: author { + login + } + author { + avatarUrl + } + comments(first: 100) { + pageInfo { + hasNextPage + endCursor } - comments(first: 100) { - pageInfo { - hasNextPage - endCursor + nodes { + id + author { + avatarUrl + login } - nodes { + bodyHTML + path + position + replyTo { id - author { - avatarUrl - login - } - bodyHTML - path - position - replyTo { - id - } - createdAt - url } + createdAt + url } } } @@ -63,7 +64,6 @@ export default createPaginationContainer(PullRequestReviewsView, { }, { direction: 'forward', getConnectionFromProps(props) { - console.log(props.pullRequest); return props.pullRequest.reviews; }, getFragmentVariables(prevVars, totalCount) { @@ -73,7 +73,6 @@ export default createPaginationContainer(PullRequestReviewsView, { }; }, getVariables(props, {count, cursor}, fragmentVariables) { - console.log(props.pullRequest); return { url: props.pullRequest.url, reviewCount: count, diff --git a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js index 5f17d1be10..3c9b629202 100644 --- a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js +++ b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js @@ -180,6 +180,18 @@ return { "name": "commentCursor", "type": "String", "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCount", + "type": "Int!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCursor", + "type": "String", + "defaultValue": null } ], "selections": [ @@ -293,6 +305,18 @@ return { }, v6, v7, + { + "kind": "Variable", + "name": "reviewCount", + "variableName": "reviewCount", + "type": null + }, + { + "kind": "Variable", + "name": "reviewCursor", + "variableName": "reviewCursor", + "type": null + }, v8, v9 ] @@ -305,5 +329,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '0a288c1ab2398af40de27baf5db2aacb'; +(node/*: any*/).hash = 'f24ee4210befb63664396cf05d2afa79'; module.exports = node; diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index ae8bc47bda..75ef71c32d 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -299,6 +299,8 @@ export default createFragmentContainer(BareIssueishDetailController, { commitCursor: {type: "String"}, commentCount: {type: "Int!"}, commentCursor: {type: "String"}, + reviewCount: {type: "Int!"}, + reviewCursor: {type: "String"}, ) { ...issueDetailView_repository ...prDetailView_repository @@ -340,6 +342,8 @@ export default createFragmentContainer(BareIssueishDetailController, { commitCursor: $commitCursor, commentCount: $commentCount, commentCursor: $commentCursor, + reviewCount: $reviewCount, + reviewCursor: $reviewCursor, ) } } diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index c82a1a5e27..538e2cf4d6 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash b8344287c886583940c118565aa06547 + * @relayHash e7fd1c7c963c648913576e5f8a5f07d4 */ /* eslint-disable */ @@ -1138,7 +1138,7 @@ return { "name": "reviews", "args": v14, "handle": "connection", - "key": "prReviewsContainer_reviews", + "key": "PrReviewsContainer_reviews", "filters": null }, { diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index c82b530b19..7296aee04d 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -281,7 +281,8 @@ export default class MultiFilePatchView extends React.Component { /> )} - + {this.renderPullRequestReviews()} + {this.props.multiFilePatch.getFilePatches().map(this.renderFilePatchDecorations)} {this.renderLineDecorations( @@ -310,6 +311,14 @@ export default class MultiFilePatchView extends React.Component { ); } + renderPullRequestReviews() { + if (this.props.itemType === IssueishDetailItem) { + return ; + } else { + return null; + } + } + renderFilePatchDecorations = filePatch => { return ( diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index c58233785d..7ebf7294fc 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {Point, Range} from 'atom'; +import {RelayConnectionPropType} from '../prop-types'; import {toNativePathSep} from '../helpers'; import Marker from '../atom/marker'; @@ -9,14 +10,29 @@ import GithubDotcomMarkdown from './github-dotcom-markdown'; import Timeago from './timeago'; export default class PullRequestCommentsView extends React.Component { + static propTypes = { + relay: PropTypes.shape({ + hasMore: PropTypes.func.isRequired, + loadMore: PropTypes.func.isRequired, + isLoading: PropTypes.func.isRequired, + }).isRequired, + pullRequest: PropTypes.shape({ + reviews: RelayConnectionPropType( + PropTypes.object, + ), + }), + multiFilePatch: PropTypes.object.isRequired, + } + render() { - if (!this.props.reviews) { + if (!this.props.pullRequest || !this.props.pullRequest.reviews) { return null; } const commentsByRootCommentId = new Map(); - this.props.reviews.edges.forEach(review => { + this.props.pullRequest.reviews.edges.forEach(({node}) => { + const review = node; review.comments.nodes.forEach(comment => { if (!comment.replyTo) { commentsByRootCommentId.set(comment.id, [comment]); diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index e87e40600a..1abd62b92d 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -209,8 +209,9 @@ export class BarePullRequestDetailView extends React.Component { destroy={this.props.destroy} shouldRefetch={this.state.refreshing} - reviews={this.props.pullRequest.reviews} switchToIssueish={this.props.switchToIssueish} + + pullRequest={this.props.pullRequest} /> From 5ac1f5566778a0adb1215a86d935989099504617 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 27 Dec 2018 17:51:41 -0800 Subject: [PATCH 2424/4847] Fetch all reviews --- .../issueishDetailContainerQuery.graphql.js | 59 ++++--- .../prReviewsContainerQuery.graphql.js | 29 +-- .../prReviewsContainer_pullRequest.graphql.js | 29 +-- lib/containers/issueish-detail-container.js | 2 +- lib/containers/pr-reviews-container.js | 1 + .../prDetailViewRefetchQuery.graphql.js | 167 +++++++++--------- lib/views/pr-comments-view.js | 49 ++++- 7 files changed, 192 insertions(+), 144 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 19a08b76f5..2005783ec7 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash e6b8ab56b47c1e91cd699080eeb040fa + * @relayHash eacb91752813910cc6e618d90f821447 */ /* eslint-disable */ @@ -249,6 +249,7 @@ fragment prReviewsContainer_pullRequest_2zzc96 on PullRequest { id } } + body bodyHTML path position @@ -1132,7 +1133,14 @@ v36 = { v18 ] }, -v37 = [ +v37 = { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null +}, +v38 = [ { "kind": "ScalarField", "alias": null, @@ -1142,7 +1150,7 @@ v37 = [ }, v2 ], -v38 = [ +v39 = [ { "kind": "Literal", "name": "first", @@ -1150,21 +1158,21 @@ v38 = [ "type": "Int" } ], -v39 = { +v40 = { "kind": "ScalarField", "alias": null, "name": "path", "args": null, "storageKey": null }, -v40 = { +v41 = { "kind": "ScalarField", "alias": null, "name": "position", "args": null, "storageKey": null }, -v41 = { +v42 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -1172,9 +1180,9 @@ v41 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": v38 }, -v42 = { +v43 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -1189,7 +1197,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int\n $reviewCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_2zzc96\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int\n $reviewCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_2zzc96\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1548,13 +1556,7 @@ return { "plural": false, "selections": [ v2, - { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null - }, + v37, { "kind": "LinkedField", "alias": "commitId", @@ -1563,7 +1565,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": v38 }, v11, { @@ -1602,7 +1604,7 @@ return { "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v38, + "args": v39, "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ @@ -1618,9 +1620,10 @@ return { "selections": [ v2, v26, + v37, v12, - v39, v40, + v41, { "kind": "LinkedField", "alias": null, @@ -1835,13 +1838,13 @@ return { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v41, + v42, { "kind": "LinkedField", "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v38, + "args": v39, "concreteType": "CommitCommentConnection", "plural": false, "selections": [ @@ -1874,11 +1877,11 @@ return { "plural": false, "selections": v23 }, - v41, + v42, v12, v27, - v39, - v40 + v40, + v41 ] } ] @@ -1891,7 +1894,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v42, + v43, { "kind": "LinkedField", "alias": null, @@ -1900,7 +1903,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": v38 }, { "kind": "LinkedField", @@ -1910,7 +1913,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": v38 }, v27 ] @@ -1919,8 +1922,8 @@ return { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ + v43, v42, - v41, { "kind": "ScalarField", "alias": null, diff --git a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js index 853f2b03ed..e6ee421cf3 100644 --- a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 78ed01f06235641c5292e2ee9fab3f03 + * @relayHash c79a1d774a35cceb455839a0124e28fc */ /* eslint-disable */ @@ -91,6 +91,7 @@ fragment prReviewsContainer_pullRequest_2zzc96 on PullRequest { id } } + body bodyHTML path position @@ -200,11 +201,18 @@ v6 = { v7 = { "kind": "ScalarField", "alias": null, - "name": "login", + "name": "body", "args": null, "storageKey": null }, v8 = { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null +}, +v9 = { "kind": "ScalarField", "alias": null, "name": "avatarUrl", @@ -216,7 +224,7 @@ return { "operationKind": "query", "name": "prReviewsContainerQuery", "id": null, - "text": "query prReviewsContainerQuery(\n $reviewCount: Int\n $reviewCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_2zzc96\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n", + "text": "query prReviewsContainerQuery(\n $reviewCount: Int\n $reviewCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_2zzc96\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -319,13 +327,7 @@ return { "plural": false, "selections": [ v3, - { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null - }, + v7, { "kind": "LinkedField", "alias": "commitId", @@ -369,7 +371,7 @@ return { "plural": false, "selections": [ v2, - v7, + v8, v3 ] }, @@ -383,7 +385,7 @@ return { "plural": false, "selections": [ v2, - v8, + v9, v3 ] }, @@ -424,11 +426,12 @@ return { "plural": false, "selections": [ v2, + v9, v8, - v7, v3 ] }, + v7, { "kind": "ScalarField", "alias": null, diff --git a/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js index 502c34a9b2..cd27865199 100644 --- a/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js +++ b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js @@ -45,6 +45,7 @@ export type prReviewsContainer_pullRequest = {| +avatarUrl: any, +login: string, |}, + +body: string, +bodyHTML: any, +path: string, +position: ?number, @@ -106,11 +107,18 @@ v2 = { v3 = { "kind": "ScalarField", "alias": null, - "name": "login", + "name": "body", "args": null, "storageKey": null }, v4 = { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null +}, +v5 = { "kind": "ScalarField", "alias": null, "name": "avatarUrl", @@ -185,13 +193,7 @@ return { "plural": false, "selections": [ v2, - { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null - }, + v3, { "kind": "LinkedField", "alias": "commitId", @@ -233,7 +235,7 @@ return { "concreteType": null, "plural": false, "selections": [ - v3 + v4 ] }, { @@ -245,7 +247,7 @@ return { "concreteType": null, "plural": false, "selections": [ - v4 + v5 ] }, { @@ -284,10 +286,11 @@ return { "concreteType": null, "plural": false, "selections": [ - v4, - v3 + v5, + v4 ] }, + v3, { "kind": "ScalarField", "alias": null, @@ -350,5 +353,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'd9ac6d62742b887f30bdeac72bbafefb'; +(node/*: any*/).hash = 'd234d1f47b1a977b18174045b21cf0f0'; module.exports = node; diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index ecb33175e9..33e2404fbe 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -152,7 +152,7 @@ export default class IssueishDetailContainer extends React.Component { commitCursor: null, commentCount: 100, commentCursor: null, - reviewCount: 3, + reviewCount: 1, reviewCursor: null, }; diff --git a/lib/containers/pr-reviews-container.js b/lib/containers/pr-reviews-container.js index 7897d2544e..f90e50e1c2 100644 --- a/lib/containers/pr-reviews-container.js +++ b/lib/containers/pr-reviews-container.js @@ -46,6 +46,7 @@ export default createPaginationContainer(PullRequestReviewsView, { avatarUrl login } + body bodyHTML path position diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index 538e2cf4d6..fe380438d1 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash e7fd1c7c963c648913576e5f8a5f07d4 + * @relayHash 8b5005b08f8393c1b2d22577e9530360 */ /* eslint-disable */ @@ -165,6 +165,7 @@ fragment prReviewsContainer_pullRequest_2zzc96 on PullRequest { id } } + body bodyHTML path position @@ -680,7 +681,14 @@ v18 = { "args": null, "storageKey": null }, -v19 = [ +v19 = { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null +}, +v20 = [ { "kind": "ScalarField", "alias": null, @@ -690,21 +698,21 @@ v19 = [ }, v6 ], -v20 = { +v21 = { "kind": "ScalarField", "alias": null, "name": "state", "args": null, "storageKey": null }, -v21 = { +v22 = { "kind": "ScalarField", "alias": null, "name": "avatarUrl", "args": null, "storageKey": null }, -v22 = [ +v23 = [ { "kind": "Literal", "name": "first", @@ -712,13 +720,13 @@ v22 = [ "type": "Int" } ], -v23 = [ +v24 = [ v5, - v21, + v22, v8, v6 ], -v24 = { +v25 = { "kind": "LinkedField", "alias": null, "name": "author", @@ -726,37 +734,37 @@ v24 = { "args": null, "concreteType": null, "plural": false, - "selections": v23 + "selections": v24 }, -v25 = { +v26 = { "kind": "ScalarField", "alias": null, "name": "bodyHTML", "args": null, "storageKey": null }, -v26 = { +v27 = { "kind": "ScalarField", "alias": null, "name": "path", "args": null, "storageKey": null }, -v27 = { +v28 = { "kind": "ScalarField", "alias": null, "name": "position", "args": null, "storageKey": null }, -v28 = { +v29 = { "kind": "ScalarField", "alias": null, "name": "createdAt", "args": null, "storageKey": null }, -v29 = [ +v30 = [ { "kind": "Variable", "name": "after", @@ -770,7 +778,7 @@ v29 = [ "type": "Int" } ], -v30 = { +v31 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -783,14 +791,14 @@ v30 = { v15 ] }, -v31 = { +v32 = { "kind": "ScalarField", "alias": "sha", "name": "oid", "args": null, "storageKey": null }, -v32 = [ +v33 = [ { "kind": "ScalarField", "alias": null, @@ -799,17 +807,17 @@ v32 = [ "storageKey": null } ], -v33 = { +v34 = { "kind": "ScalarField", "alias": null, "name": "title", "args": null, "storageKey": null }, -v34 = [ +v35 = [ v13 ], -v35 = [ +v36 = [ { "kind": "Variable", "name": "after", @@ -823,13 +831,13 @@ v35 = [ "type": "Int" } ], -v36 = [ +v37 = [ v5, v8, - v21, + v22, v6 ], -v37 = { +v38 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -837,9 +845,9 @@ v37 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v19 + "selections": v20 }, -v38 = { +v39 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -847,9 +855,9 @@ v38 = { "args": null, "concreteType": null, "plural": false, - "selections": v23 + "selections": v24 }, -v39 = { +v40 = { "kind": "LinkedField", "alias": null, "name": "user", @@ -867,7 +875,7 @@ return { "operationKind": "query", "name": "prDetailViewRefetchQuery", "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int\n $reviewCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_2zzc96\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int\n $reviewCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_2zzc96\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1034,13 +1042,7 @@ return { "plural": false, "selections": [ v6, - { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null - }, + v19, { "kind": "LinkedField", "alias": "commitId", @@ -1049,9 +1051,9 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v19 + "selections": v20 }, - v20, + v21, { "kind": "ScalarField", "alias": null, @@ -1079,7 +1081,7 @@ return { "plural": false, "selections": [ v5, - v21, + v22, v6 ] }, @@ -1088,7 +1090,7 @@ return { "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v22, + "args": v23, "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ @@ -1103,10 +1105,11 @@ return { "plural": true, "selections": [ v6, - v24, v25, + v19, v26, v27, + v28, { "kind": "LinkedField", "alias": null, @@ -1119,7 +1122,7 @@ return { v6 ] }, - v28, + v29, v13 ] } @@ -1146,11 +1149,11 @@ return { "alias": null, "name": "commits", "storageKey": null, - "args": v29, + "args": v30, "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ - v30, + v31, { "kind": "LinkedField", "alias": null, @@ -1189,7 +1192,7 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v21, + v22, v7, { "kind": "ScalarField", @@ -1221,7 +1224,7 @@ return { "args": null, "storageKey": null }, - v31, + v32, v13 ] }, @@ -1237,7 +1240,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v29, + "args": v30, "handle": "connection", "key": "prCommitsView_commits", "filters": null @@ -1250,7 +1253,7 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v32 + "selections": v33 }, { "kind": "LinkedField", @@ -1304,7 +1307,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v20, + v21, { "kind": "LinkedField", "alias": null, @@ -1315,7 +1318,7 @@ return { "plural": true, "selections": [ v6, - v20, + v21, { "kind": "ScalarField", "alias": null, @@ -1352,9 +1355,9 @@ return { } ] }, - v20, - v33, - v25, + v21, + v34, + v26, { "kind": "ScalarField", "alias": null, @@ -1380,17 +1383,17 @@ return { "selections": [ v5, v8, - v21, + v22, v6, { "kind": "InlineFragment", "type": "Bot", - "selections": v34 + "selections": v35 }, { "kind": "InlineFragment", "type": "User", - "selections": v34 + "selections": v35 } ] }, @@ -1422,11 +1425,11 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": v35, + "args": v36, "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v30, + v31, { "kind": "LinkedField", "alias": null, @@ -1468,7 +1471,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v36 + "selections": v37 }, { "kind": "LinkedField", @@ -1507,7 +1510,7 @@ return { "type": "PullRequest", "selections": [ v11, - v33, + v34, v13, { "kind": "ScalarField", @@ -1523,7 +1526,7 @@ return { "type": "Issue", "selections": [ v11, - v33, + v34, v13, { "kind": "ScalarField", @@ -1542,13 +1545,13 @@ return { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v37, + v38, { "kind": "LinkedField", "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v22, + "args": v23, "concreteType": "CommitCommentConnection", "plural": false, "selections": [ @@ -1579,13 +1582,13 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v36 + "selections": v37 }, - v37, - v25, - v28, + v38, v26, - v27 + v29, + v27, + v28 ] } ] @@ -1598,7 +1601,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v38, + v39, { "kind": "LinkedField", "alias": null, @@ -1607,7 +1610,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v19 + "selections": v20 }, { "kind": "LinkedField", @@ -1617,17 +1620,17 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v19 + "selections": v20 }, - v28 + v29 ] }, { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ + v39, v38, - v37, { "kind": "ScalarField", "alias": null, @@ -1635,16 +1638,16 @@ return { "args": null, "storageKey": null }, - v28 + v29 ] }, { "kind": "InlineFragment", "type": "IssueComment", "selections": [ - v24, v25, - v28, + v26, + v29, v13 ] }, @@ -1662,8 +1665,8 @@ return { "plural": false, "selections": [ v7, - v39, - v21 + v40, + v22 ] }, { @@ -1676,8 +1679,8 @@ return { "plural": false, "selections": [ v7, - v21, - v39 + v22, + v40 ] }, { @@ -1687,7 +1690,7 @@ return { "args": null, "storageKey": null }, - v31, + v32, { "kind": "ScalarField", "alias": null, @@ -1721,7 +1724,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v35, + "args": v36, "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null @@ -1750,7 +1753,7 @@ return { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v32 + "selections": v33 } ] } diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index 7ebf7294fc..bd2369f41f 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -24,6 +24,37 @@ export default class PullRequestCommentsView extends React.Component { multiFilePatch: PropTypes.object.isRequired, } + componentDidMount() { + console.log('DID MOUNT'); + this._attemptToLoadMoreReviews(); + } + + _loadMoreReviews = () => { + this.props.relay.loadMore( + 1, // Fetch the next 10 feed items + error => { + this._attemptToLoadMoreReviews(); + if (error) { + console.log(error); + } + }, + ); + } + + _attemptToLoadMoreReviews = () => { + if (!this.props.relay.hasMore()) { + return; + } + + if (this.props.relay.isLoading()) { + setTimeout(() => { + this._loadMoreReviews(); + }, 300); + } else { + this._loadMoreReviews(); + } + } + render() { if (!this.props.pullRequest || !this.props.pullRequest.reviews) { return null; @@ -42,6 +73,7 @@ export default class PullRequestCommentsView extends React.Component { }); }); + console.log('SIZE', commentsByRootCommentId.size, [...commentsByRootCommentId]); return [...commentsByRootCommentId].reverse().map(([rootCommentId, comments]) => { const rootComment = comments[0]; @@ -56,13 +88,16 @@ export default class PullRequestCommentsView extends React.Component { return ( - {comments.map(comment => - , - )} + {comments.map(comment => { + console.log(comment.body); + return ( + + ); + })} ); From 38efd85cf03f8605eedec56de8952db197885fe1 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 27 Dec 2018 17:52:08 -0800 Subject: [PATCH 2425/4847] Hack to get comments to show up in correct order. TODO: fixme --- lib/views/pr-comments-view.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index bd2369f41f..b0b5eebbb3 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -9,6 +9,8 @@ import Decoration from '../atom/decoration'; import GithubDotcomMarkdown from './github-dotcom-markdown'; import Timeago from './timeago'; +let count = 0; + export default class PullRequestCommentsView extends React.Component { static propTypes = { relay: PropTypes.shape({ @@ -86,7 +88,7 @@ export default class PullRequestCommentsView extends React.Component { const point = new Point(row, 0); const range = new Range(point, point); return ( - + {comments.map(comment => { console.log(comment.body); From e4abb3c121f1ca7ae4887110b1482d2fe631c45b Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 27 Dec 2018 18:10:13 -0800 Subject: [PATCH 2426/4847] Fetch 100 review items at a time --- lib/containers/issueish-detail-container.js | 2 +- lib/views/pr-comments-view.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index 33e2404fbe..ee83411112 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -152,7 +152,7 @@ export default class IssueishDetailContainer extends React.Component { commitCursor: null, commentCount: 100, commentCursor: null, - reviewCount: 1, + reviewCount: 100, reviewCursor: null, }; diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index b0b5eebbb3..d269797d1f 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -33,7 +33,7 @@ export default class PullRequestCommentsView extends React.Component { _loadMoreReviews = () => { this.props.relay.loadMore( - 1, // Fetch the next 10 feed items + 100, error => { this._attemptToLoadMoreReviews(); if (error) { From 60c413a339127619f09afbaed959c1f2216db59b Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 27 Dec 2018 18:14:44 -0800 Subject: [PATCH 2427/4847] Handle case then `replyTo` comment is outdated --- lib/views/pr-comments-view.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index d269797d1f..c1d7922f2e 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -70,7 +70,15 @@ export default class PullRequestCommentsView extends React.Component { if (!comment.replyTo) { commentsByRootCommentId.set(comment.id, [comment]); } else { - commentsByRootCommentId.get(comment.replyTo.id).push(comment); + // When comment being replied to is outdated... + // Ran into this error when viewing files for https://github.com/numpy/numpy/pull/9998 + // for comment MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE1MzA1NTUzMw, + // who's replyTo comment is an outdated comment + if (!commentsByRootCommentId.get(comment.replyTo.id)) { + commentsByRootCommentId.set(comment.replyTo.id, [comment]); + } else { + commentsByRootCommentId.get(comment.replyTo.id).push(comment); + } } }); }); From 929115f14a1249e7fb91b48c67662dd8ae6e064e Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 27 Dec 2018 18:17:44 -0800 Subject: [PATCH 2428/4847] Add TODO to inline to fix hack to get comments to show up in order --- lib/views/pr-comments-view.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index c1d7922f2e..8624c1f159 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -95,6 +95,8 @@ export default class PullRequestCommentsView extends React.Component { const row = this.props.multiFilePatch.getBufferRowForDiffPosition(nativePath, rootComment.position); const point = new Point(row, 0); const range = new Range(point, point); + // TODO: find way to re-use nodes by using same key. this count++ hack is in place to get the comments to show up + // in the correct order after new pages of data are fetched. Test it by reducing the reviewCount to a small number return ( From 130f862105d3388f0220e6b8b679399aa27d1349 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 27 Dec 2018 18:33:12 -0800 Subject: [PATCH 2429/4847] =?UTF-8?q?Make=20it=20clear=20in=20the=20commen?= =?UTF-8?q?t=20that=20I'm=20not=20100%=20sure=20=C2=AF\=5F(=E3=83=84)=5F/?= =?UTF-8?q?=C2=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/views/pr-comments-view.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index 8624c1f159..c0755edce2 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -70,7 +70,8 @@ export default class PullRequestCommentsView extends React.Component { if (!comment.replyTo) { commentsByRootCommentId.set(comment.id, [comment]); } else { - // When comment being replied to is outdated... + // When comment being replied to is outdated...?? Not 100% sure... + // Why would we even get an outdated comment or a response to one here? // Ran into this error when viewing files for https://github.com/numpy/numpy/pull/9998 // for comment MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE1MzA1NTUzMw, // who's replyTo comment is an outdated comment From cbca7804f0a32180fce8ec1247d70a612a54d6f7 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 28 Dec 2018 11:29:56 -0800 Subject: [PATCH 2430/4847] WIP handle comments pagination Co-Authored-By: Tilde Ann Thurium --- .../pr-review-comments-container.js | 71 +++++++++++++++++++ lib/containers/pr-reviews-container.js | 30 ++------ lib/controllers/pr-reviews-controller.js | 60 ++++++++++++++++ 3 files changed, 137 insertions(+), 24 deletions(-) create mode 100644 lib/containers/pr-review-comments-container.js create mode 100644 lib/controllers/pr-reviews-controller.js diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js new file mode 100644 index 0000000000..ae23b3dca4 --- /dev/null +++ b/lib/containers/pr-review-comments-container.js @@ -0,0 +1,71 @@ +import {graphql, createPaginationContainer} from 'react-relay'; + +import PullRequestReviewCommentsView from '../views/pr-comments-view'; + +export default createPaginationContainer(PullRequestReviewCommentsView, { + review: graphql` + fragment prReviewCommentsContainer_review on PullRequestReview + @argumentDefinitions( + commentCount: {type: "Int!"}, + commentCursor: {type: "String"} + ) { + url + comments( + first: $commentCount, + after: $commentCursor + ) @connection(key: "PrReviewCommentsContainer_comments") { + pageInfo { + hasNextPage + endCursor + } + + edges { + cursor + node { + id + author { + avatarUrl + login + } + body + bodyHTML + path + position + replyTo { + id + } + createdAt + url + } + } + } + } + `, +}, { + direction: 'forward', + getConnectionFromProps(props) { + return props.review.comments; + }, + getFragmentVariables(prevVars, totalCount) { + return { + ...prevVars, + commentCount: totalCount, + }; + }, + getVariables(props, {count, cursor}, fragmentVariables) { + return { + url: props.review.url, + commentCount: count, + commentCursor: cursor, + }; + }, + query: graphql` + query prReviewCommentsContainerQuery($commentCount: Int, $commentCursor: String, $url: URI!) { + resource(url: $url) { + ... on PullRequestReview { + ...prReviewCommentsContainer_review @arguments(commentCount: $commentCount, commentCursor: $commentCursor) + } + } + } + `, +}); diff --git a/lib/containers/pr-reviews-container.js b/lib/containers/pr-reviews-container.js index f90e50e1c2..d57cd3a553 100644 --- a/lib/containers/pr-reviews-container.js +++ b/lib/containers/pr-reviews-container.js @@ -1,8 +1,8 @@ import {graphql, createPaginationContainer} from 'react-relay'; -import PullRequestReviewsView from '../views/pr-comments-view'; +import PullRequestReviewsController from '../controller/pr-reviews-controller'; -export default createPaginationContainer(PullRequestReviewsView, { +export default createPaginationContainer(PullRequestReviewsController, { pullRequest: graphql` fragment prReviewsContainer_pullRequest on PullRequest @argumentDefinitions( @@ -35,28 +35,10 @@ export default createPaginationContainer(PullRequestReviewsView, { author { avatarUrl } - comments(first: 100) { - pageInfo { - hasNextPage - endCursor - } - nodes { - id - author { - avatarUrl - login - } - body - bodyHTML - path - position - replyTo { - id - } - createdAt - url - } - } + ...prReviewCommentsContainer_review @arguments( + commentCount: $commentCount, + commentCursor: $commentCursor + ) } } } diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js new file mode 100644 index 0000000000..a5b20a3882 --- /dev/null +++ b/lib/controllers/pr-reviews-controller.js @@ -0,0 +1,60 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {RelayConnectionPropType} from '../prop-types'; + +import PullRequestReviewCommentsContainer from '../containers/pr-review-comments-container'; + + +export default class PullRequestReviewsController extends React.Component { + static propTypes = { + relay: PropTypes.shape({ + hasMore: PropTypes.func.isRequired, + loadMore: PropTypes.func.isRequired, + isLoading: PropTypes.func.isRequired, + }).isRequired, + pullRequest: PropTypes.shape({ + reviews: RelayConnectionPropType( + PropTypes.object, + ), + }), + multiFilePatch: PropTypes.object.isRequired, + } + + componentDidMount() { + this._attemptToLoadMoreReviews(); + } + + _loadMoreReviews = () => { + this.props.relay.loadMore( + 100, + error => { + this._attemptToLoadMoreReviews(); + if (error) { + console.log(error); + } + }, + ); + } + + _attemptToLoadMoreReviews = () => { + if (!this.props.relay.hasMore()) { + return; + } + + if (this.props.relay.isLoading()) { + setTimeout(() => { + this._loadMoreReviews(); + }, 300); + } else { + this._loadMoreReviews(); + } + } + + render() { + if (!this.props.pullRequest || !this.props.pullRequest.reviews) { + return null; + } + + return ; + } +} From 2c239ac42722be9fb89a95eaa0c40a314d59d6ed Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 28 Dec 2018 13:18:44 -0800 Subject: [PATCH 2431/4847] wip - render paginated comments Co-Authored-By: Katrina Uychaco --- .../issueishDetailContainerQuery.graphql.js | 136 ++++--- .../prReviewCommentsContainerQuery.graphql.js | 375 ++++++++++++++++++ ...rReviewCommentsContainer_review.graphql.js | 242 +++++++++++ .../prReviewsContainerQuery.graphql.js | 233 ++++++----- .../prReviewsContainer_pullRequest.graphql.js | 256 ++++-------- .../pr-review-comments-container.js | 13 +- lib/containers/pr-reviews-container.js | 2 +- lib/controllers/pr-reviews-controller.js | 9 +- .../prDetailViewRefetchQuery.graphql.js | 136 ++++--- lib/views/pr-comments-view.js | 9 +- 10 files changed, 1044 insertions(+), 367 deletions(-) create mode 100644 lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js create mode 100644 lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 2005783ec7..85536bb239 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash eacb91752813910cc6e618d90f821447 + * @relayHash 2272e39d4e33d96fe66954cf4a808caa */ /* eslint-disable */ @@ -44,6 +44,8 @@ query issueishDetailContainerQuery( $timelineCursor: String $commitCount: Int! $commitCursor: String + $commentCount: Int! + $commentCursor: String $reviewCount: Int $reviewCursor: String ) { @@ -234,32 +236,7 @@ fragment prReviewsContainer_pullRequest_2zzc96 on PullRequest { id } } - comments(first: 100) { - pageInfo { - hasNextPage - endCursor - } - nodes { - id - author { - __typename - avatarUrl - login - ... on Node { - id - } - } - body - bodyHTML - path - position - replyTo { - id - } - createdAt - url - } - } + ...prReviewCommentsContainer_review_1VbUmL __typename } } @@ -561,6 +538,40 @@ fragment prCommitView_item on Commit { url } +fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { + id + comments(first: $commentCount, after: $commentCursor) { + pageInfo { + hasNextPage + endCursor + } + edges { + cursor + node { + id + author { + __typename + avatarUrl + login + ... on Node { + id + } + } + body + bodyHTML + path + position + replyTo { + id + } + createdAt + url + __typename + } + } + } +} + fragment issueTimelineController_issue_3D8CP9 on Issue { url timeline(first: $timelineCount, after: $timelineCursor) { @@ -1152,9 +1163,15 @@ v38 = [ ], v39 = [ { - "kind": "Literal", + "kind": "Variable", + "name": "after", + "variableName": "commentCursor", + "type": "String" + }, + { + "kind": "Variable", "name": "first", - "value": 100, + "variableName": "commentCount", "type": "Int" } ], @@ -1197,7 +1214,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int\n $reviewCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_2zzc96\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $commentCount: Int!\n $commentCursor: String\n $reviewCount: Int\n $reviewCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_2zzc96\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1603,7 +1620,7 @@ return { "kind": "LinkedField", "alias": null, "name": "comments", - "storageKey": "comments(first:100)", + "storageKey": null, "args": v39, "concreteType": "PullRequestReviewCommentConnection", "plural": false, @@ -1612,36 +1629,58 @@ return { { "kind": "LinkedField", "alias": null, - "name": "nodes", + "name": "edges", "storageKey": null, "args": null, - "concreteType": "PullRequestReviewComment", + "concreteType": "PullRequestReviewCommentEdge", "plural": true, "selections": [ - v2, - v26, - v37, - v12, - v40, - v41, + v21, { "kind": "LinkedField", "alias": null, - "name": "replyTo", + "name": "node", "storageKey": null, "args": null, "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v2 + v2, + v26, + v37, + v12, + v40, + v41, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v2 + ] + }, + v27, + v14, + v4 ] - }, - v27, - v14 + } ] } ] }, + { + "kind": "LinkedHandle", + "alias": null, + "name": "comments", + "args": v39, + "handle": "connection", + "key": "PrReviewCommentsContainer_comments", + "filters": null + }, v4 ] } @@ -1844,7 +1883,14 @@ return { "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v39, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 100, + "type": "Int" + } + ], "concreteType": "CommitCommentConnection", "plural": false, "selections": [ diff --git a/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js new file mode 100644 index 0000000000..dc46be1e33 --- /dev/null +++ b/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js @@ -0,0 +1,375 @@ +/** + * @flow + * @relayHash 5658256f086fc990e6f8c58966b65c77 + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest } from 'relay-runtime'; +type prReviewCommentsContainer_review$ref = any; +export type prReviewCommentsContainerQueryVariables = {| + commentCount: number, + commentCursor?: ?string, + id: string, +|}; +export type prReviewCommentsContainerQueryResponse = {| + +node: ?{| + +$fragmentRefs: prReviewCommentsContainer_review$ref + |} +|}; +export type prReviewCommentsContainerQuery = {| + variables: prReviewCommentsContainerQueryVariables, + response: prReviewCommentsContainerQueryResponse, +|}; +*/ + + +/* +query prReviewCommentsContainerQuery( + $commentCount: Int! + $commentCursor: String + $id: ID! +) { + node(id: $id) { + __typename + ... on PullRequestReview { + ...prReviewCommentsContainer_review_1VbUmL + } + id + } +} + +fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { + id + comments(first: $commentCount, after: $commentCursor) { + pageInfo { + hasNextPage + endCursor + } + edges { + cursor + node { + id + author { + __typename + avatarUrl + login + ... on Node { + id + } + } + body + bodyHTML + path + position + replyTo { + id + } + createdAt + url + __typename + } + } + } +} +*/ + +const node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "LocalArgument", + "name": "commentCount", + "type": "Int!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCursor", + "type": "String", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "id", + "type": "ID!", + "defaultValue": null + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "id", + "type": "ID!" + } +], +v2 = { + "kind": "ScalarField", + "alias": null, + "name": "__typename", + "args": null, + "storageKey": null +}, +v3 = { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null +}, +v4 = [ + { + "kind": "Variable", + "name": "after", + "variableName": "commentCursor", + "type": "String" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "commentCount", + "type": "Int" + } +]; +return { + "kind": "Request", + "operationKind": "query", + "name": "prReviewCommentsContainerQuery", + "id": null, + "text": "query prReviewCommentsContainerQuery(\n $commentCount: Int!\n $commentCursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequestReview {\n ...prReviewCommentsContainer_review_1VbUmL\n }\n id\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "metadata": {}, + "fragment": { + "kind": "Fragment", + "name": "prReviewCommentsContainerQuery", + "type": "Query", + "metadata": null, + "argumentDefinitions": v0, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "node", + "storageKey": null, + "args": v1, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "InlineFragment", + "type": "PullRequestReview", + "selections": [ + { + "kind": "FragmentSpread", + "name": "prReviewCommentsContainer_review", + "args": [ + { + "kind": "Variable", + "name": "commentCount", + "variableName": "commentCount", + "type": null + }, + { + "kind": "Variable", + "name": "commentCursor", + "variableName": "commentCursor", + "type": null + } + ] + } + ] + } + ] + } + ] + }, + "operation": { + "kind": "Operation", + "name": "prReviewCommentsContainerQuery", + "argumentDefinitions": v0, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "node", + "storageKey": null, + "args": v1, + "concreteType": null, + "plural": false, + "selections": [ + v2, + v3, + { + "kind": "InlineFragment", + "type": "PullRequestReview", + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": null, + "args": v4, + "concreteType": "PullRequestReviewCommentConnection", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "pageInfo", + "storageKey": null, + "args": null, + "concreteType": "PageInfo", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "hasNextPage", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "endCursor", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "edges", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewCommentEdge", + "plural": true, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "cursor", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "node", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v3, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v2, + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + }, + v3 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "bodyHTML", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "path", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "position", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v3 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null + }, + v2 + ] + } + ] + } + ] + }, + { + "kind": "LinkedHandle", + "alias": null, + "name": "comments", + "args": v4, + "handle": "connection", + "key": "PrReviewCommentsContainer_comments", + "filters": null + } + ] + } + ] + } + ] + } +}; +})(); +// prettier-ignore +(node/*: any*/).hash = 'd48507a6296f84357e94000010c34713'; +module.exports = node; diff --git a/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js b/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js new file mode 100644 index 0000000000..5a674efbcc --- /dev/null +++ b/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js @@ -0,0 +1,242 @@ +/** + * @flow + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteFragment } from 'relay-runtime'; +import type { FragmentReference } from "relay-runtime"; +declare export opaque type prReviewCommentsContainer_review$ref: FragmentReference; +export type prReviewCommentsContainer_review = {| + +id: string, + +comments: {| + +pageInfo: {| + +hasNextPage: boolean, + +endCursor: ?string, + |}, + +edges: ?$ReadOnlyArray, + |}, + +$refType: prReviewCommentsContainer_review$ref, +|}; +*/ + + +const node/*: ConcreteFragment*/ = (function(){ +var v0 = { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null +}; +return { + "kind": "Fragment", + "name": "prReviewCommentsContainer_review", + "type": "PullRequestReview", + "metadata": { + "connection": [ + { + "count": "commentCount", + "cursor": "commentCursor", + "direction": "forward", + "path": [ + "comments" + ] + } + ] + }, + "argumentDefinitions": [ + { + "kind": "LocalArgument", + "name": "commentCount", + "type": "Int!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCursor", + "type": "String", + "defaultValue": null + } + ], + "selections": [ + v0, + { + "kind": "LinkedField", + "alias": "comments", + "name": "__PrReviewCommentsContainer_comments_connection", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewCommentConnection", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "pageInfo", + "storageKey": null, + "args": null, + "concreteType": "PageInfo", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "hasNextPage", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "endCursor", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "edges", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewCommentEdge", + "plural": true, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "cursor", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "node", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v0, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + } + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "bodyHTML", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "path", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "position", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v0 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "__typename", + "args": null, + "storageKey": null + } + ] + } + ] + } + ] + } + ] +}; +})(); +// prettier-ignore +(node/*: any*/).hash = 'd4b785b8fc4e5b4bedc5aa92491f37e7'; +module.exports = node; diff --git a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js index e6ee421cf3..aac991e4b6 100644 --- a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash c79a1d774a35cceb455839a0124e28fc + * @relayHash f0d1b6fd1bbccab16bb6901bb25f4120 */ /* eslint-disable */ @@ -76,32 +76,41 @@ fragment prReviewsContainer_pullRequest_2zzc96 on PullRequest { id } } - comments(first: 100) { - pageInfo { - hasNextPage - endCursor - } - nodes { + ...prReviewCommentsContainer_review_1VbUmL + __typename + } + } + } +} + +fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { + id + comments(first: $commentCount, after: $commentCursor) { + pageInfo { + hasNextPage + endCursor + } + edges { + cursor + node { + id + author { + __typename + avatarUrl + login + ... on Node { id - author { - __typename - avatarUrl - login - ... on Node { - id - } - } - body - bodyHTML - path - position - replyTo { - id - } - createdAt - url } } + body + bodyHTML + path + position + replyTo { + id + } + createdAt + url __typename } } @@ -201,30 +210,51 @@ v6 = { v7 = { "kind": "ScalarField", "alias": null, - "name": "body", + "name": "cursor", "args": null, "storageKey": null }, v8 = { "kind": "ScalarField", "alias": null, - "name": "login", + "name": "body", "args": null, "storageKey": null }, v9 = { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null +}, +v10 = { "kind": "ScalarField", "alias": null, "name": "avatarUrl", "args": null, "storageKey": null -}; +}, +v11 = [ + { + "kind": "Variable", + "name": "after", + "variableName": "commentCursor", + "type": "String" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "commentCount", + "type": "Int" + } +]; return { "kind": "Request", "operationKind": "query", "name": "prReviewsContainerQuery", "id": null, - "text": "query prReviewsContainerQuery(\n $reviewCount: Int\n $reviewCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_2zzc96\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n", + "text": "query prReviewsContainerQuery(\n $reviewCount: Int\n $reviewCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_2zzc96\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -310,13 +340,7 @@ return { "concreteType": "PullRequestReviewEdge", "plural": true, "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "cursor", - "args": null, - "storageKey": null - }, + v7, { "kind": "LinkedField", "alias": null, @@ -327,7 +351,7 @@ return { "plural": false, "selections": [ v3, - v7, + v8, { "kind": "LinkedField", "alias": "commitId", @@ -371,7 +395,7 @@ return { "plural": false, "selections": [ v2, - v8, + v9, v3 ] }, @@ -385,7 +409,7 @@ return { "plural": false, "selections": [ v2, - v9, + v10, v3 ] }, @@ -393,15 +417,8 @@ return { "kind": "LinkedField", "alias": null, "name": "comments", - "storageKey": "comments(first:100)", - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 100, - "type": "Int" - } - ], + "storageKey": null, + "args": v11, "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ @@ -409,74 +426,96 @@ return { { "kind": "LinkedField", "alias": null, - "name": "nodes", + "name": "edges", "storageKey": null, "args": null, - "concreteType": "PullRequestReviewComment", + "concreteType": "PullRequestReviewCommentEdge", "plural": true, "selections": [ - v3, - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v2, - v9, - v8, - v3 - ] - }, v7, - { - "kind": "ScalarField", - "alias": null, - "name": "bodyHTML", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "path", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "position", - "args": null, - "storageKey": null - }, { "kind": "LinkedField", "alias": null, - "name": "replyTo", + "name": "node", "storageKey": null, "args": null, "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v3 + v3, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + v2, + v10, + v9, + v3 + ] + }, + v8, + { + "kind": "ScalarField", + "alias": null, + "name": "bodyHTML", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "path", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "position", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v3 + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + v4, + v2 ] - }, - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - }, - v4 + } ] } ] }, + { + "kind": "LinkedHandle", + "alias": null, + "name": "comments", + "args": v11, + "handle": "connection", + "key": "PrReviewCommentsContainer_comments", + "filters": null + }, v2 ] } diff --git a/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js index cd27865199..5145f6f6ec 100644 --- a/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js +++ b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js @@ -8,6 +8,7 @@ /*:: import type { ConcreteFragment } from 'relay-runtime'; +type prReviewCommentsContainer_review$ref = any; export type PullRequestReviewState = "APPROVED" | "CHANGES_REQUESTED" | "COMMENTED" | "DISMISSED" | "PENDING" | "%future added value"; import type { FragmentReference } from "relay-runtime"; declare export opaque type prReviewsContainer_pullRequest$ref: FragmentReference; @@ -34,28 +35,7 @@ export type prReviewsContainer_pullRequest = {| +author: ?{| +avatarUrl: any |}, - +comments: {| - +pageInfo: {| - +hasNextPage: boolean, - +endCursor: ?string, - |}, - +nodes: ?$ReadOnlyArray, - |}, + +$fragmentRefs: prReviewCommentsContainer_review$ref, |}, |}>, |}, @@ -64,68 +44,7 @@ export type prReviewsContainer_pullRequest = {| */ -const node/*: ConcreteFragment*/ = (function(){ -var v0 = { - "kind": "ScalarField", - "alias": null, - "name": "url", - "args": null, - "storageKey": null -}, -v1 = { - "kind": "LinkedField", - "alias": null, - "name": "pageInfo", - "storageKey": null, - "args": null, - "concreteType": "PageInfo", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "hasNextPage", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "endCursor", - "args": null, - "storageKey": null - } - ] -}, -v2 = { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null -}, -v3 = { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null -}, -v4 = { - "kind": "ScalarField", - "alias": null, - "name": "login", - "args": null, - "storageKey": null -}, -v5 = { - "kind": "ScalarField", - "alias": null, - "name": "avatarUrl", - "args": null, - "storageKey": null -}; -return { +const node/*: ConcreteFragment*/ = { "kind": "Fragment", "name": "prReviewsContainer_pullRequest", "type": "PullRequest", @@ -153,10 +72,26 @@ return { "name": "reviewCursor", "type": "String", "defaultValue": null + }, + { + "kind": "RootArgument", + "name": "commentCount", + "type": null + }, + { + "kind": "RootArgument", + "name": "commentCursor", + "type": null } ], "selections": [ - v0, + { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null + }, { "kind": "LinkedField", "alias": "reviews", @@ -166,7 +101,31 @@ return { "concreteType": "PullRequestReviewConnection", "plural": false, "selections": [ - v1, + { + "kind": "LinkedField", + "alias": null, + "name": "pageInfo", + "storageKey": null, + "args": null, + "concreteType": "PageInfo", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "hasNextPage", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "endCursor", + "args": null, + "storageKey": null + } + ] + }, { "kind": "LinkedField", "alias": null, @@ -192,8 +151,20 @@ return { "concreteType": "PullRequestReview", "plural": false, "selections": [ - v2, - v3, + { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null + }, { "kind": "LinkedField", "alias": "commitId", @@ -235,7 +206,13 @@ return { "concreteType": null, "plural": false, "selections": [ - v4 + { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null + } ] }, { @@ -247,92 +224,30 @@ return { "concreteType": null, "plural": false, "selections": [ - v5 + { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null + } ] }, { - "kind": "LinkedField", - "alias": null, - "name": "comments", - "storageKey": "comments(first:100)", + "kind": "FragmentSpread", + "name": "prReviewCommentsContainer_review", "args": [ { - "kind": "Literal", - "name": "first", - "value": 100, - "type": "Int" - } - ], - "concreteType": "PullRequestReviewCommentConnection", - "plural": false, - "selections": [ - v1, + "kind": "Variable", + "name": "commentCount", + "variableName": "commentCount", + "type": null + }, { - "kind": "LinkedField", - "alias": null, - "name": "nodes", - "storageKey": null, - "args": null, - "concreteType": "PullRequestReviewComment", - "plural": true, - "selections": [ - v2, - { - "kind": "LinkedField", - "alias": null, - "name": "author", - "storageKey": null, - "args": null, - "concreteType": null, - "plural": false, - "selections": [ - v5, - v4 - ] - }, - v3, - { - "kind": "ScalarField", - "alias": null, - "name": "bodyHTML", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "path", - "args": null, - "storageKey": null - }, - { - "kind": "ScalarField", - "alias": null, - "name": "position", - "args": null, - "storageKey": null - }, - { - "kind": "LinkedField", - "alias": null, - "name": "replyTo", - "storageKey": null, - "args": null, - "concreteType": "PullRequestReviewComment", - "plural": false, - "selections": [ - v2 - ] - }, - { - "kind": "ScalarField", - "alias": null, - "name": "createdAt", - "args": null, - "storageKey": null - }, - v0 - ] + "kind": "Variable", + "name": "commentCursor", + "variableName": "commentCursor", + "type": null } ] }, @@ -351,7 +266,6 @@ return { } ] }; -})(); // prettier-ignore -(node/*: any*/).hash = 'd234d1f47b1a977b18174045b21cf0f0'; +(node/*: any*/).hash = '4d74fc25f4b854782495fc05521f961c'; module.exports = node; diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index ae23b3dca4..3caeb9f408 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -9,7 +9,7 @@ export default createPaginationContainer(PullRequestReviewCommentsView, { commentCount: {type: "Int!"}, commentCursor: {type: "String"} ) { - url + id comments( first: $commentCount, after: $commentCursor @@ -54,16 +54,19 @@ export default createPaginationContainer(PullRequestReviewCommentsView, { }, getVariables(props, {count, cursor}, fragmentVariables) { return { - url: props.review.url, + id: props.review.id, commentCount: count, commentCursor: cursor, }; }, query: graphql` - query prReviewCommentsContainerQuery($commentCount: Int, $commentCursor: String, $url: URI!) { - resource(url: $url) { + query prReviewCommentsContainerQuery($commentCount: Int!, $commentCursor: String, $id: ID!) { + node(id: $id) { ... on PullRequestReview { - ...prReviewCommentsContainer_review @arguments(commentCount: $commentCount, commentCursor: $commentCursor) + ...prReviewCommentsContainer_review @arguments( + commentCount: $commentCount, + commentCursor: $commentCursor + ) } } } diff --git a/lib/containers/pr-reviews-container.js b/lib/containers/pr-reviews-container.js index d57cd3a553..8de768a770 100644 --- a/lib/containers/pr-reviews-container.js +++ b/lib/containers/pr-reviews-container.js @@ -1,6 +1,6 @@ import {graphql, createPaginationContainer} from 'react-relay'; -import PullRequestReviewsController from '../controller/pr-reviews-controller'; +import PullRequestReviewsController from '../controllers/pr-reviews-controller'; export default createPaginationContainer(PullRequestReviewsController, { pullRequest: graphql` diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index a5b20a3882..e744234186 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -55,6 +55,13 @@ export default class PullRequestReviewsController extends React.Component { return null; } - return ; + return this.props.pullRequest.reviews.forEach.map(({node}) => { + const review = node; + const reviewProp = this.props.reviews.find(r => r.id === review.id) + reviewProp.comments = review.comments; + return ( + + ); + }); } } diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index fe380438d1..15337e8fdb 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 8b5005b08f8393c1b2d22577e9530360 + * @relayHash e23a0a2054c2cff16dfe71a64cf4fe9f */ /* eslint-disable */ @@ -46,6 +46,8 @@ query prDetailViewRefetchQuery( $timelineCursor: String $commitCount: Int! $commitCursor: String + $commentCount: Int! + $commentCursor: String $reviewCount: Int $reviewCursor: String ) { @@ -150,32 +152,7 @@ fragment prReviewsContainer_pullRequest_2zzc96 on PullRequest { id } } - comments(first: 100) { - pageInfo { - hasNextPage - endCursor - } - nodes { - id - author { - __typename - avatarUrl - login - ... on Node { - id - } - } - body - bodyHTML - path - position - replyTo { - id - } - createdAt - url - } - } + ...prReviewCommentsContainer_review_1VbUmL __typename } } @@ -476,6 +453,40 @@ fragment prCommitView_item on Commit { sha: oid url } + +fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { + id + comments(first: $commentCount, after: $commentCursor) { + pageInfo { + hasNextPage + endCursor + } + edges { + cursor + node { + id + author { + __typename + avatarUrl + login + ... on Node { + id + } + } + body + bodyHTML + path + position + replyTo { + id + } + createdAt + url + __typename + } + } + } +} */ const node/*: ConcreteRequest*/ = (function(){ @@ -714,9 +725,15 @@ v22 = { }, v23 = [ { - "kind": "Literal", + "kind": "Variable", + "name": "after", + "variableName": "commentCursor", + "type": "String" + }, + { + "kind": "Variable", "name": "first", - "value": 100, + "variableName": "commentCount", "type": "Int" } ], @@ -875,7 +892,7 @@ return { "operationKind": "query", "name": "prDetailViewRefetchQuery", "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int\n $reviewCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_2zzc96\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n comments(first: 100) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n }\n }\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $commentCount: Int!\n $commentCursor: String\n $reviewCount: Int\n $reviewCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_2zzc96\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1089,7 +1106,7 @@ return { "kind": "LinkedField", "alias": null, "name": "comments", - "storageKey": "comments(first:100)", + "storageKey": null, "args": v23, "concreteType": "PullRequestReviewCommentConnection", "plural": false, @@ -1098,36 +1115,58 @@ return { { "kind": "LinkedField", "alias": null, - "name": "nodes", + "name": "edges", "storageKey": null, "args": null, - "concreteType": "PullRequestReviewComment", + "concreteType": "PullRequestReviewCommentEdge", "plural": true, "selections": [ - v6, - v25, - v19, - v26, - v27, - v28, + v18, { "kind": "LinkedField", "alias": null, - "name": "replyTo", + "name": "node", "storageKey": null, "args": null, "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v6 + v6, + v25, + v19, + v26, + v27, + v28, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + v6 + ] + }, + v29, + v13, + v5 ] - }, - v29, - v13 + } ] } ] }, + { + "kind": "LinkedHandle", + "alias": null, + "name": "comments", + "args": v23, + "handle": "connection", + "key": "PrReviewCommentsContainer_comments", + "filters": null + }, v5 ] } @@ -1551,7 +1590,14 @@ return { "alias": null, "name": "comments", "storageKey": "comments(first:100)", - "args": v23, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 100, + "type": "Int" + } + ], "concreteType": "CommitCommentConnection", "plural": false, "selections": [ diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-comments-view.js index c0755edce2..a63f517a2c 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-comments-view.js @@ -27,7 +27,6 @@ export default class PullRequestCommentsView extends React.Component { } componentDidMount() { - console.log('DID MOUNT'); this._attemptToLoadMoreReviews(); } @@ -58,6 +57,7 @@ export default class PullRequestCommentsView extends React.Component { } render() { + console.log('!!!! props', this.props) if (!this.props.pullRequest || !this.props.pullRequest.reviews) { return null; } @@ -66,7 +66,12 @@ export default class PullRequestCommentsView extends React.Component { this.props.pullRequest.reviews.edges.forEach(({node}) => { const review = node; - review.comments.nodes.forEach(comment => { + if (!review.comments) { + return null; + } + review.comments.edges.forEach(({node}) => { + const comment = node; + console.log('comment!!!', comment); if (!comment.replyTo) { commentsByRootCommentId.set(comment.id, [comment]); } else { From 657c7a68212a7db8a09b46f32c6d56b7972f9952 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 28 Dec 2018 15:32:41 -0800 Subject: [PATCH 2432/4847] Get comments rendering again! Woohoo Co-Authored-By: Tilde Ann Thurium --- .../pr-review-comments-container.js | 58 +++++++++++++- lib/controllers/pr-reviews-controller.js | 67 ++++++++++++++-- ...nts-view.js => pr-review-comments-view.js} | 76 ++----------------- 3 files changed, 121 insertions(+), 80 deletions(-) rename lib/views/{pr-comments-view.js => pr-review-comments-view.js} (56%) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 3caeb9f408..723d9b352e 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -1,8 +1,62 @@ import {graphql, createPaginationContainer} from 'react-relay'; +import React from 'react'; -import PullRequestReviewCommentsView from '../views/pr-comments-view'; +export class ReviewCommentsController extends React.Component { + // static getDerivedStateFromProps(nextProps, prevState) { + // console.log('getDerivedStateFromProps'); + // if (nextProps !== prevState.props) { + // nextProps.aggregateComments(nextProps.review.id, nextProps.review.comments); + // } + // return { + // props: nextProps, + // }; + // } -export default createPaginationContainer(PullRequestReviewCommentsView, { + constructor(props) { + super(props); + console.log('pr-review-container-constructor'); + } + + componentDidMount() { + this.props.aggregateComments(this.props.review.id, this.props.review.comments); + console.log('comments!!!', this.props.review.comments); + this._attemptToLoadMoreComments(); + } + + _loadMoreComments = () => { + this.props.relay.loadMore( + 100, + error => { + this.props.aggregateComments(this.props.review.id, this.props.review.comments); + console.log('comments!!!', this.props.review.comments); + this._attemptToLoadMoreComments(); + if (error) { + console.log(error); + } + }, + ); + } + + _attemptToLoadMoreComments = () => { + if (!this.props.relay.hasMore()) { + return; + } + + if (this.props.relay.isLoading()) { + setTimeout(() => { + this._loadMoreComments(); + }, 300); + } else { + this._loadMoreComments(); + } + } + + render() { + return null; + } +} + +export default createPaginationContainer(ReviewCommentsController, { review: graphql` fragment prReviewCommentsContainer_review on PullRequestReview @argumentDefinitions( diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index e744234186..79b3c32fb7 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {RelayConnectionPropType} from '../prop-types'; import PullRequestReviewCommentsContainer from '../containers/pr-review-comments-container'; - +import PullRequestReviewCommentsView from '../views/pr-review-comments-view'; export default class PullRequestReviewsController extends React.Component { static propTypes = { @@ -20,6 +20,11 @@ export default class PullRequestReviewsController extends React.Component { multiFilePatch: PropTypes.object.isRequired, } + constructor(props) { + super(props); + this.state = {}; + } + componentDidMount() { this._attemptToLoadMoreReviews(); } @@ -50,18 +55,64 @@ export default class PullRequestReviewsController extends React.Component { } } + aggregateComments = (reviewId, comments) => { + const state = this.state; + comments.edges.forEach(({node}) => { + const comment = node; + if (!comment.replyTo) { + state[comment.id] = [comment]; + // this.setState({[comment.id]: [comment]}); + } else { + // When comment being replied to is outdated...?? Not 100% sure... + // Why would we even get an outdated comment or a response to one here? + // Ran into this error when viewing files for https://github.com/numpy/numpy/pull/9998 + // for comment MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE1MzA1NTUzMw, + // who's replyTo comment is an outdated comment + if (!state[comment.replyTo.id]) { + state[comment.id] = [comment]; + // this.setState({[comment.id]: [comment]}); + } else { + state[comment.replyTo.id].push(comment); + } + } + }); + this.setState(state); + } + + renderReviewCommentContainers() { + // Aggregate comments from all reviews + return this.props.pullRequest.reviews.edges.map(({node}) => { + const review = node; + console.log('!!!! review in PrReviewsController', review); + return ( + + ); + }); + } + render() { + console.log('PrReviewsController', this.props.pullRequest); + if (!this.props.pullRequest || !this.props.pullRequest.reviews) { return null; } - return this.props.pullRequest.reviews.forEach.map(({node}) => { - const review = node; - const reviewProp = this.props.reviews.find(r => r.id === review.id) - reviewProp.comments = review.comments; - return ( - - ); + const commentThreads = Object.keys(this.state).map(rootCommentId => { + return { + rootCommentId, + comments: this.state[rootCommentId], + }; }); + + return ( +
    + {this.renderReviewCommentContainers()} + +
    + ); } } diff --git a/lib/views/pr-comments-view.js b/lib/views/pr-review-comments-view.js similarity index 56% rename from lib/views/pr-comments-view.js rename to lib/views/pr-review-comments-view.js index a63f517a2c..a7434538bb 100644 --- a/lib/views/pr-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -18,80 +18,16 @@ export default class PullRequestCommentsView extends React.Component { loadMore: PropTypes.func.isRequired, isLoading: PropTypes.func.isRequired, }).isRequired, - pullRequest: PropTypes.shape({ - reviews: RelayConnectionPropType( - PropTypes.object, - ), - }), + commentThreads: PropTypes.arrayOf(PropTypes.shape({ + rootCommentId: PropTypes.number.isRequired, + comments: PropTypes.arrayOf(PropTypes.object).isRequired, + })), multiFilePatch: PropTypes.object.isRequired, } - componentDidMount() { - this._attemptToLoadMoreReviews(); - } - - _loadMoreReviews = () => { - this.props.relay.loadMore( - 100, - error => { - this._attemptToLoadMoreReviews(); - if (error) { - console.log(error); - } - }, - ); - } - - _attemptToLoadMoreReviews = () => { - if (!this.props.relay.hasMore()) { - return; - } - - if (this.props.relay.isLoading()) { - setTimeout(() => { - this._loadMoreReviews(); - }, 300); - } else { - this._loadMoreReviews(); - } - } - render() { - console.log('!!!! props', this.props) - if (!this.props.pullRequest || !this.props.pullRequest.reviews) { - return null; - } - - const commentsByRootCommentId = new Map(); - - this.props.pullRequest.reviews.edges.forEach(({node}) => { - const review = node; - if (!review.comments) { - return null; - } - review.comments.edges.forEach(({node}) => { - const comment = node; - console.log('comment!!!', comment); - if (!comment.replyTo) { - commentsByRootCommentId.set(comment.id, [comment]); - } else { - // When comment being replied to is outdated...?? Not 100% sure... - // Why would we even get an outdated comment or a response to one here? - // Ran into this error when viewing files for https://github.com/numpy/numpy/pull/9998 - // for comment MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE1MzA1NTUzMw, - // who's replyTo comment is an outdated comment - if (!commentsByRootCommentId.get(comment.replyTo.id)) { - commentsByRootCommentId.set(comment.replyTo.id, [comment]); - } else { - commentsByRootCommentId.get(comment.replyTo.id).push(comment); - } - } - }); - }); - - console.log('SIZE', commentsByRootCommentId.size, [...commentsByRootCommentId]); - - return [...commentsByRootCommentId].reverse().map(([rootCommentId, comments]) => { + console.log('!!!! comment threads', this.props.commentThreads); + return [...this.props.commentThreads].reverse().map(({rootCommentId, comments}) => { const rootComment = comments[0]; if (!rootComment.position) { return null; From 2de958fc19433527607d7826529a360ac5c02ead Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 28 Dec 2018 15:58:53 -0800 Subject: [PATCH 2433/4847] Thread commentCount and commentCursor through component hierarchy Co-Authored-By: Tilde Ann Thurium --- .../issueishDetailContainerQuery.graphql.js | 28 ++++++------ .../prReviewsContainerQuery.graphql.js | 44 +++++++++++++++---- .../prReviewsContainer_pullRequest.graphql.js | 14 +++--- lib/containers/issueish-detail-container.js | 14 +++--- .../pr-review-comments-container.js | 18 +------- lib/containers/pr-reviews-container.js | 25 +++++++++-- ...eishDetailController_repository.graphql.js | 10 ++--- lib/controllers/issueish-detail-controller.js | 8 ++-- lib/controllers/pr-reviews-controller.js | 4 +- .../prDetailViewRefetchQuery.graphql.js | 28 ++++++------ .../prDetailView_pullRequest.graphql.js | 24 +++++++--- lib/views/pr-detail-view.js | 23 ++++++---- lib/views/pr-review-comments-view.js | 1 - 13 files changed, 144 insertions(+), 97 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 85536bb239..5158fd1965 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 2272e39d4e33d96fe66954cf4a808caa + * @relayHash 89eb63ec03a0c0f750b90f024809ee03 */ /* eslint-disable */ @@ -18,10 +18,10 @@ export type issueishDetailContainerQueryVariables = {| timelineCursor?: ?string, commitCount: number, commitCursor?: ?string, + reviewCount: number, + reviewCursor?: ?string, commentCount: number, commentCursor?: ?string, - reviewCount?: ?number, - reviewCursor?: ?string, |}; export type issueishDetailContainerQueryResponse = {| +repository: ?{| @@ -44,10 +44,10 @@ query issueishDetailContainerQuery( $timelineCursor: String $commitCount: Int! $commitCursor: String + $reviewCount: Int! + $reviewCursor: String $commentCount: Int! $commentCursor: String - $reviewCount: Int - $reviewCursor: String ) { repository(owner: $repoOwner, name: $repoName) { ...issueishDetailController_repository_y3nHF @@ -164,7 +164,7 @@ fragment prDetailView_pullRequest_2qM2KL on PullRequest { } isCrossRepository changedFiles - ...prReviewsContainer_pullRequest_2zzc96 + ...prReviewsContainer_pullRequest_y4qc0 ...prCommitsView_pullRequest_38TpXw countedCommits: commits { totalCount @@ -204,7 +204,7 @@ fragment prDetailView_pullRequest_2qM2KL on PullRequest { } } -fragment prReviewsContainer_pullRequest_2zzc96 on PullRequest { +fragment prReviewsContainer_pullRequest_y4qc0 on PullRequest { url reviews(first: $reviewCount, after: $reviewCursor) { pageInfo { @@ -641,25 +641,25 @@ var v0 = [ }, { "kind": "LocalArgument", - "name": "commentCount", + "name": "reviewCount", "type": "Int!", "defaultValue": null }, { "kind": "LocalArgument", - "name": "commentCursor", + "name": "reviewCursor", "type": "String", "defaultValue": null }, { "kind": "LocalArgument", - "name": "reviewCount", - "type": "Int", + "name": "commentCount", + "type": "Int!", "defaultValue": null }, { "kind": "LocalArgument", - "name": "reviewCursor", + "name": "commentCursor", "type": "String", "defaultValue": null } @@ -1214,7 +1214,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $commentCount: Int!\n $commentCursor: String\n $reviewCount: Int\n $reviewCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_2zzc96\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -2009,5 +2009,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'e4903c4025a67651b3086652adb8aa06'; +(node/*: any*/).hash = '6a16db513a3cd8bf14fafb3c8b269643'; module.exports = node; diff --git a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js index aac991e4b6..edf519cbfc 100644 --- a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash f0d1b6fd1bbccab16bb6901bb25f4120 + * @relayHash 4118118a2d92572dc108cf48c14c067f */ /* eslint-disable */ @@ -11,8 +11,10 @@ import type { ConcreteRequest } from 'relay-runtime'; type prReviewsContainer_pullRequest$ref = any; export type prReviewsContainerQueryVariables = {| - reviewCount?: ?number, + reviewCount: number, reviewCursor?: ?string, + commentCount: number, + commentCursor?: ?string, url: any, |}; export type prReviewsContainerQueryResponse = {| @@ -29,14 +31,16 @@ export type prReviewsContainerQuery = {| /* query prReviewsContainerQuery( - $reviewCount: Int + $reviewCount: Int! $reviewCursor: String + $commentCount: Int! + $commentCursor: String $url: URI! ) { resource(url: $url) { __typename ... on PullRequest { - ...prReviewsContainer_pullRequest_2zzc96 + ...prReviewsContainer_pullRequest_y4qc0 } ... on Node { id @@ -44,7 +48,7 @@ query prReviewsContainerQuery( } } -fragment prReviewsContainer_pullRequest_2zzc96 on PullRequest { +fragment prReviewsContainer_pullRequest_y4qc0 on PullRequest { url reviews(first: $reviewCount, after: $reviewCursor) { pageInfo { @@ -123,7 +127,7 @@ var v0 = [ { "kind": "LocalArgument", "name": "reviewCount", - "type": "Int", + "type": "Int!", "defaultValue": null }, { @@ -132,6 +136,18 @@ var v0 = [ "type": "String", "defaultValue": null }, + { + "kind": "LocalArgument", + "name": "commentCount", + "type": "Int!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCursor", + "type": "String", + "defaultValue": null + }, { "kind": "LocalArgument", "name": "url", @@ -254,7 +270,7 @@ return { "operationKind": "query", "name": "prReviewsContainerQuery", "id": null, - "text": "query prReviewsContainerQuery(\n $reviewCount: Int\n $reviewCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_2zzc96\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_2zzc96 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "text": "query prReviewsContainerQuery(\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_y4qc0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -280,6 +296,18 @@ return { "kind": "FragmentSpread", "name": "prReviewsContainer_pullRequest", "args": [ + { + "kind": "Variable", + "name": "commentCount", + "variableName": "commentCount", + "type": null + }, + { + "kind": "Variable", + "name": "commentCursor", + "variableName": "commentCursor", + "type": null + }, { "kind": "Variable", "name": "reviewCount", @@ -541,5 +569,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '29e5b225e2d3999e4cd475edc354015d'; +(node/*: any*/).hash = 'a84a1ddfd0a7a0667a57d94d5db110cf'; module.exports = node; diff --git a/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js index 5145f6f6ec..04d2100cf7 100644 --- a/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js +++ b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js @@ -64,7 +64,7 @@ const node/*: ConcreteFragment*/ = { { "kind": "LocalArgument", "name": "reviewCount", - "type": "Int", + "type": "Int!", "defaultValue": null }, { @@ -74,14 +74,16 @@ const node/*: ConcreteFragment*/ = { "defaultValue": null }, { - "kind": "RootArgument", + "kind": "LocalArgument", "name": "commentCount", - "type": null + "type": "Int!", + "defaultValue": null }, { - "kind": "RootArgument", + "kind": "LocalArgument", "name": "commentCursor", - "type": null + "type": "String", + "defaultValue": null } ], "selections": [ @@ -267,5 +269,5 @@ const node/*: ConcreteFragment*/ = { ] }; // prettier-ignore -(node/*: any*/).hash = '4d74fc25f4b854782495fc05521f961c'; +(node/*: any*/).hash = 'e5d1cfb5428af5817e22a53694345419'; module.exports = node; diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index ee83411112..fc326181ce 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -122,10 +122,10 @@ export default class IssueishDetailContainer extends React.Component { $timelineCursor: String $commitCount: Int! $commitCursor: String, + $reviewCount: Int!, + $reviewCursor: String, $commentCount: Int!, $commentCursor: String, - $reviewCount: Int, - $reviewCursor: String, ) { repository(owner: $repoOwner, name: $repoName) { ...issueishDetailController_repository @arguments( @@ -134,10 +134,10 @@ export default class IssueishDetailContainer extends React.Component { timelineCursor: $timelineCursor, commitCount: $commitCount, commitCursor: $commitCursor, - commentCount: $commentCount, - commentCursor: $commentCursor, reviewCount: $reviewCount, reviewCursor: $reviewCursor, + commentCount: $commentCount, + commentCursor: $commentCursor, ) } } @@ -150,10 +150,10 @@ export default class IssueishDetailContainer extends React.Component { timelineCursor: null, commitCount: 100, commitCursor: null, - commentCount: 100, - commentCursor: null, - reviewCount: 100, + reviewCount: 2, reviewCursor: null, + commentCount: 2, + commentCursor: null, }; return ( diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 723d9b352e..175ace49a0 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -2,24 +2,9 @@ import {graphql, createPaginationContainer} from 'react-relay'; import React from 'react'; export class ReviewCommentsController extends React.Component { - // static getDerivedStateFromProps(nextProps, prevState) { - // console.log('getDerivedStateFromProps'); - // if (nextProps !== prevState.props) { - // nextProps.aggregateComments(nextProps.review.id, nextProps.review.comments); - // } - // return { - // props: nextProps, - // }; - // } - - constructor(props) { - super(props); - console.log('pr-review-container-constructor'); - } componentDidMount() { this.props.aggregateComments(this.props.review.id, this.props.review.comments); - console.log('comments!!!', this.props.review.comments); this._attemptToLoadMoreComments(); } @@ -27,8 +12,7 @@ export class ReviewCommentsController extends React.Component { this.props.relay.loadMore( 100, error => { - this.props.aggregateComments(this.props.review.id, this.props.review.comments); - console.log('comments!!!', this.props.review.comments); + console.log('loaded more comments!', this.props.review.comments.edges); this._attemptToLoadMoreComments(); if (error) { console.log(error); diff --git a/lib/containers/pr-reviews-container.js b/lib/containers/pr-reviews-container.js index 8de768a770..a07dad5251 100644 --- a/lib/containers/pr-reviews-container.js +++ b/lib/containers/pr-reviews-container.js @@ -6,8 +6,10 @@ export default createPaginationContainer(PullRequestReviewsController, { pullRequest: graphql` fragment prReviewsContainer_pullRequest on PullRequest @argumentDefinitions( - reviewCount: {type: "Int"}, - reviewCursor: {type: "String"} + reviewCount: {type: "Int!"}, + reviewCursor: {type: "String"}, + commentCount: {type: "Int!"}, + commentCursor: {type: "String"} ) { url reviews( @@ -56,17 +58,32 @@ export default createPaginationContainer(PullRequestReviewsController, { }; }, getVariables(props, {count, cursor}, fragmentVariables) { + // console.log('fragmentVariables -------------->', fragmentVariables); + // console.log(arguments); return { url: props.pullRequest.url, reviewCount: count, reviewCursor: cursor, + commentCount: fragmentVariables.commentCount, + commentCursor: fragmentVariables.commentCursor, }; }, query: graphql` - query prReviewsContainerQuery($reviewCount: Int, $reviewCursor: String, $url: URI!) { + query prReviewsContainerQuery( + $reviewCount: Int!, + $reviewCursor: String, + $commentCount: Int!, + $commentCursor: String, + $url: URI! + ) { resource(url: $url) { ... on PullRequest { - ...prReviewsContainer_pullRequest @arguments(reviewCount: $reviewCount, reviewCursor: $reviewCursor) + ...prReviewsContainer_pullRequest @arguments( + reviewCount: $reviewCount, + reviewCursor: $reviewCursor, + commentCount: $commentCount, + commentCursor: $commentCursor + ) } } } diff --git a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js index 3c9b629202..12a4a5d6e8 100644 --- a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js +++ b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js @@ -171,25 +171,25 @@ return { }, { "kind": "LocalArgument", - "name": "commentCount", + "name": "reviewCount", "type": "Int!", "defaultValue": null }, { "kind": "LocalArgument", - "name": "commentCursor", + "name": "reviewCursor", "type": "String", "defaultValue": null }, { "kind": "LocalArgument", - "name": "reviewCount", + "name": "commentCount", "type": "Int!", "defaultValue": null }, { "kind": "LocalArgument", - "name": "reviewCursor", + "name": "commentCursor", "type": "String", "defaultValue": null } @@ -329,5 +329,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'f24ee4210befb63664396cf05d2afa79'; +(node/*: any*/).hash = 'e348cf91ee76425342abf4aa3c60b143'; module.exports = node; diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index 75ef71c32d..697a1f0e96 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -297,10 +297,10 @@ export default createFragmentContainer(BareIssueishDetailController, { timelineCursor: {type: "String"}, commitCount: {type: "Int!"}, commitCursor: {type: "String"}, - commentCount: {type: "Int!"}, - commentCursor: {type: "String"}, reviewCount: {type: "Int!"}, reviewCursor: {type: "String"}, + commentCount: {type: "Int!"}, + commentCursor: {type: "String"}, ) { ...issueDetailView_repository ...prDetailView_repository @@ -340,10 +340,10 @@ export default createFragmentContainer(BareIssueishDetailController, { timelineCursor: $timelineCursor, commitCount: $commitCount, commitCursor: $commitCursor, - commentCount: $commentCount, - commentCursor: $commentCursor, reviewCount: $reviewCount, reviewCursor: $reviewCursor, + commentCount: $commentCount, + commentCursor: $commentCursor, ) } } diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 79b3c32fb7..3e3ee359de 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -34,6 +34,7 @@ export default class PullRequestReviewsController extends React.Component { 100, error => { this._attemptToLoadMoreReviews(); + console.log('loaded more reviews!', this.props.pullRequest.reviews.edges); if (error) { console.log(error); } @@ -83,7 +84,6 @@ export default class PullRequestReviewsController extends React.Component { // Aggregate comments from all reviews return this.props.pullRequest.reviews.edges.map(({node}) => { const review = node; - console.log('!!!! review in PrReviewsController', review); return ( { this.setState({refreshing: false}); }, {force: true}); @@ -378,10 +380,10 @@ export default createRefetchContainer(BarePullRequestDetailView, { timelineCursor: {type: "String"}, commitCount: {type: "Int!"}, commitCursor: {type: "String"}, + reviewCount: {type: "Int!"}, + reviewCursor: {type: "String"}, commentCount: {type: "Int!"}, commentCursor: {type: "String"}, - reviewCount: {type: "Int"}, - reviewCursor: {type: "String"} ) { __typename @@ -393,7 +395,12 @@ export default createRefetchContainer(BarePullRequestDetailView, { isCrossRepository changedFiles - ...prReviewsContainer_pullRequest @arguments(reviewCount: $reviewCount, reviewCursor: $reviewCursor) + ...prReviewsContainer_pullRequest @arguments( + reviewCount: $reviewCount, + reviewCursor: $reviewCursor, + commentCount: $commentCount, + commentCursor: $commentCursor, + ) ...prCommitsView_pullRequest @arguments(commitCount: $commitCount, commitCursor: $commitCursor) countedCommits: commits { @@ -428,10 +435,10 @@ export default createRefetchContainer(BarePullRequestDetailView, { $timelineCursor: String, $commitCount: Int!, $commitCursor: String, + $reviewCount: Int!, + $reviewCursor: String, $commentCount: Int!, $commentCursor: String, - $reviewCount: Int, - $reviewCursor: String ) { repository:node(id: $repoId) { ...prDetailView_repository @arguments( @@ -446,10 +453,10 @@ export default createRefetchContainer(BarePullRequestDetailView, { timelineCursor: $timelineCursor, commitCount: $commitCount, commitCursor: $commitCursor, + reviewCount: $reviewCount, + reviewCursor: $reviewCursor, commentCount: $commentCount, commentCursor: $commentCursor, - reviewCount: $reviewCount, - reviewCursor: $reviewCursor ) } } diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index a7434538bb..abf70c729e 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -43,7 +43,6 @@ export default class PullRequestCommentsView extends React.Component { {comments.map(comment => { - console.log(comment.body); return ( Date: Fri, 28 Dec 2018 15:59:30 -0800 Subject: [PATCH 2434/4847] Fix proptype error Co-Authored-By: Tilde Ann Thurium --- lib/views/pr-review-comments-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index abf70c729e..1247585ee0 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -19,7 +19,7 @@ export default class PullRequestCommentsView extends React.Component { isLoading: PropTypes.func.isRequired, }).isRequired, commentThreads: PropTypes.arrayOf(PropTypes.shape({ - rootCommentId: PropTypes.number.isRequired, + rootCommentId: PropTypes.string.isRequired, comments: PropTypes.arrayOf(PropTypes.object).isRequired, })), multiFilePatch: PropTypes.object.isRequired, From 4fc8e7da2274a4cf7c4cb1684672bf8d25bf551e Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 28 Dec 2018 16:23:19 -0800 Subject: [PATCH 2435/4847] Add PAGE_SIZE const to helper file Co-Authored-By: Tilde Ann Thurium --- lib/containers/issueish-detail-container.js | 10 +++++----- lib/containers/pr-review-comments-container.js | 4 +++- lib/controllers/pr-reviews-controller.js | 3 ++- lib/helpers.js | 1 + lib/views/pr-commits-view.js | 4 +--- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/containers/issueish-detail-container.js b/lib/containers/issueish-detail-container.js index fc326181ce..7cd560d3fb 100644 --- a/lib/containers/issueish-detail-container.js +++ b/lib/containers/issueish-detail-container.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import yubikiri from 'yubikiri'; import {QueryRenderer, graphql} from 'react-relay'; -import {autobind} from '../helpers'; +import {autobind, PAGE_SIZE} from '../helpers'; import RelayNetworkLayerManager from '../relay-network-layer-manager'; import {GithubLoginModelPropType, ItemTypePropType, EndpointPropType} from '../prop-types'; import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; @@ -146,13 +146,13 @@ export default class IssueishDetailContainer extends React.Component { repoOwner: this.props.owner, repoName: this.props.repo, issueishNumber: this.props.issueishNumber, - timelineCount: 100, + timelineCount: PAGE_SIZE, timelineCursor: null, - commitCount: 100, + commitCount: PAGE_SIZE, commitCursor: null, - reviewCount: 2, + reviewCount: PAGE_SIZE, reviewCursor: null, - commentCount: 2, + commentCount: PAGE_SIZE, commentCursor: null, }; diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 175ace49a0..c55576b955 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -1,6 +1,8 @@ import {graphql, createPaginationContainer} from 'react-relay'; import React from 'react'; +import {PAGE_SIZE} from '../helpers'; + export class ReviewCommentsController extends React.Component { componentDidMount() { @@ -10,7 +12,7 @@ export class ReviewCommentsController extends React.Component { _loadMoreComments = () => { this.props.relay.loadMore( - 100, + PAGE_SIZE, error => { console.log('loaded more comments!', this.props.review.comments.edges); this._attemptToLoadMoreComments(); diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 3e3ee359de..86b33bb965 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -4,6 +4,7 @@ import {RelayConnectionPropType} from '../prop-types'; import PullRequestReviewCommentsContainer from '../containers/pr-review-comments-container'; import PullRequestReviewCommentsView from '../views/pr-review-comments-view'; +import {PAGE_SIZE} from '../helpers'; export default class PullRequestReviewsController extends React.Component { static propTypes = { @@ -31,7 +32,7 @@ export default class PullRequestReviewsController extends React.Component { _loadMoreReviews = () => { this.props.relay.loadMore( - 100, + PAGE_SIZE, error => { this._attemptToLoadMoreReviews(); console.log('loaded more reviews!', this.props.pullRequest.reviews.edges); diff --git a/lib/helpers.js b/lib/helpers.js index 74a77f9460..c45375b232 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -8,6 +8,7 @@ import RefHolder from './models/ref-holder'; export const LINE_ENDING_REGEX = /\r?\n/; export const CO_AUTHOR_REGEX = /^co-authored-by. (.+?) <(.+?)>$/i; +export const PAGE_SIZE = 50; export function autobind(self, ...methods) { for (const method of methods) { diff --git a/lib/views/pr-commits-view.js b/lib/views/pr-commits-view.js index 5398c58ad1..0ae3e6a76d 100644 --- a/lib/views/pr-commits-view.js +++ b/lib/views/pr-commits-view.js @@ -4,9 +4,7 @@ import {graphql, createPaginationContainer} from 'react-relay'; import {RelayConnectionPropType} from '../prop-types'; import PrCommitView from './pr-commit-view'; -import {autobind} from '../helpers'; - -const PAGE_SIZE = 50; +import {autobind, PAGE_SIZE} from '../helpers'; export class PrCommitsView extends React.Component { static propTypes = { From d215b328c0e0420b7015a0cea4dea65b99ffeded Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 28 Dec 2018 16:23:40 -0800 Subject: [PATCH 2436/4847] Clean up logs Co-Authored-By: Tilde Ann Thurium --- lib/containers/pr-review-comments-container.js | 1 - lib/containers/pr-reviews-container.js | 2 -- lib/controllers/pr-reviews-controller.js | 1 - lib/views/pr-review-comments-view.js | 1 - 4 files changed, 5 deletions(-) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index c55576b955..031ae77653 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -14,7 +14,6 @@ export class ReviewCommentsController extends React.Component { this.props.relay.loadMore( PAGE_SIZE, error => { - console.log('loaded more comments!', this.props.review.comments.edges); this._attemptToLoadMoreComments(); if (error) { console.log(error); diff --git a/lib/containers/pr-reviews-container.js b/lib/containers/pr-reviews-container.js index a07dad5251..b0bc33a95b 100644 --- a/lib/containers/pr-reviews-container.js +++ b/lib/containers/pr-reviews-container.js @@ -58,8 +58,6 @@ export default createPaginationContainer(PullRequestReviewsController, { }; }, getVariables(props, {count, cursor}, fragmentVariables) { - // console.log('fragmentVariables -------------->', fragmentVariables); - // console.log(arguments); return { url: props.pullRequest.url, reviewCount: count, diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 86b33bb965..1e1d8c2f11 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -35,7 +35,6 @@ export default class PullRequestReviewsController extends React.Component { PAGE_SIZE, error => { this._attemptToLoadMoreReviews(); - console.log('loaded more reviews!', this.props.pullRequest.reviews.edges); if (error) { console.log(error); } diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index 1247585ee0..286615ab76 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -26,7 +26,6 @@ export default class PullRequestCommentsView extends React.Component { } render() { - console.log('!!!! comment threads', this.props.commentThreads); return [...this.props.commentThreads].reverse().map(({rootCommentId, comments}) => { const rootComment = comments[0]; if (!rootComment.position) { From 839583e36712d6c672f98365a94eb4bcbecb5ece Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 28 Dec 2018 16:26:11 -0800 Subject: [PATCH 2437/4847] Add PAGINATION_WAIT_TIME_MS const to helper file Co-Authored-By: Tilde Ann Thurium --- lib/containers/pr-review-comments-container.js | 4 ++-- lib/controllers/pr-reviews-controller.js | 4 ++-- lib/helpers.js | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 031ae77653..c58d0ac7ee 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -1,7 +1,7 @@ import {graphql, createPaginationContainer} from 'react-relay'; import React from 'react'; -import {PAGE_SIZE} from '../helpers'; +import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../helpers'; export class ReviewCommentsController extends React.Component { @@ -30,7 +30,7 @@ export class ReviewCommentsController extends React.Component { if (this.props.relay.isLoading()) { setTimeout(() => { this._loadMoreComments(); - }, 300); + }, PAGINATION_WAIT_TIME_MS); } else { this._loadMoreComments(); } diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 1e1d8c2f11..b67df0c3f8 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -4,7 +4,7 @@ import {RelayConnectionPropType} from '../prop-types'; import PullRequestReviewCommentsContainer from '../containers/pr-review-comments-container'; import PullRequestReviewCommentsView from '../views/pr-review-comments-view'; -import {PAGE_SIZE} from '../helpers'; +import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../helpers'; export default class PullRequestReviewsController extends React.Component { static propTypes = { @@ -50,7 +50,7 @@ export default class PullRequestReviewsController extends React.Component { if (this.props.relay.isLoading()) { setTimeout(() => { this._loadMoreReviews(); - }, 300); + }, PAGINATION_WAIT_TIME_MS); } else { this._loadMoreReviews(); } diff --git a/lib/helpers.js b/lib/helpers.js index c45375b232..0b76f1bc71 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -9,6 +9,7 @@ import RefHolder from './models/ref-holder'; export const LINE_ENDING_REGEX = /\r?\n/; export const CO_AUTHOR_REGEX = /^co-authored-by. (.+?) <(.+?)>$/i; export const PAGE_SIZE = 50; +export const PAGINATION_WAIT_TIME_MS = 100; export function autobind(self, ...methods) { for (const method of methods) { From dd39ae5b561f91ef98457057ca144be3a851f338 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 28 Dec 2018 16:47:58 -0800 Subject: [PATCH 2438/4847] Add explanatory comments Co-Authored-By: Tilde Ann Thurium --- lib/controllers/pr-reviews-controller.js | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index b67df0c3f8..38479ad8b3 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {Fragment} from 'react'; import PropTypes from 'prop-types'; import {RelayConnectionPropType} from '../prop-types'; @@ -57,12 +57,14 @@ export default class PullRequestReviewsController extends React.Component { } aggregateComments = (reviewId, comments) => { + // react batches calls to setState and does not update state synchronously + // therefore we need an intermediate state so we can do checks against keys + // we have just added. const state = this.state; comments.edges.forEach(({node}) => { const comment = node; if (!comment.replyTo) { state[comment.id] = [comment]; - // this.setState({[comment.id]: [comment]}); } else { // When comment being replied to is outdated...?? Not 100% sure... // Why would we even get an outdated comment or a response to one here? @@ -71,7 +73,6 @@ export default class PullRequestReviewsController extends React.Component { // who's replyTo comment is an outdated comment if (!state[comment.replyTo.id]) { state[comment.id] = [comment]; - // this.setState({[comment.id]: [comment]}); } else { state[comment.replyTo.id].push(comment); } @@ -80,7 +81,7 @@ export default class PullRequestReviewsController extends React.Component { this.setState(state); } - renderReviewCommentContainers() { + renderCommentFetchingContainers() { // Aggregate comments from all reviews return this.props.pullRequest.reviews.edges.map(({node}) => { const review = node; @@ -106,11 +107,20 @@ export default class PullRequestReviewsController extends React.Component { }; }); + /** Slightly hacky thing to deal with comment threading... + * + * Threads can have comments belonging to multiple reviews. + * We need a nested pagination container to fetch comment pages. + * Upon fetching new comments, the `aggregateComments` method is called with the comments to add. + * Ultimately we want to organize comments based on the root comment they are replies to. + * So `renderCommentFetchingContainers` simply fetches data and doesn't render any DOM elements. + * `PullRequestReviewCommentsView` renders the comment thread data aggregated. + * */ return ( -
    - {this.renderReviewCommentContainers()} + + {this.renderCommentFetchingContainers()} -
    +
    ); } } From 75da755b4a5fd426f0125865b77dd0877276094f Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 28 Dec 2018 16:49:46 -0800 Subject: [PATCH 2439/4847] :fire: unused `body` field on review comment Co-Authored-By: Tilde Ann Thurium --- .../issueishDetailContainerQuery.graphql.js | 59 +++---- .../prReviewCommentsContainerQuery.graphql.js | 12 +- ...rReviewCommentsContainer_review.graphql.js | 10 +- .../prReviewsContainerQuery.graphql.js | 35 ++-- .../pr-review-comments-container.js | 2 - .../prDetailViewRefetchQuery.graphql.js | 167 +++++++++--------- 6 files changed, 129 insertions(+), 156 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 5158fd1965..6f0b3544a4 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 89eb63ec03a0c0f750b90f024809ee03 + * @relayHash 8593181024464fe44267e78f2c66b059 */ /* eslint-disable */ @@ -557,7 +557,6 @@ fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { id } } - body bodyHTML path position @@ -1144,14 +1143,7 @@ v36 = { v18 ] }, -v37 = { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null -}, -v38 = [ +v37 = [ { "kind": "ScalarField", "alias": null, @@ -1161,7 +1153,7 @@ v38 = [ }, v2 ], -v39 = [ +v38 = [ { "kind": "Variable", "name": "after", @@ -1175,21 +1167,21 @@ v39 = [ "type": "Int" } ], -v40 = { +v39 = { "kind": "ScalarField", "alias": null, "name": "path", "args": null, "storageKey": null }, -v41 = { +v40 = { "kind": "ScalarField", "alias": null, "name": "position", "args": null, "storageKey": null }, -v42 = { +v41 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -1197,9 +1189,9 @@ v42 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v38 + "selections": v37 }, -v43 = { +v42 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -1214,7 +1206,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1573,7 +1565,13 @@ return { "plural": false, "selections": [ v2, - v37, + { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null + }, { "kind": "LinkedField", "alias": "commitId", @@ -1582,7 +1580,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v38 + "selections": v37 }, v11, { @@ -1621,7 +1619,7 @@ return { "alias": null, "name": "comments", "storageKey": null, - "args": v39, + "args": v38, "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ @@ -1647,10 +1645,9 @@ return { "selections": [ v2, v26, - v37, v12, + v39, v40, - v41, { "kind": "LinkedField", "alias": null, @@ -1676,7 +1673,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "comments", - "args": v39, + "args": v38, "handle": "connection", "key": "PrReviewCommentsContainer_comments", "filters": null @@ -1877,7 +1874,7 @@ return { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v42, + v41, { "kind": "LinkedField", "alias": null, @@ -1923,11 +1920,11 @@ return { "plural": false, "selections": v23 }, - v42, + v41, v12, v27, - v40, - v41 + v39, + v40 ] } ] @@ -1940,7 +1937,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v43, + v42, { "kind": "LinkedField", "alias": null, @@ -1949,7 +1946,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v38 + "selections": v37 }, { "kind": "LinkedField", @@ -1959,7 +1956,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v38 + "selections": v37 }, v27 ] @@ -1968,8 +1965,8 @@ return { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v43, v42, + v41, { "kind": "ScalarField", "alias": null, diff --git a/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js index dc46be1e33..6fc33f5de0 100644 --- a/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 5658256f086fc990e6f8c58966b65c77 + * @relayHash aa28e03673267c061792b18ed9e13038 */ /* eslint-disable */ @@ -61,7 +61,6 @@ fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { id } } - body bodyHTML path position @@ -139,7 +138,7 @@ return { "operationKind": "query", "name": "prReviewCommentsContainerQuery", "id": null, - "text": "query prReviewCommentsContainerQuery(\n $commentCount: Int!\n $commentCursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequestReview {\n ...prReviewCommentsContainer_review_1VbUmL\n }\n id\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "text": "query prReviewCommentsContainerQuery(\n $commentCount: Int!\n $commentCursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequestReview {\n ...prReviewCommentsContainer_review_1VbUmL\n }\n id\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -292,13 +291,6 @@ return { v3 ] }, - { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null - }, { "kind": "ScalarField", "alias": null, diff --git a/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js b/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js index 5a674efbcc..7f1b8d16e1 100644 --- a/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js +++ b/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js @@ -25,7 +25,6 @@ export type prReviewCommentsContainer_review = {| +avatarUrl: any, +login: string, |}, - +body: string, +bodyHTML: any, +path: string, +position: ?number, @@ -167,13 +166,6 @@ return { } ] }, - { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null - }, { "kind": "ScalarField", "alias": null, @@ -238,5 +230,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'd4b785b8fc4e5b4bedc5aa92491f37e7'; +(node/*: any*/).hash = 'd2db363653fb73e8f4d019026668babc'; module.exports = node; diff --git a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js index edf519cbfc..63254fbff3 100644 --- a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 4118118a2d92572dc108cf48c14c067f + * @relayHash a2fda52ce9272b72cf214c6bcd70719a */ /* eslint-disable */ @@ -106,7 +106,6 @@ fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { id } } - body bodyHTML path position @@ -231,27 +230,20 @@ v7 = { "storageKey": null }, v8 = { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null -}, -v9 = { "kind": "ScalarField", "alias": null, "name": "login", "args": null, "storageKey": null }, -v10 = { +v9 = { "kind": "ScalarField", "alias": null, "name": "avatarUrl", "args": null, "storageKey": null }, -v11 = [ +v10 = [ { "kind": "Variable", "name": "after", @@ -270,7 +262,7 @@ return { "operationKind": "query", "name": "prReviewsContainerQuery", "id": null, - "text": "query prReviewsContainerQuery(\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_y4qc0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "text": "query prReviewsContainerQuery(\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_y4qc0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -379,7 +371,13 @@ return { "plural": false, "selections": [ v3, - v8, + { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null + }, { "kind": "LinkedField", "alias": "commitId", @@ -423,7 +421,7 @@ return { "plural": false, "selections": [ v2, - v9, + v8, v3 ] }, @@ -437,7 +435,7 @@ return { "plural": false, "selections": [ v2, - v10, + v9, v3 ] }, @@ -446,7 +444,7 @@ return { "alias": null, "name": "comments", "storageKey": null, - "args": v11, + "args": v10, "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ @@ -481,12 +479,11 @@ return { "plural": false, "selections": [ v2, - v10, v9, + v8, v3 ] }, - v8, { "kind": "ScalarField", "alias": null, @@ -539,7 +536,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "comments", - "args": v11, + "args": v10, "handle": "connection", "key": "PrReviewCommentsContainer_comments", "filters": null diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index c58d0ac7ee..a06c19c52b 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -4,7 +4,6 @@ import React from 'react'; import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../helpers'; export class ReviewCommentsController extends React.Component { - componentDidMount() { this.props.aggregateComments(this.props.review.id, this.props.review.comments); this._attemptToLoadMoreComments(); @@ -66,7 +65,6 @@ export default createPaginationContainer(ReviewCommentsController, { avatarUrl login } - body bodyHTML path position diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index 73318ce8b6..d75b7040e7 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 6c0ffc5e033e9c921a9287900c81cc20 + * @relayHash 7e3a37960cf0fb44d162883d95c9838d */ /* eslint-disable */ @@ -473,7 +473,6 @@ fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { id } } - body bodyHTML path position @@ -692,14 +691,7 @@ v18 = { "args": null, "storageKey": null }, -v19 = { - "kind": "ScalarField", - "alias": null, - "name": "body", - "args": null, - "storageKey": null -}, -v20 = [ +v19 = [ { "kind": "ScalarField", "alias": null, @@ -709,21 +701,21 @@ v20 = [ }, v6 ], -v21 = { +v20 = { "kind": "ScalarField", "alias": null, "name": "state", "args": null, "storageKey": null }, -v22 = { +v21 = { "kind": "ScalarField", "alias": null, "name": "avatarUrl", "args": null, "storageKey": null }, -v23 = [ +v22 = [ { "kind": "Variable", "name": "after", @@ -737,13 +729,13 @@ v23 = [ "type": "Int" } ], -v24 = [ +v23 = [ v5, - v22, + v21, v8, v6 ], -v25 = { +v24 = { "kind": "LinkedField", "alias": null, "name": "author", @@ -751,37 +743,37 @@ v25 = { "args": null, "concreteType": null, "plural": false, - "selections": v24 + "selections": v23 }, -v26 = { +v25 = { "kind": "ScalarField", "alias": null, "name": "bodyHTML", "args": null, "storageKey": null }, -v27 = { +v26 = { "kind": "ScalarField", "alias": null, "name": "path", "args": null, "storageKey": null }, -v28 = { +v27 = { "kind": "ScalarField", "alias": null, "name": "position", "args": null, "storageKey": null }, -v29 = { +v28 = { "kind": "ScalarField", "alias": null, "name": "createdAt", "args": null, "storageKey": null }, -v30 = [ +v29 = [ { "kind": "Variable", "name": "after", @@ -795,7 +787,7 @@ v30 = [ "type": "Int" } ], -v31 = { +v30 = { "kind": "LinkedField", "alias": null, "name": "pageInfo", @@ -808,14 +800,14 @@ v31 = { v15 ] }, -v32 = { +v31 = { "kind": "ScalarField", "alias": "sha", "name": "oid", "args": null, "storageKey": null }, -v33 = [ +v32 = [ { "kind": "ScalarField", "alias": null, @@ -824,17 +816,17 @@ v33 = [ "storageKey": null } ], -v34 = { +v33 = { "kind": "ScalarField", "alias": null, "name": "title", "args": null, "storageKey": null }, -v35 = [ +v34 = [ v13 ], -v36 = [ +v35 = [ { "kind": "Variable", "name": "after", @@ -848,13 +840,13 @@ v36 = [ "type": "Int" } ], -v37 = [ +v36 = [ v5, v8, - v22, + v21, v6 ], -v38 = { +v37 = { "kind": "LinkedField", "alias": null, "name": "commit", @@ -862,9 +854,9 @@ v38 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v20 + "selections": v19 }, -v39 = { +v38 = { "kind": "LinkedField", "alias": null, "name": "actor", @@ -872,9 +864,9 @@ v39 = { "args": null, "concreteType": null, "plural": false, - "selections": v24 + "selections": v23 }, -v40 = { +v39 = { "kind": "LinkedField", "alias": null, "name": "user", @@ -892,7 +884,7 @@ return { "operationKind": "query", "name": "prDetailViewRefetchQuery", "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n body\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1059,7 +1051,13 @@ return { "plural": false, "selections": [ v6, - v19, + { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null + }, { "kind": "LinkedField", "alias": "commitId", @@ -1068,9 +1066,9 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v20 + "selections": v19 }, - v21, + v20, { "kind": "ScalarField", "alias": null, @@ -1098,7 +1096,7 @@ return { "plural": false, "selections": [ v5, - v22, + v21, v6 ] }, @@ -1107,7 +1105,7 @@ return { "alias": null, "name": "comments", "storageKey": null, - "args": v23, + "args": v22, "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ @@ -1132,11 +1130,10 @@ return { "plural": false, "selections": [ v6, + v24, v25, - v19, v26, v27, - v28, { "kind": "LinkedField", "alias": null, @@ -1149,7 +1146,7 @@ return { v6 ] }, - v29, + v28, v13, v5 ] @@ -1162,7 +1159,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "comments", - "args": v23, + "args": v22, "handle": "connection", "key": "PrReviewCommentsContainer_comments", "filters": null @@ -1188,11 +1185,11 @@ return { "alias": null, "name": "commits", "storageKey": null, - "args": v30, + "args": v29, "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ - v31, + v30, { "kind": "LinkedField", "alias": null, @@ -1231,7 +1228,7 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v22, + v21, v7, { "kind": "ScalarField", @@ -1263,7 +1260,7 @@ return { "args": null, "storageKey": null }, - v32, + v31, v13 ] }, @@ -1279,7 +1276,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v30, + "args": v29, "handle": "connection", "key": "prCommitsView_commits", "filters": null @@ -1292,7 +1289,7 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v33 + "selections": v32 }, { "kind": "LinkedField", @@ -1346,7 +1343,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v21, + v20, { "kind": "LinkedField", "alias": null, @@ -1357,7 +1354,7 @@ return { "plural": true, "selections": [ v6, - v21, + v20, { "kind": "ScalarField", "alias": null, @@ -1394,9 +1391,9 @@ return { } ] }, - v21, - v34, - v26, + v20, + v33, + v25, { "kind": "ScalarField", "alias": null, @@ -1422,17 +1419,17 @@ return { "selections": [ v5, v8, - v22, + v21, v6, { "kind": "InlineFragment", "type": "Bot", - "selections": v35 + "selections": v34 }, { "kind": "InlineFragment", "type": "User", - "selections": v35 + "selections": v34 } ] }, @@ -1464,11 +1461,11 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": v36, + "args": v35, "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v31, + v30, { "kind": "LinkedField", "alias": null, @@ -1510,7 +1507,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v37 + "selections": v36 }, { "kind": "LinkedField", @@ -1549,7 +1546,7 @@ return { "type": "PullRequest", "selections": [ v11, - v34, + v33, v13, { "kind": "ScalarField", @@ -1565,7 +1562,7 @@ return { "type": "Issue", "selections": [ v11, - v34, + v33, v13, { "kind": "ScalarField", @@ -1584,7 +1581,7 @@ return { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v38, + v37, { "kind": "LinkedField", "alias": null, @@ -1628,13 +1625,13 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v37 + "selections": v36 }, - v38, + v37, + v25, + v28, v26, - v29, - v27, - v28 + v27 ] } ] @@ -1647,7 +1644,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v39, + v38, { "kind": "LinkedField", "alias": null, @@ -1656,7 +1653,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v20 + "selections": v19 }, { "kind": "LinkedField", @@ -1666,17 +1663,17 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v20 + "selections": v19 }, - v29 + v28 ] }, { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v39, v38, + v37, { "kind": "ScalarField", "alias": null, @@ -1684,16 +1681,16 @@ return { "args": null, "storageKey": null }, - v29 + v28 ] }, { "kind": "InlineFragment", "type": "IssueComment", "selections": [ + v24, v25, - v26, - v29, + v28, v13 ] }, @@ -1711,8 +1708,8 @@ return { "plural": false, "selections": [ v7, - v40, - v22 + v39, + v21 ] }, { @@ -1725,8 +1722,8 @@ return { "plural": false, "selections": [ v7, - v22, - v40 + v21, + v39 ] }, { @@ -1736,7 +1733,7 @@ return { "args": null, "storageKey": null }, - v32, + v31, { "kind": "ScalarField", "alias": null, @@ -1770,7 +1767,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v36, + "args": v35, "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null @@ -1799,7 +1796,7 @@ return { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v33 + "selections": v32 } ] } From 6cc0b89530d047831c52079f916b968b93f830d8 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 28 Dec 2018 16:50:18 -0800 Subject: [PATCH 2440/4847] :fire: unused prop Co-Authored-By: Tilde Ann Thurium --- lib/views/pr-review-comments-view.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index 286615ab76..7d437ec71d 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -1,7 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import {Point, Range} from 'atom'; -import {RelayConnectionPropType} from '../prop-types'; import {toNativePathSep} from '../helpers'; import Marker from '../atom/marker'; From 3c21f20c0ef2ad29049bbc1123615066a9b093a8 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 28 Dec 2018 17:21:22 -0800 Subject: [PATCH 2441/4847] Get rid of hack for ensuring comment threads appear in the right order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No idea why this stopped being necessary... ¯\_(ツ)_/¯ Co-Authored-By: Tilde Ann Thurium --- lib/views/pr-review-comments-view.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index 7d437ec71d..f14da94c3c 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -8,8 +8,6 @@ import Decoration from '../atom/decoration'; import GithubDotcomMarkdown from './github-dotcom-markdown'; import Timeago from './timeago'; -let count = 0; - export default class PullRequestCommentsView extends React.Component { static propTypes = { relay: PropTypes.shape({ @@ -38,7 +36,7 @@ export default class PullRequestCommentsView extends React.Component { // TODO: find way to re-use nodes by using same key. this count++ hack is in place to get the comments to show up // in the correct order after new pages of data are fetched. Test it by reducing the reviewCount to a small number return ( - + {comments.map(comment => { return ( From 287b609981c62a548c034216d0949a26f1bc1c0a Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 2 Jan 2019 18:00:02 +0900 Subject: [PATCH 2442/4847] Add borders to comment threads --- lib/views/pr-review-comments-view.js | 2 +- styles/pr-comment.less | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index f14da94c3c..279e4deb51 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -59,7 +59,7 @@ export class PullRequestCommentView extends React.Component { const author = this.props.comment.author; const login = author ? author.login : 'someone'; return ( -
    +
    {login} {login} commented{' '} diff --git a/styles/pr-comment.less b/styles/pr-comment.less index 427dd1a0b3..65887aef25 100644 --- a/styles/pr-comment.less +++ b/styles/pr-comment.less @@ -2,18 +2,21 @@ @avatar-size: 16px; + +.github-PrCommentThread { + padding: @component-padding/2 0; + border-bottom: 1px solid @base-border-color; +} + + .github-PrComment { + max-width: 60em; + margin: @component-padding 0; + padding-right: @component-padding*2; font-family: @font-family; font-size: @font-size; - &-wrapper { - max-width: 60em; - padding-right: @component-padding*2; - padding-bottom: @component-padding; - } - &-header { - padding: @component-padding 0 @component-padding/2 0; color: @text-color-subtle; } From 2e3a244578d6e8e652868c94b9e79dc18b79ad22 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 2 Jan 2019 13:41:57 +0100 Subject: [PATCH 2443/4847] fix some linter errors --- lib/containers/pr-review-comments-container.js | 18 +++++++++++++++++- lib/controllers/multi-file-patch-controller.js | 2 ++ lib/controllers/pr-reviews-controller.js | 3 ++- lib/views/multi-file-patch-view.js | 9 ++++++++- lib/views/pr-review-comments-view.js | 15 +++++++++++++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index a06c19c52b..d0a7ca7c31 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -1,9 +1,24 @@ import {graphql, createPaginationContainer} from 'react-relay'; +import PropTypes from 'prop-types'; import React from 'react'; import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../helpers'; export class ReviewCommentsController extends React.Component { + + static propTypes = { + aggregateComments: PropTypes.func.isRequired, + review: PropTypes.shape({ + id: PropTypes.number.isRequired, + comments: PropTypes.arrayOf(PropTypes.object).isRequired, + }), + relay: PropTypes.shape({ + hasMore: PropTypes.func.isRequired, + loadMore: PropTypes.func.isRequired, + isLoading: PropTypes.func.isRequired, + }).isRequired, + } + componentDidMount() { this.props.aggregateComments(this.props.review.id, this.props.review.comments); this._attemptToLoadMoreComments(); @@ -15,7 +30,8 @@ export class ReviewCommentsController extends React.Component { error => { this._attemptToLoadMoreComments(); if (error) { - console.log(error); + // eslint-disable-next-line no-console + console.error(error); } }, ); diff --git a/lib/controllers/multi-file-patch-controller.js b/lib/controllers/multi-file-patch-controller.js index 0214aa2db9..449747a3d0 100644 --- a/lib/controllers/multi-file-patch-controller.js +++ b/lib/controllers/multi-file-patch-controller.js @@ -25,6 +25,8 @@ export default class MultiFilePatchController extends React.Component { discardLines: PropTypes.func, undoLastDiscard: PropTypes.func, surface: PropTypes.func, + + switchToIssueish: PropTypes.func, } constructor(props) { diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 38479ad8b3..963c9d33bf 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -36,7 +36,8 @@ export default class PullRequestReviewsController extends React.Component { error => { this._attemptToLoadMoreReviews(); if (error) { - console.log(error); + // eslint-disable-next-line no-console + console.error(error); } }, ); diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 7296aee04d..80e46a0b86 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -47,8 +47,10 @@ export default class MultiFilePatchView extends React.Component { keymaps: PropTypes.object.isRequired, tooltips: PropTypes.object.isRequired, config: PropTypes.object.isRequired, + pullRequest: PropTypes.object, selectedRowsChanged: PropTypes.func, + switchToIssueish: PropTypes.func, diveIntoMirrorPatch: PropTypes.func, surface: PropTypes.func, @@ -313,7 +315,12 @@ export default class MultiFilePatchView extends React.Component { renderPullRequestReviews() { if (this.props.itemType === IssueishDetailItem) { - return ; + return ( + ); } else { return null; } diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index 279e4deb51..963abbe122 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -20,6 +20,7 @@ export default class PullRequestCommentsView extends React.Component { comments: PropTypes.arrayOf(PropTypes.object).isRequired, })), multiFilePatch: PropTypes.object.isRequired, + switchToIssueish: PropTypes.func.isRequired, } render() { @@ -55,6 +56,20 @@ export default class PullRequestCommentsView extends React.Component { } export class PullRequestCommentView extends React.Component { + + static propTypes = { + switchToIssueish: PropTypes.func.isRequired, + comment: PropTypes.shape({ + author: PropTypes.shape({ + avatarUrl: PropTypes.string, + login: PropTypes.string, + }), + bodyHTML: PropTypes.string, + url: PropTypes.string, + createdAt: PropTypes.string.isRequired, + }).isRequired, + } + render() { const author = this.props.comment.author; const login = author ? author.login : 'someone'; From 7c14d0c75f5886773e95320d7f533acb7d5fd623 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 2 Jan 2019 14:22:22 +0100 Subject: [PATCH 2444/4847] make tests run --- lib/containers/pr-review-comments-container.js | 2 +- test/views/pr-comments-view.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index d0a7ca7c31..6e634e3ca3 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -9,7 +9,7 @@ export class ReviewCommentsController extends React.Component { static propTypes = { aggregateComments: PropTypes.func.isRequired, review: PropTypes.shape({ - id: PropTypes.number.isRequired, + id: PropTypes.string.isRequired, comments: PropTypes.arrayOf(PropTypes.object).isRequired, }), relay: PropTypes.shape({ diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index ccb7b78673..7be8aa440a 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -3,7 +3,7 @@ import {shallow} from 'enzyme'; import {multiFilePatchBuilder} from '../builder/patch'; import {pullRequestBuilder} from '../builder/pr'; -import PullRequestCommentsView, {PullRequestCommentView} from '../../lib/views/pr-comments-view'; +import PullRequestCommentsView, {PullRequestCommentView} from '../../lib/views/pr-review-comments-view'; describe('PullRequestCommentsView', function() { it('adjusts the position for comments after hunk headers', function() { From 1bdb59e02ae4106d6e995bb0eb0ce025a35cc4dd Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 2 Jan 2019 16:44:24 +0100 Subject: [PATCH 2445/4847] compute comment threads in pr builder helper --- test/builder/pr.js | 23 +++++++++++++++++++++++ test/views/pr-comments-view.test.js | 5 +++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/test/builder/pr.js b/test/builder/pr.js index 24758ece0b..63352c8e8b 100644 --- a/test/builder/pr.js +++ b/test/builder/pr.js @@ -8,6 +8,7 @@ class CommentBuilder { this._url = 'https://github.com/atom/github/pull/1829/files#r242224689'; this._createdAt = 0; this._body = 'Lorem ipsum dolor sit amet, te urbanitas appellantur est.'; + this._replyTo = null; } id(i) { @@ -50,6 +51,11 @@ class CommentBuilder { return this; } + replyTo(replyToId) { + this._replyTo = replyToId; + return this; + } + build() { return { id: this._id, @@ -62,6 +68,7 @@ class CommentBuilder { position: this._position, createdAt: this._createdAt, url: this._url, + replyTo: this._replyTo, }; } } @@ -115,8 +122,24 @@ class PullRequestBuilder { } build() { + const commentThreads = {}; + this._reviews.forEach(review => { + review.comments.nodes.forEach(comment => { + if (comment.replyTo && commentThreads[comment.replyTo]) { + commentThreads[comment.replyTo].push(comment); + } else { + commentThreads[comment.id] = [comment]; + } + }); + }); return { reviews: {nodes: this._reviews}, + commentThreads: Object.keys(commentThreads).map(rootCommentId => { + return { + rootCommentId, + comments: commentThreads[rootCommentId], + }; + }), }; } } diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index 7be8aa440a..75e5f4d7fc 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -31,12 +31,13 @@ describe('PullRequestCommentsView', function() { }) .build(); - const wrapper = shallow(); + const wrapper = shallow(); assert.deepEqual(wrapper.find('Marker').at(0).prop('bufferRange').serialize(), [[1, 0], [1, 0]]); assert.deepEqual(wrapper.find('Marker').at(1).prop('bufferRange').serialize(), [[12, 0], [12, 0]]); assert.deepEqual(wrapper.find('Marker').at(2).prop('bufferRange').serialize(), [[20, 0], [20, 0]]); }); + it('does not render comment if position is null', function() { const {multiFilePatch} = multiFilePatchBuilder() .addFilePatch(fp => { @@ -56,7 +57,7 @@ describe('PullRequestCommentsView', function() { }) .build(); - const wrapper = shallow(); + const wrapper = shallow(); const comments = wrapper.find('PullRequestCommentView'); assert.lengthOf(comments, 1); From 304ff66fae7d8c84df8a3443f938c74ece7e64c2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 2 Jan 2019 11:12:05 -0500 Subject: [PATCH 2446/4847] Fork codecov-node so apm isn't unhappy with the devDependency format --- package-lock.json | 49 ++++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index 712f5bcef8..eba0c11b99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -214,6 +214,31 @@ "tmp": "0.0.31" } }, + "@smashwilson/codecov": { + "version": "3.1.1-azure0.0", + "resolved": "https://registry.npmjs.org/@smashwilson/codecov/-/codecov-3.1.1-azure0.0.tgz", + "integrity": "sha512-ctT6EDZ+uQpZhixzTJoWBOF32ZKEaAg+h4iVApEhTMxtLFNYzGSepz6hS5enIXzxMzQiMEzZgVUqGtk1G7kRXg==", + "dev": true, + "requires": { + "argv": "^0.0.2", + "ignore-walk": "^3.0.1", + "js-yaml": "^3.12.0", + "teeny-request": "^3.7.0", + "urlgrey": "^0.4.4" + }, + "dependencies": { + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, "@types/node": { "version": "10.12.12", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.12.tgz", @@ -2024,30 +2049,6 @@ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, - "codecov": { - "version": "github:codecov/codecov-node#e427d900309adb50746a39a50aa7d80071a5ddd0", - "from": "github:codecov/codecov-node#e427d90", - "dev": true, - "requires": { - "argv": "^0.0.2", - "ignore-walk": "^3.0.1", - "js-yaml": "^3.12.0", - "teeny-request": "^3.7.0", - "urlgrey": "^0.4.4" - }, - "dependencies": { - "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - } - } - }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", diff --git a/package.json b/package.json index 6ab320fd1c..1504a16ad7 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "babel-plugin-istanbul": "4.1.6", "chai": "4.1.2", "chai-as-promised": "7.1.1", - "codecov": "codecov/codecov-node#e427d90", + "@smashwilson/codecov": "3.1.1-azure0.0", "cross-env": "5.2.0", "cross-unzip": "0.2.1", "dedent-js": "1.0.1", From 94b8d95d4ddf2d3de781de799dfd429665182743 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 2 Jan 2019 11:13:16 -0500 Subject: [PATCH 2447/4847] Prepare 0.24.0-0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index eba0c11b99..cdae93d690 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "github", - "version": "0.23.0", + "version": "0.24.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1504a16ad7..16bb4a45fa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "github", "main": "./lib/index", - "version": "0.23.0", + "version": "0.24.0-0", "description": "GitHub integration", "repository": "https://github.com/atom/github", "license": "MIT", From 378a113a8188820415b4fcb1f2b4c9806c2f1de6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 2 Jan 2019 13:03:26 -0500 Subject: [PATCH 2448/4847] Unit test to catch an empty repository --- test/models/user-store.test.js | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 6d5d255928..0d70bfd23c 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -38,6 +38,7 @@ describe('UserStore', function() { const opts = { owner: 'me', name: 'stuff', + repositoryFound: true, ...options, }; @@ -50,7 +51,7 @@ describe('UserStore', function() { name: 'GetMentionableUsers', variables: {owner: opts.owner, name: opts.name, first: 100, after: lastCursor}, }, { - repository: { + repository: !opts.repositoryFound ? null : { mentionableUsers: { nodes: page, pageInfo: { @@ -173,6 +174,27 @@ describe('UserStore', function() { ]); }); + it('skips GitHub remotes that no longer exist', async function() { + await login.setToken('https://api.github.com', '1234'); + + const workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + + await repository.setConfig('remote.origin.url', 'git@github.com:me/stuff.git'); + await repository.setConfig('remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*'); + + const [{resolve, promise}] = expectPagedRelayQueries({repositoryFound: false}, []); + + store = new UserStore({repository, login, config}); + await nextUpdatePromise(); + + resolve(); + // nextUpdatePromise will not fire because the update is empty + await promise; + + assert.deepEqual(store.getUsers(), []); + }); + it('infers no-reply emails for users without a public email address', async function() { await login.setToken('https://api.github.com', '1234'); @@ -406,8 +428,8 @@ describe('UserStore', function() { const actualToken = await store.getToken(loginModel, 'https://api.github.com'); assert.strictEqual(expectedToken, actualToken); }); - }); + describe('loadMentionableUsers', function() { it('returns undefined if token is null', async function() { const workdirPath = await cloneRepository('multiple-commits'); From fe93f9b7c8cee857ba5dfd9a0df009d44103ed91 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 2 Jan 2019 13:03:34 -0500 Subject: [PATCH 2449/4847] Break on a missing repository --- lib/models/user-store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index ae11ba48a2..30a8c97355 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -175,7 +175,7 @@ export default class UserStore { console.error(`Error fetching mentionable users:\n${response.errors.map(e => e.message).join('\n')}`); } - if (!response.data) { + if (!response.data || !response.data.repository) { break; } From c2da60107a46e4154aa51e9f209da05d75d271fb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 2 Jan 2019 14:20:17 -0500 Subject: [PATCH 2450/4847] Prepare 0.24.0-1 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cdae93d690..bcac3e3ae6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "github", - "version": "0.24.0-0", + "version": "0.24.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 16bb4a45fa..86bae59b72 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "github", "main": "./lib/index", - "version": "0.24.0-0", + "version": "0.24.0-1", "description": "GitHub integration", "repository": "https://github.com/atom/github", "license": "MIT", From 84fb79a907fba92f41c34db02108e530bfb889f7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 2 Jan 2019 15:17:00 -0500 Subject: [PATCH 2451/4847] Sinon has a `.resolves()` helper to save some typing --- test/models/github-login-model.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/models/github-login-model.test.js b/test/models/github-login-model.test.js index 816c9ce428..bfc2240263 100644 --- a/test/models/github-login-model.test.js +++ b/test/models/github-login-model.test.js @@ -47,19 +47,19 @@ describe('GithubLoginModel', function() { }); it('returns INSUFFICIENT if scopes are present', async function() { - sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'read:org'])); + sinon.stub(loginModel, 'getScopes').resolves(['repo', 'read:org']); assert.strictEqual(await loginModel.getToken('https://api.github.com'), INSUFFICIENT); }); it('returns the token if at least the required scopes are present', async function() { - sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'read:org', 'user:email', 'extra'])); + sinon.stub(loginModel, 'getScopes').resolves(['repo', 'read:org', 'user:email', 'extra']); assert.strictEqual(await loginModel.getToken('https://api.github.com'), '1234'); }); it('caches checked tokens', async function() { - sinon.stub(loginModel, 'getScopes').returns(Promise.resolve(['repo', 'read:org', 'user:email'])); + sinon.stub(loginModel, 'getScopes').resolves(['repo', 'read:org', 'user:email']); assert.strictEqual(await loginModel.getToken('https://api.github.com'), '1234'); assert.strictEqual(loginModel.getScopes.callCount, 1); From cf36d8a6c0b25cccbb6738aa642378694f7cc3f6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 2 Jan 2019 15:17:12 -0500 Subject: [PATCH 2452/4847] Tests for failure caching --- test/models/github-login-model.test.js | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/models/github-login-model.test.js b/test/models/github-login-model.test.js index bfc2240263..d770ac317f 100644 --- a/test/models/github-login-model.test.js +++ b/test/models/github-login-model.test.js @@ -67,5 +67,35 @@ describe('GithubLoginModel', function() { assert.strictEqual(await loginModel.getToken('https://api.github.com'), '1234'); assert.strictEqual(loginModel.getScopes.callCount, 1); }); + + it('caches tokens that failed to authenticate correctly', async function() { + sinon.stub(loginModel, 'getScopes').resolves(GithubLoginModel.UNAUTHORIZED); + + assert.strictEqual(await loginModel.getToken('https://api.github.com'), UNAUTHENTICATED); + assert.strictEqual(loginModel.getScopes.callCount, 1); + + assert.strictEqual(await loginModel.getToken('https://api.github.com'), UNAUTHENTICATED); + assert.strictEqual(loginModel.getScopes.callCount, 1); + }); + + it('caches tokens that had insufficient scopes', async function() { + sinon.stub(loginModel, 'getScopes').resolves(['repo', 'read:org']); + + assert.strictEqual(await loginModel.getToken('https://api.github.com'), INSUFFICIENT); + assert.strictEqual(loginModel.getScopes.callCount, 1); + + assert.strictEqual(await loginModel.getToken('https://api.github.com'), INSUFFICIENT); + assert.strictEqual(loginModel.getScopes.callCount, 1); + }); + + it('does not cache network errors', async function() { + sinon.stub(loginModel, 'getScopes').rejects(new Error('You unplugged your ethernet cable')); + + assert.strictEqual(await loginModel.getToken('https://api.github.com'), UNAUTHENTICATED); + assert.strictEqual(loginModel.getScopes.callCount, 1); + + assert.strictEqual(await loginModel.getToken('https://api.github.com'), UNAUTHENTICATED); + assert.strictEqual(loginModel.getScopes.callCount, 2); + }); }); }); From 92849a97068d7c131cca7a6b5514fe70018e9e1a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 2 Jan 2019 15:17:49 -0500 Subject: [PATCH 2453/4847] Cache the outcome of the scope check regardless of success or failure --- lib/models/github-login-model.js | 34 +++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/models/github-login-model.js b/lib/models/github-login-model.js index 99554e64bd..04e02d3dd6 100644 --- a/lib/models/github-login-model.js +++ b/lib/models/github-login-model.js @@ -10,6 +10,9 @@ export default class GithubLoginModel { // give everyone a really frustrating experience ;-) static REQUIRED_SCOPES = ['repo', 'read:org', 'user:email'] + // Returned from getScopes if the HEAD request fails with a 401 + static UNAUTHORIZED = Symbol('unauthorized') + static get() { if (!instance) { instance = new GithubLoginModel(); @@ -21,7 +24,7 @@ export default class GithubLoginModel { this._Strategy = Strategy; this._strategy = null; this.emitter = new Emitter(); - this.checked = new Set(); + this.checked = new Map(); } async getStrategy() { @@ -53,21 +56,33 @@ export default class GithubLoginModel { hash.update(password); const fingerprint = hash.digest('base64'); - if (!this.checked.has(fingerprint)) { + const outcome = this.checked.get(fingerprint); + if (outcome === UNAUTHENTICATED || outcome === INSUFFICIENT) { + // Cached failure + return outcome; + } else if (!outcome) { + // No cached outcome. Query for scopes. try { - const scopes = new Set(await this.getScopes(account, password)); + const scopes = await this.getScopes(account, password); + if (scopes === this.constructor.UNAUTHORIZED) { + // password is incorrect + this.checked.set(fingerprint, UNAUTHENTICATED); + return UNAUTHENTICATED; + } + const scopeSet = new Set(scopes); for (const scope of this.constructor.REQUIRED_SCOPES) { - if (!scopes.has(scope)) { + if (!scopeSet.has(scope)) { // Token doesn't have enough OAuth scopes, need to reauthenticate + this.checked.set(fingerprint, INSUFFICIENT); return INSUFFICIENT; } } - // We're good - this.checked.add(fingerprint); + // Successfully authenticated and had all required scopes. + this.checked.set(fingerprint, true); } catch (e) { - // Bad credential most likely + // Most likely a network error. Do not cache the failure. // eslint-disable-next-line no-console console.error(`Unable to validate token scopes against ${account}`, e); return UNAUTHENTICATED; @@ -104,6 +119,11 @@ export default class GithubLoginModel { headers: {Authorization: `bearer ${token}`}, }); + if (response.status === 401) { + // Unauthorized + return this.constructor.UNAUTHORIZED; + } + if (response.status !== 200) { throw new Error(`Unable to check token for OAuth scopes against ${host}: ${await response.text()}`); } From ea391fb3425ef864e30999eedf6c2810d22949e7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 2 Jan 2019 15:44:06 -0500 Subject: [PATCH 2454/4847] getScopes() exists to do a `fetch`, skip it for coverage --- lib/models/github-login-model.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/models/github-login-model.js b/lib/models/github-login-model.js index 04e02d3dd6..394dbfd71f 100644 --- a/lib/models/github-login-model.js +++ b/lib/models/github-login-model.js @@ -105,6 +105,7 @@ export default class GithubLoginModel { this.didUpdate(); } + /* istanbul ignore next */ async getScopes(host, token) { if (atom.inSpecMode()) { if (token === 'good-token') { From 3b61634adf5339a29e8e9ca0ead8909a590e96af Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Wed, 2 Jan 2019 13:03:23 -0800 Subject: [PATCH 2455/4847] :fire: stale todo --- lib/views/pr-review-comments-view.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index 963abbe122..ea926a730d 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -34,8 +34,6 @@ export default class PullRequestCommentsView extends React.Component { const row = this.props.multiFilePatch.getBufferRowForDiffPosition(nativePath, rootComment.position); const point = new Point(row, 0); const range = new Range(point, point); - // TODO: find way to re-use nodes by using same key. this count++ hack is in place to get the comments to show up - // in the correct order after new pages of data are fetched. Test it by reducing the reviewCount to a small number return ( From 97fad343dc2d6691b0c0b1a17c65fa261c029ca6 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 2 Jan 2019 21:49:07 +0000 Subject: [PATCH 2456/4847] chore(package): update electron-link to version 0.3.2 Closes #1861 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 86bae59b72..b2f0b0ca8f 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "cross-unzip": "0.2.1", "dedent-js": "1.0.1", "electron-devtools-installer": "2.2.4", - "electron-link": "0.2.2", + "electron-link": "0.3.2", "electron-mksnapshot": "3.0.0-beta.1", "enzyme": "3.8.0", "enzyme-adapter-react-16": "1.7.1", From 9e5047d4f9bda961b3fcf3fd6dacfba4677fc1b8 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 2 Jan 2019 21:49:10 +0000 Subject: [PATCH 2457/4847] chore(package): update lockfile package-lock.json --- package-lock.json | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index bcac3e3ae6..390a2f75e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1643,9 +1643,9 @@ } }, "bindings": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz", - "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.1.tgz", + "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==", "dev": true }, "bl": { @@ -2667,19 +2667,27 @@ } }, "electron-link": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/electron-link/-/electron-link-0.2.2.tgz", - "integrity": "sha1-uWvx/MrowwyAuiaTBq+UVOYtP2U=", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/electron-link/-/electron-link-0.3.2.tgz", + "integrity": "sha512-V7QmtujzWgvrW5BI2CKmIRF+q+pkrFO5Lecd8TpibbBz+FfW5WQ4kCN0sZjNaUOMtGGroCib721OqIDEynjwgA==", "dev": true, "requires": { "ast-util": "^0.6.0", "encoding-down": "~5.0.0", - "indent-string": "^2.1.0", + "indent-string": "^3.2.0", "leveldown": "~4.0.0", "levelup": "~3.0.0", "recast": "^0.12.6", "resolve": "^1.5.0", "source-map": "^0.5.6" + }, + "dependencies": { + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + } } }, "electron-mksnapshot": { @@ -6968,12 +6976,12 @@ } }, "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz", + "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } }, "resolve-from": { From 9a81c9a1434c07a37caca80fd1884bcc66be13d7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 3 Jan 2019 08:45:20 -0500 Subject: [PATCH 2458/4847] Move UNAUTHORIZED to keytar-strategy with the rest of the token states --- lib/models/github-login-model.js | 12 ++++-------- lib/shared/keytar-strategy.js | 6 ++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/models/github-login-model.js b/lib/models/github-login-model.js index 394dbfd71f..ab95551915 100644 --- a/lib/models/github-login-model.js +++ b/lib/models/github-login-model.js @@ -1,7 +1,7 @@ import crypto from 'crypto'; import {Emitter} from 'event-kit'; -import {UNAUTHENTICATED, INSUFFICIENT, createStrategy} from '../shared/keytar-strategy'; +import {UNAUTHENTICATED, INSUFFICIENT, UNAUTHORIZED, createStrategy} from '../shared/keytar-strategy'; let instance = null; @@ -10,9 +10,6 @@ export default class GithubLoginModel { // give everyone a really frustrating experience ;-) static REQUIRED_SCOPES = ['repo', 'read:org', 'user:email'] - // Returned from getScopes if the HEAD request fails with a 401 - static UNAUTHORIZED = Symbol('unauthorized') - static get() { if (!instance) { instance = new GithubLoginModel(); @@ -64,8 +61,8 @@ export default class GithubLoginModel { // No cached outcome. Query for scopes. try { const scopes = await this.getScopes(account, password); - if (scopes === this.constructor.UNAUTHORIZED) { - // password is incorrect + if (scopes === UNAUTHORIZED) { + // Password is incorrect. Treat it as though you aren't authenticated at all. this.checked.set(fingerprint, UNAUTHENTICATED); return UNAUTHENTICATED; } @@ -121,8 +118,7 @@ export default class GithubLoginModel { }); if (response.status === 401) { - // Unauthorized - return this.constructor.UNAUTHORIZED; + return UNAUTHORIZED; } if (response.status !== 200) { diff --git a/lib/shared/keytar-strategy.js b/lib/shared/keytar-strategy.js index 86dcea24e2..51aa16c3d3 100644 --- a/lib/shared/keytar-strategy.js +++ b/lib/shared/keytar-strategy.js @@ -16,10 +16,15 @@ if (typeof atom === 'undefined') { }; } +// No token available in your OS keychain. const UNAUTHENTICATED = Symbol('UNAUTHENTICATED'); +// The token in your keychain isn't granted all of the required OAuth scopes. const INSUFFICIENT = Symbol('INSUFFICIENT'); +// The token in your keychain is not accepted by GitHub. +const UNAUTHORIZED = Symbol('UNAUTHORIZED'); + class KeytarStrategy { static get keytar() { return require('keytar'); @@ -248,6 +253,7 @@ async function createStrategy() { module.exports = { UNAUTHENTICATED, INSUFFICIENT, + UNAUTHORIZED, KeytarStrategy, SecurityBinaryStrategy, InMemoryStrategy, From e8f41f1c240161576cd74921f3fae339ba7954d6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 3 Jan 2019 08:55:58 -0500 Subject: [PATCH 2459/4847] Use UNAUTHORIZED constant in GithubLoginModel tests --- test/models/github-login-model.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/models/github-login-model.test.js b/test/models/github-login-model.test.js index d770ac317f..e4d2f754be 100644 --- a/test/models/github-login-model.test.js +++ b/test/models/github-login-model.test.js @@ -5,6 +5,7 @@ import { InMemoryStrategy, UNAUTHENTICATED, INSUFFICIENT, + UNAUTHORIZED, } from '../../lib/shared/keytar-strategy'; describe('GithubLoginModel', function() { @@ -69,7 +70,7 @@ describe('GithubLoginModel', function() { }); it('caches tokens that failed to authenticate correctly', async function() { - sinon.stub(loginModel, 'getScopes').resolves(GithubLoginModel.UNAUTHORIZED); + sinon.stub(loginModel, 'getScopes').resolves(UNAUTHORIZED); assert.strictEqual(await loginModel.getToken('https://api.github.com'), UNAUTHENTICATED); assert.strictEqual(loginModel.getScopes.callCount, 1); From 9b61d09f2287acba52590a0a0178c63e7e8c88b6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 3 Jan 2019 09:47:29 -0500 Subject: [PATCH 2460/4847] Give the "show more" button a left margin --- styles/pr-commit-view.less | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/styles/pr-commit-view.less b/styles/pr-commit-view.less index f39b4b3e33..eab4fbbe89 100644 --- a/styles/pr-commit-view.less +++ b/styles/pr-commit-view.less @@ -3,14 +3,6 @@ @default-padding: @component-padding; @avatar-dimensions: 16px; -.github-PrCommitsView { - - &-load-more-button { - display: block; - margin: 20px auto 0; - } -} - .github-PrCommitView { &-container { @@ -72,7 +64,7 @@ } &-moreButton { - border: none; + margin: 0 auto 0 @default-padding; padding: 0em .2em; color: @text-color-subtle; font-style: italic; From 358efdc64937534ff0c6b902bce68ec3a45ecb5e Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Thu, 3 Jan 2019 16:01:49 +0100 Subject: [PATCH 2461/4847] make title texts in PR details tabs not selectable --- styles/issueish-detail-view.less | 1 + 1 file changed, 1 insertion(+) diff --git a/styles/issueish-detail-view.less b/styles/issueish-detail-view.less index 89781361f1..704b4de843 100644 --- a/styles/issueish-detail-view.less +++ b/styles/issueish-detail-view.less @@ -156,6 +156,7 @@ font-weight: 600; color: mix(@text-color, @app-background-color, 75%); cursor: default; + user-select: none; } &-tab-icon { From 2630e7aada692bce3946774781a93ac9384c9d6a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 3 Jan 2019 11:33:30 -0500 Subject: [PATCH 2462/4847] Prepare 0.24.0-2 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bcac3e3ae6..df8492f3da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "github", - "version": "0.24.0-1", + "version": "0.24.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 86bae59b72..1effff30f5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "github", "main": "./lib/index", - "version": "0.24.0-1", + "version": "0.24.0-2", "description": "GitHub integration", "repository": "https://github.com/atom/github", "license": "MIT", From 10fb0861626700eefa9b7c47229117f6a53433b7 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 3 Jan 2019 12:41:47 -0500 Subject: [PATCH 2463/4847] Prepare 0.24.0 release --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index df8492f3da..76cc2d0cbe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "github", - "version": "0.24.0-2", + "version": "0.24.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1effff30f5..b5fd068b65 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "github", "main": "./lib/index", - "version": "0.24.0-2", + "version": "0.24.0", "description": "GitHub integration", "repository": "https://github.com/atom/github", "license": "MIT", From f47c68b7ae3456a62c763eedec139895841b027f Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 2 Jan 2019 12:08:46 -0800 Subject: [PATCH 2464/4847] follow bare container component naming convention --- lib/containers/pr-review-comments-container.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 6e634e3ca3..d1e8789740 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -4,7 +4,7 @@ import React from 'react'; import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../helpers'; -export class ReviewCommentsController extends React.Component { +export class BarePullRequestReviewCommentsContainer extends React.Component { static propTypes = { aggregateComments: PropTypes.func.isRequired, @@ -56,7 +56,7 @@ export class ReviewCommentsController extends React.Component { } } -export default createPaginationContainer(ReviewCommentsController, { +export default createPaginationContainer(BarePullRequestReviewCommentsContainer, { review: graphql` fragment prReviewCommentsContainer_review on PullRequestReview @argumentDefinitions( From 72af9951a97da9b1df7c62df0aa25c63cc9cfe87 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 3 Jan 2019 15:37:28 -0800 Subject: [PATCH 2465/4847] Fix issue with comment grouping Previously, we were not grouping comments correctly if there were multiple pages of comments. The best approach we found was to wait until we have all reviews and all comments, and then group them by root comment ID. Co-Authored-By: Katrina Uychaco --- .../issueishDetailContainerQuery.graphql.js | 5 +- .../prReviewCommentsContainerQuery.graphql.js | 12 ++- ...rReviewCommentsContainer_review.graphql.js | 10 ++- .../prReviewsContainerQuery.graphql.js | 5 +- .../pr-review-comments-container.js | 9 ++- lib/controllers/pr-reviews-controller.js | 73 ++++++++++++------- .../prDetailViewRefetchQuery.graphql.js | 5 +- 7 files changed, 80 insertions(+), 39 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 6f0b3544a4..0ee982a7d9 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 8593181024464fe44267e78f2c66b059 + * @relayHash 86a6d997a1bfd3d4f567397ecdaa752b */ /* eslint-disable */ @@ -540,6 +540,7 @@ fragment prCommitView_item on Commit { fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { id + submittedAt comments(first: $commentCount, after: $commentCursor) { pageInfo { hasNextPage @@ -1206,7 +1207,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", diff --git a/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js index 6fc33f5de0..0904ea42ba 100644 --- a/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash aa28e03673267c061792b18ed9e13038 + * @relayHash 5e0b465f16f55322d70100cd893a1c04 */ /* eslint-disable */ @@ -44,6 +44,7 @@ query prReviewCommentsContainerQuery( fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { id + submittedAt comments(first: $commentCount, after: $commentCursor) { pageInfo { hasNextPage @@ -138,7 +139,7 @@ return { "operationKind": "query", "name": "prReviewCommentsContainerQuery", "id": null, - "text": "query prReviewCommentsContainerQuery(\n $commentCount: Int!\n $commentCursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequestReview {\n ...prReviewCommentsContainer_review_1VbUmL\n }\n id\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "text": "query prReviewCommentsContainerQuery(\n $commentCount: Int!\n $commentCursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequestReview {\n ...prReviewCommentsContainer_review_1VbUmL\n }\n id\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -204,6 +205,13 @@ return { "kind": "InlineFragment", "type": "PullRequestReview", "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "submittedAt", + "args": null, + "storageKey": null + }, { "kind": "LinkedField", "alias": null, diff --git a/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js b/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js index 7f1b8d16e1..aec8134452 100644 --- a/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js +++ b/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js @@ -12,6 +12,7 @@ import type { FragmentReference } from "relay-runtime"; declare export opaque type prReviewCommentsContainer_review$ref: FragmentReference; export type prReviewCommentsContainer_review = {| +id: string, + +submittedAt: ?any, +comments: {| +pageInfo: {| +hasNextPage: boolean, @@ -81,6 +82,13 @@ return { ], "selections": [ v0, + { + "kind": "ScalarField", + "alias": null, + "name": "submittedAt", + "args": null, + "storageKey": null + }, { "kind": "LinkedField", "alias": "comments", @@ -230,5 +238,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'd2db363653fb73e8f4d019026668babc'; +(node/*: any*/).hash = '63492273ddd049ed59809581c7795811'; module.exports = node; diff --git a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js index 63254fbff3..7e64650ea5 100644 --- a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash a2fda52ce9272b72cf214c6bcd70719a + * @relayHash 455845bc2fe2987a2c32d72dbc9247b6 */ /* eslint-disable */ @@ -89,6 +89,7 @@ fragment prReviewsContainer_pullRequest_y4qc0 on PullRequest { fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { id + submittedAt comments(first: $commentCount, after: $commentCursor) { pageInfo { hasNextPage @@ -262,7 +263,7 @@ return { "operationKind": "query", "name": "prReviewsContainerQuery", "id": null, - "text": "query prReviewsContainerQuery(\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_y4qc0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "text": "query prReviewsContainerQuery(\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_y4qc0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index d1e8789740..67151ff784 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -7,9 +7,10 @@ import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../helpers'; export class BarePullRequestReviewCommentsContainer extends React.Component { static propTypes = { - aggregateComments: PropTypes.func.isRequired, + collectComments: PropTypes.func.isRequired, review: PropTypes.shape({ id: PropTypes.string.isRequired, + submittedAt: PropTypes.string.isRequired, comments: PropTypes.arrayOf(PropTypes.object).isRequired, }), relay: PropTypes.shape({ @@ -20,14 +21,17 @@ export class BarePullRequestReviewCommentsContainer extends React.Component { } componentDidMount() { - this.props.aggregateComments(this.props.review.id, this.props.review.comments); this._attemptToLoadMoreComments(); + const {submittedAt, comments, id} = this.props.review; + this.props.collectComments({reviewId: id, submittedAt, comments, hasMore: this.props.relay.hasMore()}); } _loadMoreComments = () => { this.props.relay.loadMore( PAGE_SIZE, error => { + const {submittedAt, comments, id} = this.props.review; + this.props.collectComments({reviewId: id, submittedAt, comments, hasMore: this.props.relay.hasMore()}); this._attemptToLoadMoreComments(); if (error) { // eslint-disable-next-line no-console @@ -64,6 +68,7 @@ export default createPaginationContainer(BarePullRequestReviewCommentsContainer, commentCursor: {type: "String"} ) { id + submittedAt comments( first: $commentCount, after: $commentCursor diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 963c9d33bf..dca64a9bfa 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -24,6 +24,7 @@ export default class PullRequestReviewsController extends React.Component { constructor(props) { super(props); this.state = {}; + this.reviewsById = new Map(); } componentDidMount() { @@ -57,40 +58,15 @@ export default class PullRequestReviewsController extends React.Component { } } - aggregateComments = (reviewId, comments) => { - // react batches calls to setState and does not update state synchronously - // therefore we need an intermediate state so we can do checks against keys - // we have just added. - const state = this.state; - comments.edges.forEach(({node}) => { - const comment = node; - if (!comment.replyTo) { - state[comment.id] = [comment]; - } else { - // When comment being replied to is outdated...?? Not 100% sure... - // Why would we even get an outdated comment or a response to one here? - // Ran into this error when viewing files for https://github.com/numpy/numpy/pull/9998 - // for comment MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE1MzA1NTUzMw, - // who's replyTo comment is an outdated comment - if (!state[comment.replyTo.id]) { - state[comment.id] = [comment]; - } else { - state[comment.replyTo.id].push(comment); - } - } - }); - this.setState(state); - } - renderCommentFetchingContainers() { - // Aggregate comments from all reviews - return this.props.pullRequest.reviews.edges.map(({node}) => { + this.props.pullRequest.reviews.edges.map(({node}) => { const review = node; + return ( ); }); @@ -124,4 +100,45 @@ export default class PullRequestReviewsController extends React.Component { ); } + + collectComments = ({reviewId, submittedAt, comments, hasMore}) => { + this.reviewsById.set(reviewId, {submittedAt, comments, hasMore}); + const noMoreReviewsToFetch = !this.props.relay.hasMore(); + if (noMoreReviewsToFetch) { + const noMoreCommentsToFetch = [...this.reviewsById.values()].every(review => !review.hasMore) + if (noMoreCommentsToFetch) { + this.groupCommentsByThread(); + } + } + } + + groupCommentsByThread() { + // TODO make sure they're sorted according to submitted at + + // react batches calls to setState and does not update state synchronously + // therefore we need an intermediate state so we can do checks against keys + // we have just added. + const state = {}; + [...this.reviewsById.values()].forEach(({comments}) => { + comments.edges.forEach(({node}) => { + const comment = node; + if (!comment.replyTo) { + state[comment.id] = [comment]; + } else { + // When comment being replied to is outdated...?? Not 100% sure... + // Why would we even get an outdated comment or a response to one here? + // Ran into this error when viewing files for https://github.com/numpy/numpy/pull/9998 + // for comment MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE1MzA1NTUzMw, + // who's replyTo comment is an outdated comment + if (!state[comment.replyTo.id]) { + state[comment.id] = [comment]; + } else { + state[comment.replyTo.id].push(comment); + } + } + }); + }) + + this.setState(state); + } } diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index d75b7040e7..8b5d424baa 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 7e3a37960cf0fb44d162883d95c9838d + * @relayHash 631a28049723f0b6b8a3f8eb25a4f955 */ /* eslint-disable */ @@ -456,6 +456,7 @@ fragment prCommitView_item on Commit { fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { id + submittedAt comments(first: $commentCount, after: $commentCursor) { pageInfo { hasNextPage @@ -884,7 +885,7 @@ return { "operationKind": "query", "name": "prDetailViewRefetchQuery", "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", From 033c18d4744a6e06ce7a1d257481686d4ddef752 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 3 Jan 2019 15:59:39 -0800 Subject: [PATCH 2466/4847] render helpers actually need to return some jsx, dawg --- lib/controllers/pr-reviews-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index dca64a9bfa..6dc8050e23 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -59,7 +59,7 @@ export default class PullRequestReviewsController extends React.Component { } renderCommentFetchingContainers() { - this.props.pullRequest.reviews.edges.map(({node}) => { + return this.props.pullRequest.reviews.edges.map(({node}) => { const review = node; return ( From 065c78bff8d060a2d7efa36bedcc4090ecbfd8b6 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 3 Jan 2019 16:21:52 -0800 Subject: [PATCH 2467/4847] sort reviews by date --- lib/controllers/pr-reviews-controller.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 6dc8050e23..c5976e1a58 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -113,13 +113,24 @@ export default class PullRequestReviewsController extends React.Component { } groupCommentsByThread() { - // TODO make sure they're sorted according to submitted at + // we have no guarantees that reviews will return in order so sort them by date. + const sortedReviews = [...this.reviewsById.values()].sort((a, b) => { + const dateA = new Date(a.submittedAt); + const dateB = new Date(b.submittedAt); + if (dateA > dateB) { + return 1; + } else if (dateB > dateA) { + return -1; + } else { + return 0; + } + }); // react batches calls to setState and does not update state synchronously // therefore we need an intermediate state so we can do checks against keys // we have just added. const state = {}; - [...this.reviewsById.values()].forEach(({comments}) => { + sortedReviews.forEach(({comments}) => { comments.edges.forEach(({node}) => { const comment = node; if (!comment.replyTo) { From be7659698210dbd43742919ea6ab949099ce92b0 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 3 Jan 2019 16:26:31 -0800 Subject: [PATCH 2468/4847] :art: move sort comparator to be its own function --- lib/controllers/pr-reviews-controller.js | 25 +++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index c5976e1a58..f70ef509ea 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -101,6 +101,19 @@ export default class PullRequestReviewsController extends React.Component { ); } + // sorts reviews by date ascending (oldest to newest) + sortComparator(a, b) { + const dateA = new Date(a.submittedAt); + const dateB = new Date(b.submittedAt); + if (dateA > dateB) { + return 1; + } else if (dateB > dateA) { + return -1; + } else { + return 0; + } + } + collectComments = ({reviewId, submittedAt, comments, hasMore}) => { this.reviewsById.set(reviewId, {submittedAt, comments, hasMore}); const noMoreReviewsToFetch = !this.props.relay.hasMore(); @@ -114,17 +127,7 @@ export default class PullRequestReviewsController extends React.Component { groupCommentsByThread() { // we have no guarantees that reviews will return in order so sort them by date. - const sortedReviews = [...this.reviewsById.values()].sort((a, b) => { - const dateA = new Date(a.submittedAt); - const dateB = new Date(b.submittedAt); - if (dateA > dateB) { - return 1; - } else if (dateB > dateA) { - return -1; - } else { - return 0; - } - }); + const sortedReviews = [...this.reviewsById.values()].sort(this.sortComparator); // react batches calls to setState and does not update state synchronously // therefore we need an intermediate state so we can do checks against keys From 5706820aaca0a9ed2ed1eaf332af088f447de365 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 3 Jan 2019 16:30:12 -0800 Subject: [PATCH 2469/4847] :shirt: --- lib/controllers/pr-reviews-controller.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index f70ef509ea..282793e740 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -109,8 +109,8 @@ export default class PullRequestReviewsController extends React.Component { return 1; } else if (dateB > dateA) { return -1; - } else { - return 0; + } else { + return 0; } } @@ -118,7 +118,7 @@ export default class PullRequestReviewsController extends React.Component { this.reviewsById.set(reviewId, {submittedAt, comments, hasMore}); const noMoreReviewsToFetch = !this.props.relay.hasMore(); if (noMoreReviewsToFetch) { - const noMoreCommentsToFetch = [...this.reviewsById.values()].every(review => !review.hasMore) + const noMoreCommentsToFetch = [...this.reviewsById.values()].every(review => !review.hasMore); if (noMoreCommentsToFetch) { this.groupCommentsByThread(); } @@ -151,7 +151,7 @@ export default class PullRequestReviewsController extends React.Component { } } }); - }) + }); this.setState(state); } From 1c9912003d732c77d54b2ef24dae93f2e1b76ddb Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 3 Jan 2019 16:32:03 -0800 Subject: [PATCH 2470/4847] to the PropTypes mobile, batman!! --- lib/containers/pr-review-comments-container.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 67151ff784..5e5f0f24c1 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -11,7 +11,7 @@ export class BarePullRequestReviewCommentsContainer extends React.Component { review: PropTypes.shape({ id: PropTypes.string.isRequired, submittedAt: PropTypes.string.isRequired, - comments: PropTypes.arrayOf(PropTypes.object).isRequired, + comments: PropTypes.object.isRequired, }), relay: PropTypes.shape({ hasMore: PropTypes.func.isRequired, From 915947102ffeee6667ee957f24349ba5159cefce Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 3 Jan 2019 17:02:30 -0800 Subject: [PATCH 2471/4847] add some tests for `PullRequestReviewCommentsContainer` --- .../pr-review-comments-container.test.js | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 test/containers/pr-review-comments-container.test.js diff --git a/test/containers/pr-review-comments-container.test.js b/test/containers/pr-review-comments-container.test.js new file mode 100644 index 0000000000..fe83100f18 --- /dev/null +++ b/test/containers/pr-review-comments-container.test.js @@ -0,0 +1,72 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import {BarePullRequestReviewCommentsContainer} from '../../lib/containers/pr-review-comments-container'; + +describe('PullRequestReviewCommentsContainer', function() { + function buildApp(opts, overrideProps = {}) { + const o = { + relayHasMore: () => { return false; }, + relayLoadMore: () => {}, + relayIsLoading: () => { return false; }, + ...opts, + }; + + const props = { + relay: { + hasMore: o.relayHasMore, + loadMore: o.relayLoadMore, + isLoading: o.relayIsLoading, + }, + collectComments: () => {}, + review: { + id: '123', + submittedAt: '2018-12-27T20:40:55Z', + comments: {edges: ['this kiki is marvelous']}, + }, + ...overrideProps, + }; + return ; + } + it('aggregates the comments after component has been mounted', function() { + const collectCommentsStub = sinon.stub(); + shallow(buildApp({}, {collectComments: collectCommentsStub})); + assert.strictEqual(collectCommentsStub.callCount, 1); + const args = collectCommentsStub.lastCall.args[0]; + + assert.strictEqual(args.reviewId, '123'); + assert.strictEqual(args.submittedAt, '2018-12-27T20:40:55Z'); + assert.deepEqual(args.comments, {edges: ['this kiki is marvelous']}); + assert.isFalse(args.hasMore); + }); + + it('attempts to load comments after component has been mounted', function() { + const wrapper = shallow(buildApp()); + sinon.stub(wrapper.instance(), '_attemptToLoadMoreComments'); + wrapper.instance().componentDidMount(); + + }); + + + describe('loadMoreComments', function() { + it('calls this.props.relay.loadMore with correct arguments', function() { + }); + }); + + it('handles errors', function() { + + }); + + describe('attemptToLoadMoreComments', function() { + it('does not call loadMore if hasMore prop is falsy', function() { + }); + + it('calls loadMore immediately if not already loading more', function() { + }); + + it('if already loading more, calls loadMore after a timeout', function() { + }); + + }); + +}); From 3f61b5dea358101c882d83820e3408df0448f981 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 3 Jan 2019 17:57:09 -0800 Subject: [PATCH 2472/4847] add some more tests for PullRequestReviewCommentsContainer Co-Authored-By: Katrina Uychaco --- .../pr-review-comments-container.test.js | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/test/containers/pr-review-comments-container.test.js b/test/containers/pr-review-comments-container.test.js index fe83100f18..d37df302fc 100644 --- a/test/containers/pr-review-comments-container.test.js +++ b/test/containers/pr-review-comments-container.test.js @@ -1,6 +1,8 @@ import React from 'react'; import {shallow} from 'enzyme'; +import {PAGE_SIZE} from '../../lib/helpers'; + import {BarePullRequestReviewCommentsContainer} from '../../lib/containers/pr-review-comments-container'; describe('PullRequestReviewCommentsContainer', function() { @@ -28,7 +30,7 @@ describe('PullRequestReviewCommentsContainer', function() { }; return ; } - it('aggregates the comments after component has been mounted', function() { + it('collects the comments after component has been mounted', function() { const collectCommentsStub = sinon.stub(); shallow(buildApp({}, {collectComments: collectCommentsStub})); assert.strictEqual(collectCommentsStub.callCount, 1); @@ -44,19 +46,48 @@ describe('PullRequestReviewCommentsContainer', function() { const wrapper = shallow(buildApp()); sinon.stub(wrapper.instance(), '_attemptToLoadMoreComments'); wrapper.instance().componentDidMount(); - + assert.strictEqual(wrapper.instance()._attemptToLoadMoreComments.callCount, 1); }); describe('loadMoreComments', function() { - it('calls this.props.relay.loadMore with correct arguments', function() { + it('calls this.props.relay.loadMore with correct args', function() { + const relayLoadMoreStub = sinon.stub(); + const wrapper = shallow(buildApp({relayLoadMore: relayLoadMoreStub})); + wrapper.instance()._loadMoreComments(); + + const args = relayLoadMoreStub.lastCall.args; + assert.strictEqual(args[0], PAGE_SIZE); + assert.strictEqual(args[1], wrapper.instance().onDidLoadMore); }); }); - it('handles errors', function() { + describe('onDidLoadMore', function() { + it('collects comments and attempts to load more comments', function() { + const collectCommentsStub = sinon.stub(); + const wrapper = shallow(buildApp({}, {collectComments: collectCommentsStub})); + // collect comments is called when mounted, we don't care about that in this test so reset the count + collectCommentsStub.reset(); + sinon.stub(wrapper.instance(), '_attemptToLoadMoreComments'); + wrapper.instance().onDidLoadMore(); + + assert.strictEqual(collectCommentsStub.callCount, 1); + const args = collectCommentsStub.lastCall.args[0]; + + assert.strictEqual(args.reviewId, '123'); + assert.strictEqual(args.submittedAt, '2018-12-27T20:40:55Z'); + assert.deepEqual(args.comments, {edges: ['this kiki is marvelous']}); + assert.isFalse(args.hasMore); + }); + + it('handles errors', function() { + + }); + }); + describe('attemptToLoadMoreComments', function() { it('does not call loadMore if hasMore prop is falsy', function() { }); From 968ad4da85012601231f8f9d201d6bdba4854667 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 4 Jan 2019 20:07:55 +0900 Subject: [PATCH 2473/4847] Put comments into boxes --- styles/pr-comment.less | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/styles/pr-comment.less b/styles/pr-comment.less index 65887aef25..f2ff654985 100644 --- a/styles/pr-comment.less +++ b/styles/pr-comment.less @@ -1,30 +1,45 @@ @import 'variables'; @avatar-size: 16px; +@avatar-spacing: 6px; .github-PrCommentThread { - padding: @component-padding/2 0; - border-bottom: 1px solid @base-border-color; + padding: @component-padding 0; } .github-PrComment { max-width: 60em; - margin: @component-padding 0; - padding-right: @component-padding*2; + padding: @component-padding; font-family: @font-family; font-size: @font-size; + border: 1px solid @base-border-color; + + &:first-child { + border-top-left-radius: @component-border-radius; + border-top-right-radius: @component-border-radius; + } + &:last-child { + border-bottom-left-radius: @component-border-radius; + border-bottom-right-radius: @component-border-radius; + } + + & + .github-PrComment { + border-top: none; + } &-header { color: @text-color-subtle; + line-height: @avatar-size; } &-avatar { - margin-right: 4px; + margin-right: @avatar-spacing; height: @avatar-size; width: @avatar-size; border-radius: @component-border-radius; + vertical-align: top; } &-timeAgo { @@ -32,7 +47,7 @@ } &-body { - margin-left: @avatar-size + 4px; // avatar + margin + margin-left: @avatar-size + @avatar-spacing; // avatar + margin } } From c4ee2dd8704e2b18473389b1ad62ae02295c1a8e Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Fri, 4 Jan 2019 12:49:01 +0000 Subject: [PATCH 2474/4847] fix(package): update react-tabs to version 3.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b5fd068b65..087d28235f 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "react-dom": "16.4.0", "react-relay": "1.6.0", "react-select": "1.2.1", - "react-tabs": "^2.3.0", + "react-tabs": "^3.0.0", "relay-runtime": "1.6.0", "temp": "0.9.0", "tinycolor2": "1.4.1", From 65fbf592bdd95fb706b0d9710c3644fd66eec9a4 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Fri, 4 Jan 2019 12:49:05 +0000 Subject: [PATCH 2475/4847] chore(package): update lockfile package-lock.json --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76cc2d0cbe..1fcba091f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6550,9 +6550,9 @@ } }, "react-tabs": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-2.3.0.tgz", - "integrity": "sha512-pYaefgVy76/36AMEP+B8YuVVzDHa3C5UFZ3REU78zolk0qMxEhKvUFofvDCXyLZwf0RZjxIfiwok1BEb18nHyA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-3.0.0.tgz", + "integrity": "sha512-z90cDIb+5V7MzjXFHq1VLxYiMH7dDQWan7mXSw6BWQtw+9pYAnq/fEDvsPaXNyevYitvLetdW87C61uu27JVMA==", "requires": { "classnames": "^2.2.0", "prop-types": "^15.5.0" From b36f05bcca7fd71671305dff5473c26ed9d818e7 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 4 Jan 2019 10:58:45 -0800 Subject: [PATCH 2476/4847] import PAGE_SIZE in `IssueishDetailContainer` tests --- test/containers/issueish-detail-container.test.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/containers/issueish-detail-container.test.js b/test/containers/issueish-detail-container.test.js index 934f24df9f..d8323e8f89 100644 --- a/test/containers/issueish-detail-container.test.js +++ b/test/containers/issueish-detail-container.test.js @@ -5,6 +5,7 @@ import {cloneRepository, buildRepository} from '../helpers'; import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import {issueishDetailContainerProps} from '../fixtures/props/issueish-pane-props'; import {createPullRequestDetailResult} from '../fixtures/factories/pull-request-result'; +import {PAGE_SIZE} from '../../lib/helpers'; import GithubLoginModel from '../../lib/models/github-login-model'; import {InMemoryStrategy, UNAUTHENTICATED} from '../../lib/shared/keytar-strategy'; import IssueishDetailContainer from '../../lib/containers/issueish-detail-container'; @@ -26,12 +27,14 @@ describe('IssueishDetailContainer', function() { repoOwner: 'owner', repoName: 'repo', issueishNumber: 1, - timelineCount: 100, + timelineCount: PAGE_SIZE, timelineCursor: null, - commitCount: 100, + commitCount: PAGE_SIZE, commitCursor: null, - commentCount: 100, + commentCount: PAGE_SIZE, commentCursor: null, + reviewCount: PAGE_SIZE, + reviewCursor: null, }, }, { repository: { From bf3d4c17f842059ee0eaf78bb0c3087159a66f7f Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 4 Jan 2019 11:02:08 -0800 Subject: [PATCH 2477/4847] import PAGE_SIXE in checkout pr integration tests --- test/integration/checkout-pr.test.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/integration/checkout-pr.test.js b/test/integration/checkout-pr.test.js index a15a1adced..6509d22b8a 100644 --- a/test/integration/checkout-pr.test.js +++ b/test/integration/checkout-pr.test.js @@ -2,6 +2,7 @@ import hock from 'hock'; import http from 'http'; import {setup, teardown} from './helpers'; +import {PAGE_SIZE} from '../../lib/helpers'; import {expectRelayQuery} from '../../lib/relay-network-layer-manager'; import GitShellOutStrategy from '../../lib/git-shell-out-strategy'; import {createRepositoryResult} from '../fixtures/factories/repository-result'; @@ -136,11 +137,13 @@ describe('integration: check out a pull request', function() { repoOwner: 'owner', repoName: 'repo', issueishNumber: 1, - timelineCount: 100, + timelineCount: PAGE_SIZE, timelineCursor: null, - commitCount: 100, + commitCount: PAGE_SIZE, commitCursor: null, - commentCount: 100, + reviewCount: PAGE_SIZE, + reviewCursor: null, + commentCount: PAGE_SIZE, commentCursor: null, }, }, result); From e927e76c1c67819762785074a4e7952b590493ed Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 4 Jan 2019 11:07:32 -0800 Subject: [PATCH 2478/4847] extract callback into its own function for better testability Co-Authored-By: Katrina Uychaco --- .../pr-review-comments-container.js | 20 ++++++++++--------- .../pr-review-comments-container.test.js | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 5e5f0f24c1..885da598ff 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -26,18 +26,20 @@ export class BarePullRequestReviewCommentsContainer extends React.Component { this.props.collectComments({reviewId: id, submittedAt, comments, hasMore: this.props.relay.hasMore()}); } + onDidLoadMore = error => { + const {submittedAt, comments, id} = this.props.review; + this.props.collectComments({reviewId: id, submittedAt, comments, hasMore: this.props.relay.hasMore()}); + this._attemptToLoadMoreComments(); + if (error) { + // eslint-disable-next-line no-console + console.error(error); + } + } + _loadMoreComments = () => { this.props.relay.loadMore( PAGE_SIZE, - error => { - const {submittedAt, comments, id} = this.props.review; - this.props.collectComments({reviewId: id, submittedAt, comments, hasMore: this.props.relay.hasMore()}); - this._attemptToLoadMoreComments(); - if (error) { - // eslint-disable-next-line no-console - console.error(error); - } - }, + this.onDidLoadMore, ); } diff --git a/test/containers/pr-review-comments-container.test.js b/test/containers/pr-review-comments-container.test.js index d37df302fc..c9477a195c 100644 --- a/test/containers/pr-review-comments-container.test.js +++ b/test/containers/pr-review-comments-container.test.js @@ -89,7 +89,7 @@ describe('PullRequestReviewCommentsContainer', function() { describe('attemptToLoadMoreComments', function() { - it('does not call loadMore if hasMore prop is falsy', function() { + it('does not call loadMore if hasMore is false', function() { }); it('calls loadMore immediately if not already loading more', function() { From 1c60c1e74d5ab3daf2e41120c25c534ef802a171 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 4 Jan 2019 14:57:01 -0500 Subject: [PATCH 2479/4847] :arrow_up: react and react-dom --- package-lock.json | 42 ++++++++++++++++++++++++++++++++---------- package.json | 4 ++-- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76cc2d0cbe..c0f3b89033 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6461,25 +6461,47 @@ } }, "react": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.4.0.tgz", - "integrity": "sha512-K0UrkLXSAekf5nJu89obKUM7o2vc6MMN9LYoKnCa+c+8MJRAT120xzPLENcWSRc7GYKIg0LlgJRDorrufdglQQ==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.7.0.tgz", + "integrity": "sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==", "requires": { - "fbjs": "^0.8.16", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "prop-types": "^15.6.2", + "scheduler": "^0.12.0" + }, + "dependencies": { + "scheduler": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz", + "integrity": "sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + } } }, "react-dom": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.0.tgz", - "integrity": "sha512-bbLd+HYpBEnYoNyxDe9XpSG2t9wypMohwQPvKw8Hov3nF7SJiJIgK56b46zHpBUpHb06a1iEuw7G3rbrsnNL6w==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.7.0.tgz", + "integrity": "sha512-D0Ufv1ExCAmF38P2Uh1lwpminZFRXEINJe53zRAbm4KPwSyd6DY/uDoS0Blj9jvPpn1+wivKpZYc8aAAN/nAkg==", "requires": { - "fbjs": "^0.8.16", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "prop-types": "^15.6.2", + "scheduler": "^0.12.0" + }, + "dependencies": { + "scheduler": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz", + "integrity": "sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + } } }, "react-input-autosize": { diff --git a/package.json b/package.json index b5fd068b65..67c2ff5a0f 100644 --- a/package.json +++ b/package.json @@ -59,8 +59,8 @@ "moment": "2.22.2", "node-emoji": "^1.8.1", "prop-types": "15.6.2", - "react": "16.4.0", - "react-dom": "16.4.0", + "react": "16.7.0", + "react-dom": "16.7.0", "react-relay": "1.6.0", "react-select": "1.2.1", "react-tabs": "^2.3.0", From 415435ea0fb2a8232b4251f4cb13c4cf8984fc7d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 4 Jan 2019 15:09:13 -0500 Subject: [PATCH 2480/4847] Lock electron-mksnapshot to the version used in Atom --- package-lock.json | 20 ++++++++++---------- package.json | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 390a2f75e5..4e76304d5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2650,9 +2650,9 @@ }, "dependencies": { "debug": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", - "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -2691,9 +2691,9 @@ } }, "electron-mksnapshot": { - "version": "3.0.0-beta.1", - "resolved": "https://registry.npmjs.org/electron-mksnapshot/-/electron-mksnapshot-3.0.0-beta.1.tgz", - "integrity": "sha512-0Q4yV7jCnXiCFOAih8ZvmFBS492kPzQYtsIj30pVyWsytAEyxmyPQD5NbSAaAAJt5di2XocxfvbAEgcAhUXEqA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/electron-mksnapshot/-/electron-mksnapshot-2.0.0.tgz", + "integrity": "sha512-OoZwZJNKgHP+DwhCGVTJEuDSeb478hOzAbHeg7dKGCHDbKKmUWmjGc+pEjxGutpqQ3Mn8hCdLzdx2c/lAJcTLA==", "dev": true, "requires": { "electron-download": "^4.1.0", @@ -6340,7 +6340,7 @@ }, "pretty-bytes": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "resolved": "http://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", "dev": true, "requires": { @@ -7176,7 +7176,7 @@ "dependencies": { "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -7898,7 +7898,7 @@ }, "through2": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.2.3.tgz", "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", "dev": true, "requires": { @@ -7926,7 +7926,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, diff --git a/package.json b/package.json index b2f0b0ca8f..127f8160c0 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "dedent-js": "1.0.1", "electron-devtools-installer": "2.2.4", "electron-link": "0.3.2", - "electron-mksnapshot": "3.0.0-beta.1", + "electron-mksnapshot": "~2.0", "enzyme": "3.8.0", "enzyme-adapter-react-16": "1.7.1", "eslint": "5.0.1", From fd590c2d18a7072a6726f350983fdca22353e7d1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 4 Jan 2019 15:09:25 -0500 Subject: [PATCH 2481/4847] Ignore updates to electron-link and electron-mksnapshot --- package.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package.json b/package.json index 127f8160c0..52d475cf19 100644 --- a/package.json +++ b/package.json @@ -204,5 +204,11 @@ "FilePatchControllerStub": "createFilePatchControllerStub", "CommitPreviewStub": "createCommitPreviewStub", "CommitDetailStub": "createCommitDetailStub" + }, + "greenkeeper": { + "ignore": [ + "electron-link", + "electron-mksnapshot" + ] } } From 083c048b726f14964b9e4c3b5dd04c4047ffc6c3 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 4 Jan 2019 13:45:36 -0800 Subject: [PATCH 2482/4847] moar tests for `PullRequestReviewCommentsContainer` --- .../pr-review-comments-container.test.js | 48 +++++++++++++++++-- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/test/containers/pr-review-comments-container.test.js b/test/containers/pr-review-comments-container.test.js index c9477a195c..342909610f 100644 --- a/test/containers/pr-review-comments-container.test.js +++ b/test/containers/pr-review-comments-container.test.js @@ -1,7 +1,7 @@ import React from 'react'; import {shallow} from 'enzyme'; -import {PAGE_SIZE} from '../../lib/helpers'; +import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../../lib/helpers'; import {BarePullRequestReviewCommentsContainer} from '../../lib/containers/pr-review-comments-container'; @@ -89,15 +89,53 @@ describe('PullRequestReviewCommentsContainer', function() { describe('attemptToLoadMoreComments', function() { - it('does not call loadMore if hasMore is false', function() { + let clock; + beforeEach(function() { + clock = sinon.useFakeTimers(); + }); + afterEach(function() { + clock = sinon.restore(); }); + it('does not call loadMore if hasMore is false', function() { + const relayLoadMoreStub = sinon.stub(); + const wrapper = shallow(buildApp({relayLoadMore: relayLoadMoreStub})); + relayLoadMoreStub.reset(); - it('calls loadMore immediately if not already loading more', function() { + wrapper.instance()._attemptToLoadMoreComments(); + assert.strictEqual(relayLoadMoreStub.callCount, 0); }); - it('if already loading more, calls loadMore after a timeout', function() { + it('calls loadMore immediately if hasMore is true and isLoading is false', function() { + const relayLoadMoreStub = sinon.stub(); + const relayHasMore = () => { return true; }; + const wrapper = shallow(buildApp({relayHasMore, relayLoadMore: relayLoadMoreStub})); + relayLoadMoreStub.reset(); + + wrapper.instance()._attemptToLoadMoreComments(); + assert.strictEqual(relayLoadMoreStub.callCount, 1); + const args = relayLoadMoreStub.lastCall.args; + assert.strictEqual(args[0], PAGE_SIZE); + assert.strictEqual(args[1], wrapper.instance().onDidLoadMore); }); + it('calls loadMore after a timeout if hasMore is true and isLoading is true', function() { + const relayLoadMoreStub = sinon.stub(); + const relayHasMore = () => { return true; }; + const relayIsLoading = () => { return true; }; + const wrapper = shallow(buildApp({relayHasMore, relayIsLoading, relayLoadMore: relayLoadMoreStub})); + // advancing the timer and resetting the stub to clear the initial calls of + // _attemptToLoadMoreComments when the component is initially mounted. + clock.tick(PAGINATION_WAIT_TIME_MS); + relayLoadMoreStub.reset(); + + wrapper.instance()._attemptToLoadMoreComments(); + assert.strictEqual(relayLoadMoreStub.callCount, 0); + + clock.tick(PAGINATION_WAIT_TIME_MS); + assert.strictEqual(relayLoadMoreStub.callCount, 1); + const args = relayLoadMoreStub.lastCall.args; + assert.strictEqual(args[0], PAGE_SIZE); + assert.strictEqual(args[1], wrapper.instance().onDidLoadMore); + }); }); - }); From 1e24ba2287f0224a7e4971f546d2181ac602efee Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 4 Jan 2019 13:45:47 -0800 Subject: [PATCH 2483/4847] :fire: unnecessary arrow function --- lib/containers/pr-review-comments-container.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 885da598ff..72cda3b23f 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -49,9 +49,7 @@ export class BarePullRequestReviewCommentsContainer extends React.Component { } if (this.props.relay.isLoading()) { - setTimeout(() => { - this._loadMoreComments(); - }, PAGINATION_WAIT_TIME_MS); + setTimeout(this._loadMoreComments, PAGINATION_WAIT_TIME_MS); } else { this._loadMoreComments(); } From 5f15a181c96a62a1e804d3fd53eee8c46687b96e Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 4 Jan 2019 14:00:32 -0800 Subject: [PATCH 2484/4847] we don't need that other arrow function either --- lib/controllers/pr-reviews-controller.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 282793e740..f95135643a 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -50,9 +50,7 @@ export default class PullRequestReviewsController extends React.Component { } if (this.props.relay.isLoading()) { - setTimeout(() => { - this._loadMoreReviews(); - }, PAGINATION_WAIT_TIME_MS); + setTimeout(this._loadMoreReviews, PAGINATION_WAIT_TIME_MS); } else { this._loadMoreReviews(); } From cdc717f69361d67e632bcda72bf395a2db6173de Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 4 Jan 2019 14:21:07 -0800 Subject: [PATCH 2485/4847] pass getBufferRowForDiffPosition function as a prop we don't really need the entire multiFilePatch, dawg. --- lib/controllers/pr-reviews-controller.js | 2 +- lib/models/patch/multi-file-patch.js | 2 +- lib/views/multi-file-patch-view.js | 2 +- lib/views/pr-review-comments-view.js | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index f95135643a..85d9687cae 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -18,7 +18,7 @@ export default class PullRequestReviewsController extends React.Component { PropTypes.object, ), }), - multiFilePatch: PropTypes.object.isRequired, + getBufferRowForDiffPosition: PropTypes.func.isRequired, } constructor(props) { diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 132573214d..e04a498416 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -339,7 +339,7 @@ export default class MultiFilePatch { return false; } - getBufferRowForDiffPosition(fileName, diffRow) { + getBufferRowForDiffPosition = (fileName, diffRow) => { // TODO verify that this works on Windows const {startBufferRow, index} = this.diffRowOffsetIndices.get(fileName); const {offset} = index.lowerBound({diffRow}).data(); diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 80e46a0b86..9d0655b770 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -318,7 +318,7 @@ export default class MultiFilePatchView extends React.Component { return ( ); } else { diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index ea926a730d..7eb1276902 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -19,7 +19,7 @@ export default class PullRequestCommentsView extends React.Component { rootCommentId: PropTypes.string.isRequired, comments: PropTypes.arrayOf(PropTypes.object).isRequired, })), - multiFilePatch: PropTypes.object.isRequired, + getBufferRowForDiffPosition: PropTypes.func.isRequired, switchToIssueish: PropTypes.func.isRequired, } @@ -31,7 +31,7 @@ export default class PullRequestCommentsView extends React.Component { } const nativePath = toNativePathSep(rootComment.path); - const row = this.props.multiFilePatch.getBufferRowForDiffPosition(nativePath, rootComment.position); + const row = this.props.getBufferRowForDiffPosition(nativePath, rootComment.position); const point = new Point(row, 0); const range = new Range(point, point); return ( From 33a79c25cb7aa89c091ec900e7cbee824be11640 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 17:23:06 -0800 Subject: [PATCH 2486/4847] Istanbul ignore if statements that handle errors when loading more pages Co-Authored-By: Tilde Ann Thurium --- lib/containers/pr-review-comments-container.js | 2 ++ lib/controllers/pr-reviews-controller.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 72cda3b23f..9b3138f1fd 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -30,6 +30,8 @@ export class BarePullRequestReviewCommentsContainer extends React.Component { const {submittedAt, comments, id} = this.props.review; this.props.collectComments({reviewId: id, submittedAt, comments, hasMore: this.props.relay.hasMore()}); this._attemptToLoadMoreComments(); + + /* istanbul ignore if */ if (error) { // eslint-disable-next-line no-console console.error(error); diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 85d9687cae..62262e9130 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -36,6 +36,8 @@ export default class PullRequestReviewsController extends React.Component { PAGE_SIZE, error => { this._attemptToLoadMoreReviews(); + + /* istanbul ignore if */ if (error) { // eslint-disable-next-line no-console console.error(error); From d913c9fb8de6180836808365f7b627aff506c53d Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 17:24:13 -0800 Subject: [PATCH 2487/4847] :fire: unnecessary test for error handling Co-Authored-By: Tilde Ann Thurium --- test/containers/pr-review-comments-container.test.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/test/containers/pr-review-comments-container.test.js b/test/containers/pr-review-comments-container.test.js index 342909610f..d690000057 100644 --- a/test/containers/pr-review-comments-container.test.js +++ b/test/containers/pr-review-comments-container.test.js @@ -30,6 +30,7 @@ describe('PullRequestReviewCommentsContainer', function() { }; return ; } + it('collects the comments after component has been mounted', function() { const collectCommentsStub = sinon.stub(); shallow(buildApp({}, {collectComments: collectCommentsStub})); @@ -49,7 +50,6 @@ describe('PullRequestReviewCommentsContainer', function() { assert.strictEqual(wrapper.instance()._attemptToLoadMoreComments.callCount, 1); }); - describe('loadMoreComments', function() { it('calls this.props.relay.loadMore with correct args', function() { const relayLoadMoreStub = sinon.stub(); @@ -79,23 +79,18 @@ describe('PullRequestReviewCommentsContainer', function() { assert.deepEqual(args.comments, {edges: ['this kiki is marvelous']}); assert.isFalse(args.hasMore); }); - - it('handles errors', function() { - - }); - - }); - describe('attemptToLoadMoreComments', function() { let clock; beforeEach(function() { clock = sinon.useFakeTimers(); }); + afterEach(function() { clock = sinon.restore(); }); + it('does not call loadMore if hasMore is false', function() { const relayLoadMoreStub = sinon.stub(); const wrapper = shallow(buildApp({relayLoadMore: relayLoadMoreStub})); From e71dbb77a6763fcd0b3651538501dc039ef99a61 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 4 Jan 2019 16:56:12 -0800 Subject: [PATCH 2488/4847] [wip] add tests for PullRequestReviewsController --- .../controllers/pr-reviews-controller.test.js | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 test/controllers/pr-reviews-controller.test.js diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js new file mode 100644 index 0000000000..7105fcbcff --- /dev/null +++ b/test/controllers/pr-reviews-controller.test.js @@ -0,0 +1,57 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import PullRequestReviewsController from '../../lib/controllers/pr-reviews-controller'; + +describe('PullRequestReviewsController', function() { + function buildApp(opts, overrideProps = {}) { + const o = { + relayHasMore: () => { return false; }, + relayLoadMore: () => {}, + relayIsLoading: () => { return false; }, + reveiwSpecs: [], + reviewStartCursor: 0, + ...opts, + }; + + const review = { + edges: o.reviewItemSpecs.map((spec, i) => ({ + cursor: `result${i}`, + node: { + id: spec.id, + __typename: spec.kind, + }, + })), + pageInfo: { + startCursor: `result${o.reviewStartCursor}`, + endCursor: `result${o.reviewStartCursor + o.reviewItemSpecs.length}`, + hasNextPage: o.reviewStartCursor + o.reviewItemSpecs.length < o.reviewItemTotal, + hasPreviousPage: o.reviewStartCursor !== 0, + }, + totalCount: o.reviewItemTotal, + }; + + const props = { + relay: { + hasMore: o.relayHasMore, + loadMore: o.relayLoadMore, + isLoading: o.relayIsLoading, + }, + getBufferRowForDiffPosition: () => {}, + pullRequest: review, + ...overrideProps, + }; + return ; + } + it('renders a PullRequestReviewCommentsContainer for every review', function() { + + }); + + it('renders a PullRequestReviewCommentsView', function() { + + }); + + it('groups the comments into threads once all the data has been fetched', function() { + + }); +}); From 7d76f4f8b8ef3de1111fe4856abfe89a4b2fb6b0 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 4 Jan 2019 17:43:57 -0800 Subject: [PATCH 2489/4847] give `PullRequestCommentsView` tests the new getBufferRowForDiffPosition prop --- test/views/pr-comments-view.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index 75e5f4d7fc..346542323d 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -31,7 +31,7 @@ describe('PullRequestCommentsView', function() { }) .build(); - const wrapper = shallow(); + const wrapper = shallow(); assert.deepEqual(wrapper.find('Marker').at(0).prop('bufferRange').serialize(), [[1, 0], [1, 0]]); assert.deepEqual(wrapper.find('Marker').at(1).prop('bufferRange').serialize(), [[12, 0], [12, 0]]); @@ -57,7 +57,7 @@ describe('PullRequestCommentsView', function() { }) .build(); - const wrapper = shallow(); + const wrapper = shallow(); const comments = wrapper.find('PullRequestCommentView'); assert.lengthOf(comments, 1); From 2aa93bbcb4a683f9a8bc9e380ec845a630715d76 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 4 Jan 2019 18:20:24 -0800 Subject: [PATCH 2490/4847] reverse order of comment threads in pr builder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the test was asserting on 3 individual comments, that they rendered in the correct positions. when Katrina implemented grouping comments by thread, she did something like: `[...this.props.commentThreads].reverse().map(({rootCommentId, comments}) => {` tbh I don’t really understand why we need to call `reverse` there but we also need to be calling reverse in the comment builder, so that the tests are doing the same thing as the code. and then there was also a minor problem where we were passing in two comments with the same ID, which is now fixed. --- test/builder/pr.js | 2 +- test/views/pr-comments-view.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/builder/pr.js b/test/builder/pr.js index 63352c8e8b..55f3465fbc 100644 --- a/test/builder/pr.js +++ b/test/builder/pr.js @@ -134,7 +134,7 @@ class PullRequestBuilder { }); return { reviews: {nodes: this._reviews}, - commentThreads: Object.keys(commentThreads).map(rootCommentId => { + commentThreads: Object.keys(commentThreads).reverse().map(rootCommentId => { return { rootCommentId, comments: commentThreads[rootCommentId], diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index 346542323d..1a740bccae 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -27,7 +27,7 @@ describe('PullRequestCommentsView', function() { .addReview(r => { r.addComment(c => c.id(0).path('file0.txt').position(2).body('one')); r.addComment(c => c.id(1).path('file0.txt').position(15).body('three')); - r.addComment(c => c.id(1).path('file1.txt').position(7).body('three')); + r.addComment(c => c.id(2).path('file1.txt').position(7).body('three')); }) .build(); From 47dbdaf626b12c57f6d1de92973a7de69dac6af9 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 17:55:54 -0800 Subject: [PATCH 2491/4847] :fire: unnecessary commit-related arguments from issueDetailView fragment --- lib/controllers/issueish-detail-controller.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index 697a1f0e96..cd19de9636 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -287,7 +287,7 @@ export class BareIssueishDetailController extends React.Component { addEvent('open-commit-in-pane', {package: 'github', from: this.constructor.name}); } } -// todo: we probably don't need to commit count and cursor in the issue fragment + export default createFragmentContainer(BareIssueishDetailController, { repository: graphql` fragment issueishDetailController_repository on Repository @@ -316,8 +316,6 @@ export default createFragmentContainer(BareIssueishDetailController, { ...issueDetailView_issue @arguments( timelineCount: $timelineCount, timelineCursor: $timelineCursor, - commitCount: $commitCount, - commitCursor: $commitCursor, ) } } From bb47ca58a8498983a6f2412d9bb9ea2457d41343 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 18:16:03 -0800 Subject: [PATCH 2492/4847] Attempt to load more reviews only if no error ... in case we hit an error case where we fall into an infinite loop of retrying --- lib/controllers/pr-reviews-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 62262e9130..9021cfd1fa 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -35,12 +35,12 @@ export default class PullRequestReviewsController extends React.Component { this.props.relay.loadMore( PAGE_SIZE, error => { - this._attemptToLoadMoreReviews(); - /* istanbul ignore if */ if (error) { // eslint-disable-next-line no-console console.error(error); + } else { + this._attemptToLoadMoreReviews(); } }, ); From 99c6cc1e0712128915be4455e84d906d84f252d9 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 18:16:37 -0800 Subject: [PATCH 2493/4847] :art: re-order methods for readability --- lib/controllers/pr-reviews-controller.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 9021cfd1fa..1e1e2c06fa 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -31,6 +31,18 @@ export default class PullRequestReviewsController extends React.Component { this._attemptToLoadMoreReviews(); } + _attemptToLoadMoreReviews = () => { + if (!this.props.relay.hasMore()) { + return; + } + + if (this.props.relay.isLoading()) { + setTimeout(this._loadMoreReviews, PAGINATION_WAIT_TIME_MS); + } else { + this._loadMoreReviews(); + } + } + _loadMoreReviews = () => { this.props.relay.loadMore( PAGE_SIZE, @@ -46,18 +58,6 @@ export default class PullRequestReviewsController extends React.Component { ); } - _attemptToLoadMoreReviews = () => { - if (!this.props.relay.hasMore()) { - return; - } - - if (this.props.relay.isLoading()) { - setTimeout(this._loadMoreReviews, PAGINATION_WAIT_TIME_MS); - } else { - this._loadMoreReviews(); - } - } - renderCommentFetchingContainers() { return this.props.pullRequest.reviews.edges.map(({node}) => { const review = node; From 816ab62624396cf4ce3ef94ba464d846e3112f6c Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 18:31:36 -0800 Subject: [PATCH 2494/4847] Update generated relay code after :fire:ing commit-related arguments --- .../issueishDetailContainerQuery.graphql.js | 8 ++-- ...eishDetailController_repository.graphql.js | 38 +++++++++---------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 0ee982a7d9..08c8d4132a 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 86a6d997a1bfd3d4f567397ecdaa752b + * @relayHash b2844afc76c2e9c390039931a9af7d40 */ /* eslint-disable */ @@ -69,7 +69,7 @@ fragment issueishDetailController_repository_y3nHF on Repository { ... on Issue { title number - ...issueDetailView_issue_4cAEh0 + ...issueDetailView_issue_3D8CP9 } ... on Node { id @@ -120,7 +120,7 @@ fragment prDetailView_repository on Repository { } } -fragment issueDetailView_issue_4cAEh0 on Issue { +fragment issueDetailView_issue_3D8CP9 on Issue { __typename ... on Node { id @@ -1207,7 +1207,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_4cAEh0\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_4cAEh0 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_3D8CP9 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", diff --git a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js index 12a4a5d6e8..fa323bdbdd 100644 --- a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js +++ b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js @@ -110,24 +110,12 @@ v5 = { "storageKey": null }, v6 = { - "kind": "Variable", - "name": "commitCount", - "variableName": "commitCount", - "type": null -}, -v7 = { - "kind": "Variable", - "name": "commitCursor", - "variableName": "commitCursor", - "type": null -}, -v8 = { "kind": "Variable", "name": "timelineCount", "variableName": "timelineCount", "type": null }, -v9 = { +v7 = { "kind": "Variable", "name": "timelineCursor", "variableName": "timelineCursor", @@ -228,9 +216,7 @@ return { "name": "issueDetailView_issue", "args": [ v6, - v7, - v8, - v9 + v7 ] } ] @@ -303,8 +289,18 @@ return { "variableName": "commentCursor", "type": null }, - v6, - v7, + { + "kind": "Variable", + "name": "commitCount", + "variableName": "commitCount", + "type": null + }, + { + "kind": "Variable", + "name": "commitCursor", + "variableName": "commitCursor", + "type": null + }, { "kind": "Variable", "name": "reviewCount", @@ -317,8 +313,8 @@ return { "variableName": "reviewCursor", "type": null }, - v8, - v9 + v6, + v7 ] } ] @@ -329,5 +325,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = 'e348cf91ee76425342abf4aa3c60b143'; +(node/*: any*/).hash = 'c06dfbb4f1cc1c45187449da61fd7328'; module.exports = node; From 8eba48bd7fb3f39fdc01933d7c5718ddeefd7c71 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 18:31:55 -0800 Subject: [PATCH 2495/4847] More :art: for readability. Fix up comment --- lib/controllers/pr-reviews-controller.js | 32 +++++++++++------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 1e1e2c06fa..0051b5abd5 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -58,20 +58,6 @@ export default class PullRequestReviewsController extends React.Component { ); } - renderCommentFetchingContainers() { - return this.props.pullRequest.reviews.edges.map(({node}) => { - const review = node; - - return ( - - ); - }); - } - render() { if (!this.props.pullRequest || !this.props.pullRequest.reviews) { return null; @@ -84,14 +70,14 @@ export default class PullRequestReviewsController extends React.Component { }; }); - /** Slightly hacky thing to deal with comment threading... + /** Dealing with comment threading... * * Threads can have comments belonging to multiple reviews. * We need a nested pagination container to fetch comment pages. - * Upon fetching new comments, the `aggregateComments` method is called with the comments to add. + * Upon fetching new comments, the `collectComments` method is called with all comments fetched for that review. * Ultimately we want to organize comments based on the root comment they are replies to. * So `renderCommentFetchingContainers` simply fetches data and doesn't render any DOM elements. - * `PullRequestReviewCommentsView` renders the comment thread data aggregated. + * `PullRequestReviewCommentsView` renders the aggregated comment thread data. * */ return ( @@ -101,6 +87,18 @@ export default class PullRequestReviewsController extends React.Component { ); } + renderCommentFetchingContainers() { + return this.props.pullRequest.reviews.edges.map(({node: review}) => { + return ( + + ); + }); + } + // sorts reviews by date ascending (oldest to newest) sortComparator(a, b) { const dateA = new Date(a.submittedAt); From 2c6c8eb54576c2168d04e8cb1cc4c6c528c86de5 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 19:11:44 -0800 Subject: [PATCH 2496/4847] :art: :art: :art: --- .../pr-review-comments-container.js | 33 ++++++++------ lib/controllers/pr-reviews-controller.js | 44 +++++++++---------- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 9b3138f1fd..c514c9f313 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -21,28 +21,26 @@ export class BarePullRequestReviewCommentsContainer extends React.Component { } componentDidMount() { - this._attemptToLoadMoreComments(); - const {submittedAt, comments, id} = this.props.review; - this.props.collectComments({reviewId: id, submittedAt, comments, hasMore: this.props.relay.hasMore()}); + this.handleComments(); } - onDidLoadMore = error => { - const {submittedAt, comments, id} = this.props.review; - this.props.collectComments({reviewId: id, submittedAt, comments, hasMore: this.props.relay.hasMore()}); - this._attemptToLoadMoreComments(); - + handleComments = error => { /* istanbul ignore if */ if (error) { // eslint-disable-next-line no-console console.error(error); + return; } - } - _loadMoreComments = () => { - this.props.relay.loadMore( - PAGE_SIZE, - this.onDidLoadMore, - ); + const {submittedAt, comments, id} = this.props.review; + this.props.collectComments({ + reviewId: id, + submittedAt, + comments, + fetchingMoreComments: this.props.relay.hasMore(), + }); + + this._attemptToLoadMoreComments(); } _attemptToLoadMoreComments = () => { @@ -57,6 +55,13 @@ export class BarePullRequestReviewCommentsContainer extends React.Component { } } + _loadMoreComments = () => { + this.props.relay.loadMore( + PAGE_SIZE, + this.handleComments, + ); + } + render() { return null; } diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 0051b5abd5..ad3d89b652 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -99,25 +99,12 @@ export default class PullRequestReviewsController extends React.Component { }); } - // sorts reviews by date ascending (oldest to newest) - sortComparator(a, b) { - const dateA = new Date(a.submittedAt); - const dateB = new Date(b.submittedAt); - if (dateA > dateB) { - return 1; - } else if (dateB > dateA) { - return -1; - } else { - return 0; - } - } - - collectComments = ({reviewId, submittedAt, comments, hasMore}) => { - this.reviewsById.set(reviewId, {submittedAt, comments, hasMore}); - const noMoreReviewsToFetch = !this.props.relay.hasMore(); - if (noMoreReviewsToFetch) { - const noMoreCommentsToFetch = [...this.reviewsById.values()].every(review => !review.hasMore); - if (noMoreCommentsToFetch) { + collectComments = ({reviewId, submittedAt, comments, fetchingMoreCommnts}) => { + this.reviewsById.set(reviewId, {submittedAt, comments, fetchingMoreCommnts}); + const stillFetchingReviews = this.props.relay.hasMore(); + if (!stillFetchingReviews) { + const stillFetchingComments = [...this.reviewsById.values()].some(review => review.fetchingMoreCommnts); + if (!stillFetchingComments) { this.groupCommentsByThread(); } } @@ -125,18 +112,18 @@ export default class PullRequestReviewsController extends React.Component { groupCommentsByThread() { // we have no guarantees that reviews will return in order so sort them by date. - const sortedReviews = [...this.reviewsById.values()].sort(this.sortComparator); + const sortedReviews = [...this.reviewsById.values()].sort(this.sortByDate); // react batches calls to setState and does not update state synchronously // therefore we need an intermediate state so we can do checks against keys // we have just added. const state = {}; sortedReviews.forEach(({comments}) => { - comments.edges.forEach(({node}) => { - const comment = node; + comments.edges.forEach(({node: comment}) => { if (!comment.replyTo) { state[comment.id] = [comment]; } else { + // TODO: look at this more closely... // When comment being replied to is outdated...?? Not 100% sure... // Why would we even get an outdated comment or a response to one here? // Ran into this error when viewing files for https://github.com/numpy/numpy/pull/9998 @@ -153,4 +140,17 @@ export default class PullRequestReviewsController extends React.Component { this.setState(state); } + + // sorts reviews by date ascending (oldest to newest) + sortByDate(a, b) { + const dateA = new Date(a.submittedAt); + const dateB = new Date(b.submittedAt); + if (dateA > dateB) { + return 1; + } else if (dateB > dateA) { + return -1; + } else { + return 0; + } + } } From 708700825ddf8bab55d949b867399c533c387382 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 19:16:29 -0800 Subject: [PATCH 2497/4847] Reverse the array earlier --- lib/controllers/pr-reviews-controller.js | 2 +- lib/views/pr-review-comments-view.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index ad3d89b652..ba5674883f 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -63,7 +63,7 @@ export default class PullRequestReviewsController extends React.Component { return null; } - const commentThreads = Object.keys(this.state).map(rootCommentId => { + const commentThreads = Object.keys(this.state).reverse().map(rootCommentId => { return { rootCommentId, comments: this.state[rootCommentId], diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index 7eb1276902..09f8bc9bf9 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -24,7 +24,7 @@ export default class PullRequestCommentsView extends React.Component { } render() { - return [...this.props.commentThreads].reverse().map(({rootCommentId, comments}) => { + return [...this.props.commentThreads].map(({rootCommentId, comments}) => { const rootComment = comments[0]; if (!rootComment.position) { return null; From b42ab575763f51105fb135607c50bddaa2dbfda4 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 19:34:26 -0800 Subject: [PATCH 2498/4847] Use PAGE_SIZE for refetch variables --- lib/views/pr-detail-view.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index d0f18ae388..ed8d1f6d3d 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -15,6 +15,7 @@ import EmojiReactionsView from '../views/emoji-reactions-view'; import IssueishBadge from '../views/issueish-badge'; import PrCommitsView from '../views/pr-commits-view'; import PrStatusesView from '../views/pr-statuses-view'; +import {PAGE_SIZE} from '../helpers'; class CheckoutState { constructor(name) { @@ -348,13 +349,13 @@ export class BarePullRequestDetailView extends React.Component { this.props.relay.refetch({ repoId: this.props.repository.id, issueishId: this.props.pullRequest.id, - timelineCount: 100, + timelineCount: PAGE_SIZE, timelineCursor: null, - commitCount: 100, + commitCount: PAGE_SIZE, commitCursor: null, - reviewCount: 2, + reviewCount: PAGE_SIZE, reviewCursor: null, - commentCount: 2, + commentCount: PAGE_SIZE, commentCursor: null, }, null, () => { this.setState({refreshing: false}); From 0ce67983023f0307d6bba478ab6e99d5ff4f5993 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 19:59:26 -0800 Subject: [PATCH 2499/4847] Make tests consistent --- test/models/patch/multi-file-patch.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index 767b17e233..cad02eaffa 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -710,7 +710,7 @@ describe('MultiFilePatch', function() { .addFilePatch(fp => { fp.setOldFile(f => f.path('file.txt')); fp.addHunk(h => { - h.unchanged('1 (0)').added('2 (1)', '3 (2)').deleted('4 (3)', '5 (4)', '6 (5)').unchanged('7 (6)'); + h.unchanged('0 (1)').added('1 (2)', '2 (3)').deleted('3 (4)', '4 (5)', '5 (6)').unchanged('6 (7)'); }); }) .build(); From 0498b50922bdcc7d1fae589c897fa871c6e5a5fc Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 23:02:18 -0800 Subject: [PATCH 2500/4847] Fix PullRequestReviewCommentsContainer tests --- .../pr-review-comments-container.test.js | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/test/containers/pr-review-comments-container.test.js b/test/containers/pr-review-comments-container.test.js index d690000057..43f3f9c08d 100644 --- a/test/containers/pr-review-comments-container.test.js +++ b/test/containers/pr-review-comments-container.test.js @@ -6,6 +6,12 @@ import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../../lib/helpers'; import {BarePullRequestReviewCommentsContainer} from '../../lib/containers/pr-review-comments-container'; describe('PullRequestReviewCommentsContainer', function() { + const review = { + id: '123', + submittedAt: '2018-12-27T20:40:55Z', + comments: {edges: ['this kiki is marvelous']}, + }; + function buildApp(opts, overrideProps = {}) { const o = { relayHasMore: () => { return false; }, @@ -21,11 +27,7 @@ describe('PullRequestReviewCommentsContainer', function() { isLoading: o.relayIsLoading, }, collectComments: () => {}, - review: { - id: '123', - submittedAt: '2018-12-27T20:40:55Z', - comments: {edges: ['this kiki is marvelous']}, - }, + review, ...overrideProps, }; return ; @@ -35,12 +37,14 @@ describe('PullRequestReviewCommentsContainer', function() { const collectCommentsStub = sinon.stub(); shallow(buildApp({}, {collectComments: collectCommentsStub})); assert.strictEqual(collectCommentsStub.callCount, 1); - const args = collectCommentsStub.lastCall.args[0]; - assert.strictEqual(args.reviewId, '123'); - assert.strictEqual(args.submittedAt, '2018-12-27T20:40:55Z'); - assert.deepEqual(args.comments, {edges: ['this kiki is marvelous']}); - assert.isFalse(args.hasMore); + const {submittedAt, comments, id} = review; + assert.deepEqual(collectCommentsStub.lastCall.args[0], { + reviewId: id, + submittedAt, + comments, + fetchingMoreComments: false, + }); }); it('attempts to load comments after component has been mounted', function() { @@ -56,28 +60,29 @@ describe('PullRequestReviewCommentsContainer', function() { const wrapper = shallow(buildApp({relayLoadMore: relayLoadMoreStub})); wrapper.instance()._loadMoreComments(); - const args = relayLoadMoreStub.lastCall.args; - assert.strictEqual(args[0], PAGE_SIZE); - assert.strictEqual(args[1], wrapper.instance().onDidLoadMore); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleComments]); }); }); - describe('onDidLoadMore', function() { + describe('handleComments', function() { it('collects comments and attempts to load more comments', function() { const collectCommentsStub = sinon.stub(); const wrapper = shallow(buildApp({}, {collectComments: collectCommentsStub})); // collect comments is called when mounted, we don't care about that in this test so reset the count collectCommentsStub.reset(); sinon.stub(wrapper.instance(), '_attemptToLoadMoreComments'); - wrapper.instance().onDidLoadMore(); + wrapper.instance().handleComments(); assert.strictEqual(collectCommentsStub.callCount, 1); const args = collectCommentsStub.lastCall.args[0]; - assert.strictEqual(args.reviewId, '123'); - assert.strictEqual(args.submittedAt, '2018-12-27T20:40:55Z'); - assert.deepEqual(args.comments, {edges: ['this kiki is marvelous']}); - assert.isFalse(args.hasMore); + const {submittedAt, comments, id} = review; + assert.deepEqual(collectCommentsStub.lastCall.args[0], { + reviewId: id, + submittedAt, + comments, + fetchingMoreComments: false, + }); }); }); @@ -108,9 +113,7 @@ describe('PullRequestReviewCommentsContainer', function() { wrapper.instance()._attemptToLoadMoreComments(); assert.strictEqual(relayLoadMoreStub.callCount, 1); - const args = relayLoadMoreStub.lastCall.args; - assert.strictEqual(args[0], PAGE_SIZE); - assert.strictEqual(args[1], wrapper.instance().onDidLoadMore); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleComments]); }); it('calls loadMore after a timeout if hasMore is true and isLoading is true', function() { @@ -128,9 +131,7 @@ describe('PullRequestReviewCommentsContainer', function() { clock.tick(PAGINATION_WAIT_TIME_MS); assert.strictEqual(relayLoadMoreStub.callCount, 1); - const args = relayLoadMoreStub.lastCall.args; - assert.strictEqual(args[0], PAGE_SIZE); - assert.strictEqual(args[1], wrapper.instance().onDidLoadMore); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleComments]); }); }); }); From 80c97c5aeb7e964b1cec9b7ab5c6f5f8836cef12 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 23:06:04 -0800 Subject: [PATCH 2501/4847] Don't `reverse` in PullRequestBuilder --- test/builder/pr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/builder/pr.js b/test/builder/pr.js index 55f3465fbc..63352c8e8b 100644 --- a/test/builder/pr.js +++ b/test/builder/pr.js @@ -134,7 +134,7 @@ class PullRequestBuilder { }); return { reviews: {nodes: this._reviews}, - commentThreads: Object.keys(commentThreads).reverse().map(rootCommentId => { + commentThreads: Object.keys(commentThreads).map(rootCommentId => { return { rootCommentId, comments: commentThreads[rootCommentId], From 905a1a27dbe7a02b7d159b74b7a6ec125d963b71 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 4 Jan 2019 23:16:31 -0800 Subject: [PATCH 2502/4847] :art: tests --- test/views/pr-comments-view.test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index 1a740bccae..3a87f20737 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -73,7 +73,7 @@ describe('PullRequestCommentView', function() { const bodyHTML = '
    yo yo
    '; const switchToIssueish = () => {}; - function buildApp(overrideProps = {}, opts = {}) { + function buildApp(commentOverrideProps = {}, opts = {}) { const props = { comment: { bodyHTML, @@ -83,7 +83,7 @@ describe('PullRequestCommentView', function() { avatarUrl, login, }, - ...overrideProps, + ...commentOverrideProps, }, switchToIssueish, ...opts, @@ -93,6 +93,7 @@ describe('PullRequestCommentView', function() { ); } + it('renders the PullRequestCommentReview information', function() { const wrapper = shallow(buildApp()); const avatar = wrapper.find('.github-PrComment-avatar'); From 5ca856826a1d8770e72a3cf68ee3ac35969af76a Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 7 Jan 2019 18:08:40 +0100 Subject: [PATCH 2503/4847] fall back to using git log authors if remote users cannot be loaded --- lib/models/user-store.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index 30a8c97355..57077e3144 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -100,11 +100,13 @@ export default class UserStore { this.setCommitter(data.committer); const githubRemotes = Array.from(data.remotes).filter(remote => remote.isGithubRepo()); - if (githubRemotes.length === 0) { - this.addUsers(data.authors, source.GITLOG); - } else { + if (githubRemotes.length > 0) { await this.loadUsersFromGraphQL(githubRemotes); } + + if (this.getUsers().length === 0) { + this.addUsers(data.authors, source.GITLOG); + } } loadUsersFromGraphQL(remotes) { From bb1536275ea1982b686e4b8ce4bf66be45126c71 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 7 Jan 2019 19:09:24 +0100 Subject: [PATCH 2504/4847] add test --- test/models/user-store.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 0d70bfd23c..51e130c864 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -97,6 +97,21 @@ describe('UserStore', function() { assert.deepEqual(store.committer, new Author(FAKE_USER.email, FAKE_USER.name)); }); + it('falls back to local git users and committers if laodMentionableUsers cannot load any user for whatever reason', async function() { + const workdirPath = await cloneRepository('multiple-commits'); + const repository = await buildRepository(workdirPath); + + store = new UserStore({repository, login, config}); + sinon.stub(store, 'loadMentionableUsers').returns(undefined); + + await store.loadUsers(); + await nextUpdatePromise(); + + assert.deepEqual(store.getUsers(), [ + new Author('kuychaco@github.com', 'Katrina Uychaco'), + ]); + }); + it('loads store with mentionable users from the GitHub API in a repo with a GitHub remote', async function() { await login.setToken('https://api.github.com', '1234'); From 8915ec0337991a7316319680a81e3b8f42ccf990 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 7 Jan 2019 19:38:31 +0100 Subject: [PATCH 2505/4847] don't need login stub --- test/models/user-store.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 51e130c864..4b78905532 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -101,7 +101,7 @@ describe('UserStore', function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); - store = new UserStore({repository, login, config}); + store = new UserStore({repository, config}); sinon.stub(store, 'loadMentionableUsers').returns(undefined); await store.loadUsers(); From d08daca581f51e57871a9c214fee21b222e6caeb Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 7 Jan 2019 14:04:26 -0800 Subject: [PATCH 2506/4847] fix typo in method name --- lib/controllers/pr-reviews-controller.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index ba5674883f..18f503b996 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -99,11 +99,11 @@ export default class PullRequestReviewsController extends React.Component { }); } - collectComments = ({reviewId, submittedAt, comments, fetchingMoreCommnts}) => { - this.reviewsById.set(reviewId, {submittedAt, comments, fetchingMoreCommnts}); + collectComments = ({reviewId, submittedAt, comments, fetchingMoreComments}) => { + this.reviewsById.set(reviewId, {submittedAt, comments, fetchingMoreComments}); const stillFetchingReviews = this.props.relay.hasMore(); if (!stillFetchingReviews) { - const stillFetchingComments = [...this.reviewsById.values()].some(review => review.fetchingMoreCommnts); + const stillFetchingComments = [...this.reviewsById.values()].some(review => review.fetchingMoreComments); if (!stillFetchingComments) { this.groupCommentsByThread(); } From edc49781f2ee6cadbfab161234797aa30b92bfc0 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 7 Jan 2019 14:08:33 -0800 Subject: [PATCH 2507/4847] pedantic af function name change --- lib/controllers/pr-reviews-controller.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 18f503b996..73ac847aa9 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -112,7 +112,7 @@ export default class PullRequestReviewsController extends React.Component { groupCommentsByThread() { // we have no guarantees that reviews will return in order so sort them by date. - const sortedReviews = [...this.reviewsById.values()].sort(this.sortByDate); + const sortedReviews = [...this.reviewsById.values()].sort(this.compareReviewsByDate); // react batches calls to setState and does not update state synchronously // therefore we need an intermediate state so we can do checks against keys @@ -141,10 +141,10 @@ export default class PullRequestReviewsController extends React.Component { this.setState(state); } - // sorts reviews by date ascending (oldest to newest) - sortByDate(a, b) { - const dateA = new Date(a.submittedAt); - const dateB = new Date(b.submittedAt); + // compare reviews by date ascending (in order to sort oldest to newest) + compareReviewsByDate(reviewA, reviewB) { + const dateA = new Date(reviewA.submittedAt); + const dateB = new Date(reviewB.submittedAt); if (dateA > dateB) { return 1; } else if (dateB > dateA) { From 73b06c69a56dac66612c51c2978e7cf380c9d95f Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 7 Jan 2019 15:59:20 -0800 Subject: [PATCH 2508/4847] :fire: unused variable --- test/containers/pr-review-comments-container.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/containers/pr-review-comments-container.test.js b/test/containers/pr-review-comments-container.test.js index 43f3f9c08d..ca3bbcc1f0 100644 --- a/test/containers/pr-review-comments-container.test.js +++ b/test/containers/pr-review-comments-container.test.js @@ -74,7 +74,6 @@ describe('PullRequestReviewCommentsContainer', function() { wrapper.instance().handleComments(); assert.strictEqual(collectCommentsStub.callCount, 1); - const args = collectCommentsStub.lastCall.args[0]; const {submittedAt, comments, id} = review; assert.deepEqual(collectCommentsStub.lastCall.args[0], { From dcaee75346663874a3d30f88621c2847bf6e86d2 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 7 Jan 2019 17:24:40 -0800 Subject: [PATCH 2509/4847] make builder reflect the new improved shape of our data - we're using edges now instead of nodes, as the query was originally using - add `submittedAt` to reviews - `replyTo` is an object with an id - --- test/builder/pr.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/test/builder/pr.js b/test/builder/pr.js index 63352c8e8b..f6f14e8fdb 100644 --- a/test/builder/pr.js +++ b/test/builder/pr.js @@ -52,7 +52,7 @@ class CommentBuilder { } replyTo(replyToId) { - this._replyTo = replyToId; + this._replyTo = {id: replyToId}; return this; } @@ -78,6 +78,7 @@ class ReviewBuilder { this.nextCommentID = 0; this._id = 0; this._comments = []; + this._submittedAt = '2018-12-28T20:40:55Z'; } id(i) { @@ -85,6 +86,11 @@ class ReviewBuilder { return this; } + submittedAt(timestamp) { + this._submittedAt = timestamp; + return this; + } + addComment(block = () => {}) { const builder = new CommentBuilder(); builder.id(this.nextCommentID); @@ -97,9 +103,12 @@ class ReviewBuilder { } build() { + const comments = this._comments.map(comment => { + return {node: comment}; + }); return { id: this._id, - comments: {nodes: this._comments}, + comments: {edges: comments}, }; } } @@ -124,9 +133,9 @@ class PullRequestBuilder { build() { const commentThreads = {}; this._reviews.forEach(review => { - review.comments.nodes.forEach(comment => { - if (comment.replyTo && commentThreads[comment.replyTo]) { - commentThreads[comment.replyTo].push(comment); + review.comments.edges.forEach(({node: comment}) => { + if (comment.replyTo && comment.replyTo.id && commentThreads[comment.replyTo.id]) { + commentThreads[comment.replyTo.id].push(comment); } else { commentThreads[comment.id] = [comment]; } From 8d83ebd55a25301221422824193f8df0d4bc35f0 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 7 Jan 2019 17:27:19 -0800 Subject: [PATCH 2510/4847] add more tests for `PullRequestReviewsController` --- .../controllers/pr-reviews-controller.test.js | 94 +++++++++++++++++-- 1 file changed, 86 insertions(+), 8 deletions(-) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index 7105fcbcff..41bcbff8fb 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -1,5 +1,6 @@ import React from 'react'; import {shallow} from 'enzyme'; +import {reviewBuilder} from '../builder/pr'; import PullRequestReviewsController from '../../lib/controllers/pr-reviews-controller'; @@ -9,23 +10,23 @@ describe('PullRequestReviewsController', function() { relayHasMore: () => { return false; }, relayLoadMore: () => {}, relayIsLoading: () => { return false; }, - reveiwSpecs: [], + reviewSpecs: [], reviewStartCursor: 0, ...opts, }; - const review = { - edges: o.reviewItemSpecs.map((spec, i) => ({ + const reviews = { + edges: o.reviewSpecs.map((spec, i) => ({ cursor: `result${i}`, node: { id: spec.id, - __typename: spec.kind, + __typename: 'review', }, })), pageInfo: { startCursor: `result${o.reviewStartCursor}`, - endCursor: `result${o.reviewStartCursor + o.reviewItemSpecs.length}`, - hasNextPage: o.reviewStartCursor + o.reviewItemSpecs.length < o.reviewItemTotal, + endCursor: `result${o.reviewStartCursor + o.reviewSpecs.length}`, + hasNextPage: o.reviewStartCursor + o.reviewSpecs.length < o.reviewItemTotal, hasPreviousPage: o.reviewStartCursor !== 0, }, totalCount: o.reviewItemTotal, @@ -37,21 +38,98 @@ describe('PullRequestReviewsController', function() { loadMore: o.relayLoadMore, isLoading: o.relayIsLoading, }, + + switchToIssueish: () => {}, getBufferRowForDiffPosition: () => {}, - pullRequest: review, + pullRequest: {reviews}, ...overrideProps, }; return ; } + it('returns null if props.pullRequest is falsy', function() { + const wrapper = shallow(buildApp({}, {pullRequest: null})); + assert.isNull(wrapper.getElement()); + }); + + it('returns null if props.pullRequest.reviews is falsy', function() { + const wrapper = shallow(buildApp({}, {pullRequest: {reviews: null}})); + assert.isNull(wrapper.getElement()); + }); + it('renders a PullRequestReviewCommentsContainer for every review', function() { + const review1 = reviewBuilder().build(); + const review2 = reviewBuilder().build(); + const reviewSpecs = [review1, review2]; + const wrapper = shallow(buildApp({reviewSpecs})); + const containers = wrapper.find('Relay(BarePullRequestReviewCommentsContainer)'); + assert.strictEqual(containers.length, 2); + // should I assert on props here? }); - it('renders a PullRequestReviewCommentsView', function() { + it('renders a PullRequestReviewCommentsView and passes props through', function() { + const review1 = reviewBuilder().build(); + const review2 = reviewBuilder().build(); + + const reviewSpecs = [review1, review2]; + const passThroughProp = 'I only exist for the children'; + const wrapper = shallow(buildApp({reviewSpecs}, {passThroughProp})); + const view = wrapper.find('PullRequestCommentsView'); + assert.strictEqual(view.length, 1); + assert.strictEqual(wrapper.instance().props.passThroughProp, view.prop('passThroughProp')); + + // should I assert on the commentThreads prop? }); + describe('collectComments', function() { + it('sets this.reviewsById with correct data', function() { + const wrapper = shallow(buildApp()); + const args = {reviewId: 123, submittedAt: '2018-12-27T20:40:55Z', comments: ['a comment', + ], fetchingMoreComments: true}; + assert.strictEqual(wrapper.instance().reviewsById.size, 0); + wrapper.instance().collectComments(args); + const review = wrapper.instance().reviewsById.get(args.reviewId); + delete args.reviewId; + assert.deepEqual(review, args); + }); + + it('calls groupCommentsByThread if there are no more reviews or comments to be fetched', function() { + const wrapper = shallow(buildApp()); + const groupCommentsStub = sinon.stub(wrapper.instance(), 'groupCommentsByThread'); + assert.isFalse(groupCommentsStub.called); + const args = {reviewId: 123, submittedAt: '2018-12-27T20:40:55Z', comments: ['a comment', + ], fetchingMoreComments: false}; + wrapper.instance().collectComments(args); + assert.strictEqual(groupCommentsStub.callCount, 1); + }); + }); + + it('groups the comments into threads once all the data has been fetched', function() { + const review1 = reviewBuilder() + .id(0) + .submittedAt('2018-12-27T20:40:55Z') + .addComment(c => c.id(1).path('file0.txt').body('OG comment')) + .build(); + + const review2 = reviewBuilder() + .id(1) + .submittedAt('2018-12-28T20:40:55Z') + .addComment(c => c.id(2).path('file0.txt').replyTo(1).body('reply to OG comment')) + .build(); + + const reviewSpecs = [review1, review2]; + + const wrapper = shallow(buildApp({reviewSpecs})); + + // adding this manually to reviewsById because the last time you call collectComments + wrapper.instance().reviewsById.set(review1.id, {submittedAt: review1.submittedAt, comments: review1.comments, fetchingMoreComments: false}); + wrapper.instance().collectComments({reviewId: review2.id, submittedAt: review2.submittedAt, comments: review2.comments, fetchingMoreComments: false}); + const threadedComments = wrapper.instance().state[1]; + assert.lengthOf(threadedComments, 2); + assert.strictEqual(threadedComments[0].body, 'OG comment'); + assert.strictEqual(threadedComments[1].body, 'reply to OG comment'); }); }); From 8baab2f0f257315794b4620928516e560c015aab Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 7 Jan 2019 17:28:37 -0800 Subject: [PATCH 2511/4847] :shirt: --- test/builder/pr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/builder/pr.js b/test/builder/pr.js index f6f14e8fdb..e7b78ba2db 100644 --- a/test/builder/pr.js +++ b/test/builder/pr.js @@ -133,7 +133,7 @@ class PullRequestBuilder { build() { const commentThreads = {}; this._reviews.forEach(review => { - review.comments.edges.forEach(({node: comment}) => { + review.comments.edges.forEach(({node: comment}) => { if (comment.replyTo && comment.replyTo.id && commentThreads[comment.replyTo.id]) { commentThreads[comment.replyTo.id].push(comment); } else { From 7542c0d36988becbf70fb421373137cbc9ab0043 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Mon, 7 Jan 2019 17:34:19 -0800 Subject: [PATCH 2512/4847] clean up some cruft --- test/controllers/pr-reviews-controller.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index 41bcbff8fb..66d6f78896 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -64,7 +64,9 @@ describe('PullRequestReviewsController', function() { const wrapper = shallow(buildApp({reviewSpecs})); const containers = wrapper.find('Relay(BarePullRequestReviewCommentsContainer)'); assert.strictEqual(containers.length, 2); - // should I assert on props here? + + assert.strictEqual(containers.at(0).prop('review').id, review1.id); + assert.strictEqual(containers.at(1).prop('review').id, review2.id); }); it('renders a PullRequestReviewCommentsView and passes props through', function() { @@ -78,8 +80,6 @@ describe('PullRequestReviewsController', function() { assert.strictEqual(view.length, 1); assert.strictEqual(wrapper.instance().props.passThroughProp, view.prop('passThroughProp')); - - // should I assert on the commentThreads prop? }); describe('collectComments', function() { From c6c99cc11543dfdf1eda139dd4aaca795066221e Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 8 Jan 2019 11:50:47 +0100 Subject: [PATCH 2513/4847] use `allUsers` size instead --- lib/models/user-store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index 57077e3144..a4b5f894d2 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -104,7 +104,7 @@ export default class UserStore { await this.loadUsersFromGraphQL(githubRemotes); } - if (this.getUsers().length === 0) { + if (this.allUsers.size === 0) { this.addUsers(data.authors, source.GITLOG); } } From 5302d3845b1233fbbdfe0a9bc3c2675b253f1625 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 8 Jan 2019 11:51:09 +0100 Subject: [PATCH 2514/4847] fix test --- test/models/user-store.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 4b78905532..7b9d8afc5c 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -238,12 +238,12 @@ describe('UserStore', function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); store = new UserStore({repository, config}); + sinon.spy(store, 'addUsers'); await assert.async.lengthOf(store.getUsers(), 1); + await assert.async.equal(store.addUsers.callCount, 1); - sinon.spy(store, 'addUsers'); // make a commit with FAKE_USER as committer await repository.commit('made a new commit', {allowEmpty: true}); - await assert.async.equal(store.addUsers.callCount, 1); // verify that FAKE_USER is in commit history const lastCommit = await repository.getLastCommit(); From b697a730c1a60c9b484d5eb29eda05fb45ef6769 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 8 Jan 2019 11:51:20 +0100 Subject: [PATCH 2515/4847] typo! --- test/models/user-store.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/user-store.test.js b/test/models/user-store.test.js index 7b9d8afc5c..0092288e3d 100644 --- a/test/models/user-store.test.js +++ b/test/models/user-store.test.js @@ -97,7 +97,7 @@ describe('UserStore', function() { assert.deepEqual(store.committer, new Author(FAKE_USER.email, FAKE_USER.name)); }); - it('falls back to local git users and committers if laodMentionableUsers cannot load any user for whatever reason', async function() { + it('falls back to local git users and committers if loadMentionableUsers cannot load any user for whatever reason', async function() { const workdirPath = await cloneRepository('multiple-commits'); const repository = await buildRepository(workdirPath); From f982959c32c0bcf81afb17acafb996d9514b99f1 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 8 Jan 2019 12:14:33 +0100 Subject: [PATCH 2516/4847] add some comments + tweaks --- lib/models/user-store.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/models/user-store.js b/lib/models/user-store.js index a4b5f894d2..ccea24f90f 100644 --- a/lib/models/user-store.js +++ b/lib/models/user-store.js @@ -102,8 +102,12 @@ export default class UserStore { if (githubRemotes.length > 0) { await this.loadUsersFromGraphQL(githubRemotes); + } else { + this.addUsers(data.authors, source.GITLOG); } + // if for whatever reason, no committers can be added, fall back to + // using git log committers as the last resort if (this.allUsers.size === 0) { this.addUsers(data.authors, source.GITLOG); } From 838784dd14304fdffc5ef13f5a9ac53e45d2654e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 8 Jan 2019 11:01:48 -0500 Subject: [PATCH 2517/4847] Exclude Relay-generated GraphQL files from code coverage --- .nycrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.nycrc.json b/.nycrc.json index 7135cec850..ba08fac8e8 100644 --- a/.nycrc.json +++ b/.nycrc.json @@ -7,6 +7,7 @@ "exclude": [ "lib/views/git-cache-view.js", "lib/views/git-timings-view.js", - "lib/relay-network-layer-manager.js" + "lib/relay-network-layer-manager.js", + "*.graphql.js" ] } From b8f1482d5b5c2ab47dd4f304ee92ab4be0652194 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 8 Jan 2019 11:04:44 -0500 Subject: [PATCH 2518/4847] More specific exclusion glob --- .nycrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nycrc.json b/.nycrc.json index ba08fac8e8..a9ba28c23f 100644 --- a/.nycrc.json +++ b/.nycrc.json @@ -8,6 +8,6 @@ "lib/views/git-cache-view.js", "lib/views/git-timings-view.js", "lib/relay-network-layer-manager.js", - "*.graphql.js" + "**/__generated__/*.graphql.js" ] } From 2c75c8b6db22b90f9aa9a80ffbae78c67f8ad610 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 8 Jan 2019 10:31:15 -0800 Subject: [PATCH 2519/4847] test that mfpView renders the `PullRequestReviewsController` --- test/views/multi-file-patch-view.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/views/multi-file-patch-view.test.js b/test/views/multi-file-patch-view.test.js index 30cf1d92af..813c206af9 100644 --- a/test/views/multi-file-patch-view.test.js +++ b/test/views/multi-file-patch-view.test.js @@ -9,6 +9,7 @@ import FilePatch from '../../lib/models/patch/file-patch'; import RefHolder from '../../lib/models/ref-holder'; import CommitPreviewItem from '../../lib/items/commit-preview-item'; import ChangedFileItem from '../../lib/items/changed-file-item'; +import IssueishDetailItem from '../../lib/items/issueish-detail-item'; describe('MultiFilePatchView', function() { let atomEnv, workspace, repository, filePatches; @@ -134,6 +135,11 @@ describe('MultiFilePatchView', function() { assert.isFalse(wrapper.find('FilePatchHeaderView[relPath="1"]').prop('hasMultipleFileSelections')); }); + it('renders a PullRequestsReviewsContainer if itemType is IssueishDetailItem', function() { + const wrapper = shallow(buildApp({itemType: IssueishDetailItem})); + assert.lengthOf(wrapper.find('Relay(PullRequestReviewsController)'), 1); + }); + it('renders the file patch within an editor', function() { const wrapper = mount(buildApp()); From 8817466d3c39299e4882149c14e16adcdf60b20b Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 8 Jan 2019 11:05:57 -0800 Subject: [PATCH 2520/4847] add test for error handling in `PullRequestReviewsController` --- lib/controllers/pr-reviews-controller.js | 23 +++--- .../pr-review-comments-container.test.js | 2 +- .../controllers/pr-reviews-controller.test.js | 80 ++++++++++++++----- 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 73ac847aa9..140586d79f 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -43,19 +43,18 @@ export default class PullRequestReviewsController extends React.Component { } } + handleError = error => { + /* istanbul ignore if */ + if (error) { + // eslint-disable-next-line no-console + console.error(error); + } else { + this._attemptToLoadMoreReviews(); + } + } + _loadMoreReviews = () => { - this.props.relay.loadMore( - PAGE_SIZE, - error => { - /* istanbul ignore if */ - if (error) { - // eslint-disable-next-line no-console - console.error(error); - } else { - this._attemptToLoadMoreReviews(); - } - }, - ); + this.props.relay.loadMore(PAGE_SIZE, this.handleError); } render() { diff --git a/test/containers/pr-review-comments-container.test.js b/test/containers/pr-review-comments-container.test.js index ca3bbcc1f0..8eb7916221 100644 --- a/test/containers/pr-review-comments-container.test.js +++ b/test/containers/pr-review-comments-container.test.js @@ -54,7 +54,7 @@ describe('PullRequestReviewCommentsContainer', function() { assert.strictEqual(wrapper.instance()._attemptToLoadMoreComments.callCount, 1); }); - describe('loadMoreComments', function() { + describe('_loadMoreComments', function() { it('calls this.props.relay.loadMore with correct args', function() { const relayLoadMoreStub = sinon.stub(); const wrapper = shallow(buildApp({relayLoadMore: relayLoadMoreStub})); diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index 66d6f78896..6a9d13ed34 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -4,6 +4,8 @@ import {reviewBuilder} from '../builder/pr'; import PullRequestReviewsController from '../../lib/controllers/pr-reviews-controller'; +import {PAGE_SIZE} from '../../lib/helpers'; + describe('PullRequestReviewsController', function() { function buildApp(opts, overrideProps = {}) { const o = { @@ -105,31 +107,69 @@ describe('PullRequestReviewsController', function() { }); }); + describe('_loadMoreReviews', function() { + it('calls this.props.relay.loadMore with correct args', function() { + const relayLoadMoreStub = sinon.stub(); + const wrapper = shallow(buildApp({relayLoadMore: relayLoadMoreStub})); + wrapper.instance()._loadMoreReviews(); - it('groups the comments into threads once all the data has been fetched', function() { - const review1 = reviewBuilder() - .id(0) - .submittedAt('2018-12-27T20:40:55Z') - .addComment(c => c.id(1).path('file0.txt').body('OG comment')) - .build(); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleError]); + }); + }); - const review2 = reviewBuilder() - .id(1) - .submittedAt('2018-12-28T20:40:55Z') - .addComment(c => c.id(2).path('file0.txt').replyTo(1).body('reply to OG comment')) - .build(); + describe('grouping and ordering comments', function() { + it('groups the comments into threads based on replyId', function() { + const review1 = reviewBuilder() + .id(0) + .submittedAt('2018-12-27T20:40:55Z') + .addComment(c => c.id(1).path('file0.txt').body('OG comment')) + .build(); - const reviewSpecs = [review1, review2]; + const review2 = reviewBuilder() + .id(1) + .submittedAt('2018-12-28T20:40:55Z') + .addComment(c => c.id(2).path('file0.txt').replyTo(1).body('reply to OG comment')) + .build(); - const wrapper = shallow(buildApp({reviewSpecs})); + const reviewSpecs = [review1, review2]; - // adding this manually to reviewsById because the last time you call collectComments - wrapper.instance().reviewsById.set(review1.id, {submittedAt: review1.submittedAt, comments: review1.comments, fetchingMoreComments: false}); + const wrapper = shallow(buildApp({reviewSpecs})); + + // adding this manually to reviewsById because the last time you call collectComments it groups them, and we don't want to do that just yet. + wrapper.instance().reviewsById.set(review1.id, {submittedAt: review1.submittedAt, comments: review1.comments, fetchingMoreComments: false}); + + wrapper.instance().collectComments({reviewId: review2.id, submittedAt: review2.submittedAt, comments: review2.comments, fetchingMoreComments: false}); + const threadedComments = wrapper.instance().state[1]; + assert.lengthOf(threadedComments, 2); + assert.strictEqual(threadedComments[0].body, 'OG comment'); + assert.strictEqual(threadedComments[1].body, 'reply to OG comment'); + }); + it('sorts replies based on date', function() { + const review1 = reviewBuilder() + .id(0) + .submittedAt('2018-12-27T20:40:55Z') + .addComment(c => c.id(1).path('file0.txt').body('OG comment')) + .build(); + + const review2 = reviewBuilder() + .id(1) + .submittedAt('2018-12-28T20:40:55Z') + .addComment(c => c.id(2).path('file0.txt').replyTo(1).body('reply to OG comment')) + .build(); + + const reviewSpecs = [review1, review2]; + + const wrapper = shallow(buildApp({reviewSpecs})); + + // adding this manually to reviewsById because the last time you call collectComments it groups them, and we don't want to do that just yet. + wrapper.instance().reviewsById.set(review1.id, {submittedAt: review1.submittedAt, comments: review1.comments, fetchingMoreComments: false}); + + wrapper.instance().collectComments({reviewId: review2.id, submittedAt: review2.submittedAt, comments: review2.comments, fetchingMoreComments: false}); + const threadedComments = wrapper.instance().state[1]; + assert.lengthOf(threadedComments, 2); + assert.strictEqual(threadedComments[0].body, 'OG comment'); + assert.strictEqual(threadedComments[1].body, 'reply to OG comment'); + }); - wrapper.instance().collectComments({reviewId: review2.id, submittedAt: review2.submittedAt, comments: review2.comments, fetchingMoreComments: false}); - const threadedComments = wrapper.instance().state[1]; - assert.lengthOf(threadedComments, 2); - assert.strictEqual(threadedComments[0].body, 'OG comment'); - assert.strictEqual(threadedComments[1].body, 'reply to OG comment'); }); }); From 24e00fc0beb736ec686b3fb94632a286b0771498 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 8 Jan 2019 11:22:32 -0800 Subject: [PATCH 2521/4847] yummy copypasta --- .../controllers/pr-reviews-controller.test.js | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index 6a9d13ed34..682550dc2b 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -4,7 +4,7 @@ import {reviewBuilder} from '../builder/pr'; import PullRequestReviewsController from '../../lib/controllers/pr-reviews-controller'; -import {PAGE_SIZE} from '../../lib/helpers'; +import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../../lib/helpers'; describe('PullRequestReviewsController', function() { function buildApp(opts, overrideProps = {}) { @@ -107,6 +107,55 @@ describe('PullRequestReviewsController', function() { }); }); + describe('attemptToLoadMoreReviews', function() { + let clock; + beforeEach(function() { + clock = sinon.useFakeTimers(); + }); + + afterEach(function() { + clock = sinon.restore(); + }); + + it('does not call loadMore if hasMore is false', function() { + const relayLoadMoreStub = sinon.stub(); + const wrapper = shallow(buildApp({relayLoadMore: relayLoadMoreStub})); + relayLoadMoreStub.reset(); + + wrapper.instance()._attemptToLoadMoreReviews(); + assert.strictEqual(relayLoadMoreStub.callCount, 0); + }); + + it('calls loadMore immediately if hasMore is true and isLoading is false', function() { + const relayLoadMoreStub = sinon.stub(); + const relayHasMore = () => { return true; }; + const wrapper = shallow(buildApp({relayHasMore, relayLoadMore: relayLoadMoreStub})); + relayLoadMoreStub.reset(); + + wrapper.instance()._attemptToLoadMoreReviews(); + assert.strictEqual(relayLoadMoreStub.callCount, 1); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleError]); + }); + + it('calls loadMore after a timeout if hasMore is true and isLoading is true', function() { + const relayLoadMoreStub = sinon.stub(); + const relayHasMore = () => { return true; }; + const relayIsLoading = () => { return true; }; + const wrapper = shallow(buildApp({relayHasMore, relayIsLoading, relayLoadMore: relayLoadMoreStub})); + // advancing the timer and resetting the stub to clear the initial calls of + // _attemptToLoadMoreReviews when the component is initially mounted. + clock.tick(PAGINATION_WAIT_TIME_MS); + relayLoadMoreStub.reset(); + + wrapper.instance()._attemptToLoadMoreReviews(); + assert.strictEqual(relayLoadMoreStub.callCount, 0); + + clock.tick(PAGINATION_WAIT_TIME_MS); + assert.strictEqual(relayLoadMoreStub.callCount, 1); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleError]); + }); + }); + describe('_loadMoreReviews', function() { it('calls this.props.relay.loadMore with correct args', function() { const relayLoadMoreStub = sinon.stub(); From 5a9fa489d3868650e6af0dea2abe842c60642b45 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 8 Jan 2019 14:30:54 -0500 Subject: [PATCH 2522/4847] :arrow_up: Relay and family --- package-lock.json | 205 ++++++++++++++++++++++++++-------------------- package.json | 8 +- 2 files changed, 119 insertions(+), 94 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6deb8786ee..a400756b8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -186,9 +186,9 @@ } }, "@nodelib/fs.stat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.2.tgz", - "integrity": "sha512-yprFYuno9FtNsSHVlSWd+nRlmGoAbqbeCwOryP6sC/zoCjhpArcRMYp19EvpSUSizJAlsXEwJv+wcWS9XaXdMw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", "dev": true }, "@sinonjs/formatio": { @@ -370,7 +370,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -956,11 +955,21 @@ } } }, + "babel-plugin-macros": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.4.5.tgz", + "integrity": "sha512-+/9yteNQw3yuZ3krQUfjAeoT/f4EAdn3ELwhFfDj0rTMIaoHfIdrcLePOfIaL0qmFLpIcgPIL2Lzm58h+CGWaw==", + "requires": { + "cosmiconfig": "^5.0.5", + "resolve": "^1.8.1" + } + }, "babel-plugin-relay": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-relay/-/babel-plugin-relay-1.6.0.tgz", - "integrity": "sha1-oiTaUkNi1pA6UkIUobhAUw/fvSg=", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/babel-plugin-relay/-/babel-plugin-relay-1.7.0.tgz", + "integrity": "sha512-4kDgElsQ3+m1YHGinm2CWu55XzpPqEzf42JuYWUAJWvTBcHkd/VGVftO9C6BjnssUU7fDH9izn3qMtp0XFWGKw==", "requires": { + "babel-plugin-macros": "^2.0.0", "babel-runtime": "^6.23.0", "babel-types": "^6.24.1" } @@ -1821,6 +1830,21 @@ "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", "dev": true }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "requires": { + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" + } + } + }, "caller-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", @@ -2152,6 +2176,28 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "cosmiconfig": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.7.tgz", + "integrity": "sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA==", + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0" + }, + "dependencies": { + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + } + } + }, "cross-env": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz", @@ -2842,7 +2888,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -3164,8 +3209,7 @@ "esprima": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=", - "dev": true + "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=" }, "esquery": { "version": "1.0.1", @@ -3417,16 +3461,16 @@ "dev": true }, "fast-glob": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.3.tgz", - "integrity": "sha512-NiX+JXjnx43RzvVFwRWfPKo4U+1BrK5pJPsHQdKMlLoFHrrGktXglQhHliSihWAq+m1z6fHk3uwGHrtRbS9vLA==", + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.6.tgz", + "integrity": "sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w==", "dev": true, "requires": { "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.0.1", + "@nodelib/fs.stat": "^1.1.2", "glob-parent": "^3.1.0", "is-glob": "^4.0.0", - "merge2": "^1.2.1", + "merge2": "^1.2.3", "micromatch": "^3.1.10" } }, @@ -3451,9 +3495,9 @@ } }, "fbjs": { - "version": "0.8.16", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", - "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", "requires": { "core-js": "^1.0.0", "isomorphic-fetch": "^2.1.1", @@ -3461,22 +3505,13 @@ "object-assign": "^4.1.0", "promise": "^7.1.1", "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.9" + "ua-parser-js": "^0.7.18" }, "dependencies": { "core-js": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" - }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } } } }, @@ -4116,6 +4151,30 @@ "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=", "dev": true }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "dependencies": { + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + } + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -4260,8 +4319,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-boolean-object": { "version": "1.0.0", @@ -4334,6 +4392,11 @@ } } }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" + }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -4705,7 +4768,6 @@ "version": "3.11.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz", "integrity": "sha1-WXwai9VxUvJtYizkEXhRpR9euu8=", - "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -4722,6 +4784,11 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -6230,8 +6297,7 @@ "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "path-to-regexp": { "version": "1.7.0", @@ -6543,14 +6609,14 @@ "dev": true }, "react-relay": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/react-relay/-/react-relay-1.6.0.tgz", - "integrity": "sha512-8clmRHXNo96pcdkA8ZeiqF7xGjE+mjSbdX/INj5upRm2M8AprSrFk2Oz5nH084O+0hvXQhZtFyraXJWQO9ld3A==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/react-relay/-/react-relay-1.7.0.tgz", + "integrity": "sha512-vZOs1iK6LxqeaAelwSuD5eVXnQux5eVIrik/kxKt6Y3j6ylrjrdTadmgO6sapGc0TG61VtFK5CKPOtW+XSNotg==", "requires": { "babel-runtime": "^6.23.0", - "fbjs": "^0.8.14", + "fbjs": "0.8.17", "prop-types": "^15.5.8", - "relay-runtime": "1.6.0" + "relay-runtime": "1.7.0" } }, "react-select": { @@ -6843,33 +6909,10 @@ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "dev": true }, - "fbjs": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", - "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", - "dev": true, - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", - "dev": true - } - } - }, "jsesc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", - "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, "lodash": { @@ -6883,32 +6926,16 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true - }, - "relay-runtime": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/relay-runtime/-/relay-runtime-1.7.0.tgz", - "integrity": "sha512-gvx01aRoLHdIMQoIjMQ79js4BR9JZVfF/SoSiLXvWOgDWEnD7RKb80zmCZTByCpka0GwFzkVwBWUy1gW6g0zlQ==", - "dev": true, - "requires": { - "babel-runtime": "^6.23.0", - "fbjs": "0.8.17" - } - }, - "ua-parser-js": { - "version": "0.7.19", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz", - "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==", - "dev": true } } }, "relay-runtime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/relay-runtime/-/relay-runtime-1.6.0.tgz", - "integrity": "sha512-UJiEHp8CX2uFxXdM0nVLTCQ6yAT0GLmyMceXLISuW/l2a9jrS9a4MdZgdr/9UkkYno7Sj1hU/EUIQ0GaVkou8g==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/relay-runtime/-/relay-runtime-1.7.0.tgz", + "integrity": "sha512-gvx01aRoLHdIMQoIjMQ79js4BR9JZVfF/SoSiLXvWOgDWEnD7RKb80zmCZTByCpka0GwFzkVwBWUy1gW6g0zlQ==", "requires": { "babel-runtime": "^6.23.0", - "fbjs": "^0.8.14" + "fbjs": "0.8.17" } }, "repeat-element": { @@ -7001,7 +7028,6 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz", "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==", - "dev": true, "requires": { "path-parse": "^1.0.6" } @@ -7484,8 +7510,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { "version": "1.14.1", @@ -8101,9 +8126,9 @@ "dev": true }, "ua-parser-js": { - "version": "0.7.14", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.14.tgz", - "integrity": "sha1-EQ1T+kw/MmwSEpK76skE0uAzh8o=" + "version": "0.7.19", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz", + "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==" }, "uglify-js": { "version": "2.8.29", diff --git a/package.json b/package.json index 7979e96b16..2a6656ad67 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "atom-babel6-transpiler": "1.2.0", "babel-generator": "6.26.1", "babel-plugin-chai-assert-async": "0.1.0", - "babel-plugin-relay": "1.6.0", + "babel-plugin-relay": "1.7.0", "babel-plugin-transform-class-properties": "6.24.1", "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", "babel-plugin-transform-object-rest-spread": "6.26.0", @@ -61,10 +61,10 @@ "prop-types": "15.6.2", "react": "16.7.0", "react-dom": "16.7.0", - "react-relay": "1.6.0", + "react-relay": "1.7.0", "react-select": "1.2.1", "react-tabs": "^3.0.0", - "relay-runtime": "1.6.0", + "relay-runtime": "1.7.0", "temp": "0.9.0", "tinycolor2": "1.4.1", "tree-kill": "1.2.1", @@ -75,10 +75,10 @@ }, "devDependencies": { "@smashwilson/atom-mocha-test-runner": "1.4.0", + "@smashwilson/codecov": "3.1.1-azure0.0", "babel-plugin-istanbul": "4.1.6", "chai": "4.1.2", "chai-as-promised": "7.1.1", - "@smashwilson/codecov": "3.1.1-azure0.0", "cross-env": "5.2.0", "cross-unzip": "0.2.1", "dedent-js": "1.0.1", From 5a899aa4ffb848bb958af530f3c36953562b10e3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 8 Jan 2019 14:44:57 -0500 Subject: [PATCH 2523/4847] :arrow_up: dev dependencies --- package-lock.json | 2630 +++++++++++++++++++++++++++------------------ package.json | 16 +- 2 files changed, 1569 insertions(+), 1077 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6deb8786ee..7a11d91370 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,73 +11,79 @@ "dev": true }, "@babel/code-frame": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.49.tgz", - "integrity": "sha1-vs2AVIJzREDJ0TfkbXc0DmTX9Rs=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", "dev": true, "requires": { - "@babel/highlight": "7.0.0-beta.49" + "@babel/highlight": "^7.0.0" } }, "@babel/generator": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.49.tgz", - "integrity": "sha1-6c/9qROZaszseTu8JauRvBnQv3o=", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.2.2.tgz", + "integrity": "sha512-I4o675J/iS8k+P38dvJ3IBGqObLXyQLTxtrR4u9cSUJOURvafeEWb/pFMOTwtNrmq73mJzyF6ueTbO1BtN0Zeg==", "dev": true, "requires": { - "@babel/types": "7.0.0-beta.49", + "@babel/types": "^7.2.2", "jsesc": "^2.5.1", - "lodash": "^4.17.5", + "lodash": "^4.17.10", "source-map": "^0.5.0", "trim-right": "^1.0.1" }, "dependencies": { "jsesc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", - "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true } } }, "@babel/helper-function-name": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.49.tgz", - "integrity": "sha1-olwRGbnwNSeGcBJuAiXAMEHI3jI=", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "7.0.0-beta.49", - "@babel/template": "7.0.0-beta.49", - "@babel/types": "7.0.0-beta.49" + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-get-function-arity": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.49.tgz", - "integrity": "sha1-z1Aj8y0q2S0Ic3STnOwJUby1FEE=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", "dev": true, "requires": { - "@babel/types": "7.0.0-beta.49" + "@babel/types": "^7.0.0" } }, "@babel/helper-split-export-declaration": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.49.tgz", - "integrity": "sha1-QNeO2glo0BGxxShm5XRs+yPldUg=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", + "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", "dev": true, "requires": { - "@babel/types": "7.0.0-beta.49" + "@babel/types": "^7.0.0" } }, "@babel/highlight": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.49.tgz", - "integrity": "sha1-lr3GtD4TSCASumaRsQGEktOWIsw=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", - "js-tokens": "^3.0.0" + "js-tokens": "^4.0.0" }, "dependencies": { "ansi-styles": { @@ -90,9 +96,9 @@ } }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -100,10 +106,16 @@ "supports-color": "^5.3.0" } }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -112,67 +124,85 @@ } }, "@babel/parser": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.0.0-beta.49.tgz", - "integrity": "sha1-lE0MW6KBK7FZ7b0iZ0Ov0mUXm9w=", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.2.3.tgz", + "integrity": "sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA==", "dev": true }, "@babel/template": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.49.tgz", - "integrity": "sha1-44q+ghfLl5P0YaUwbXrXRdg+HSc=", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", + "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0-beta.49", - "@babel/parser": "7.0.0-beta.49", - "@babel/types": "7.0.0-beta.49", - "lodash": "^4.17.5" + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.2.2", + "@babel/types": "^7.2.2" } }, "@babel/traverse": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.49.tgz", - "integrity": "sha1-TypzaCoYM07WYl0QCo0nMZ98LWg=", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", + "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0-beta.49", - "@babel/generator": "7.0.0-beta.49", - "@babel/helper-function-name": "7.0.0-beta.49", - "@babel/helper-split-export-declaration": "7.0.0-beta.49", - "@babel/parser": "7.0.0-beta.49", - "@babel/types": "7.0.0-beta.49", - "debug": "^3.1.0", + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.2.2", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.2.3", + "@babel/types": "^7.2.2", + "debug": "^4.1.0", "globals": "^11.1.0", - "invariant": "^2.2.0", - "lodash": "^4.17.5" + "lodash": "^4.17.10" }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "globals": { - "version": "11.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", - "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", + "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==", + "dev": true + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true } } }, "@babel/types": { - "version": "7.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.49.tgz", - "integrity": "sha1-t+Oxw/TUz+Eb34yJ8e/V4WF7h6Y=", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.2.2.tgz", + "integrity": "sha512-fKCuD6UFUMkR541eDWL+2ih/xFZBXPOg/7EQFeTluMDebfqR4jrpaCjLhkWlQS4hT6nRa2PMEgXKbRB5/H2fpg==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.5", + "lodash": "^4.17.10", "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + } } }, "@mrmlnc/readdir-enhanced": { @@ -191,13 +221,33 @@ "integrity": "sha512-yprFYuno9FtNsSHVlSWd+nRlmGoAbqbeCwOryP6sC/zoCjhpArcRMYp19EvpSUSizJAlsXEwJv+wcWS9XaXdMw==", "dev": true }, + "@sinonjs/commons": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.3.0.tgz", + "integrity": "sha512-j4ZwhaHmwsCb4DlDOIWnI5YyKDNMoNThsmwEpfHx6a1EpsGZ9qYLxP++LMlmBRjtGptGHFsGItJ768snllFWpA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, "@sinonjs/formatio": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", - "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.1.0.tgz", + "integrity": "sha512-ZAR2bPHOl4Xg6eklUGpsdiIJ4+J1SNag1DHHrG/73Uz/nVwXqjgUtRPLoS+aVyieN9cSbc0E4LsU984tWcDyNg==", + "dev": true, + "requires": { + "@sinonjs/samsam": "^2 || ^3" + } + }, + "@sinonjs/samsam": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.0.2.tgz", + "integrity": "sha512-m08g4CS3J6lwRQk1pj1EO+KEVWbrbXsmi9Pw0ySmrIbcVxVaedoFgLvFsV8wHLwh01EpROVz3KvVcD1Jmks9FQ==", "dev": true, "requires": { - "samsam": "1.3.0" + "@sinonjs/commons": "^1.0.2", + "array-from": "^2.1.1", + "lodash.get": "^4.4.2" } }, "@smashwilson/atom-mocha-test-runner": { @@ -255,19 +305,16 @@ } }, "acorn": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", - "integrity": "sha1-8JWCkpdwanyXdpWMCvyJMKm52dg=", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.5.tgz", + "integrity": "sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==", "dev": true }, "acorn-jsx": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-4.1.1.tgz", - "integrity": "sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw==", - "dev": true, - "requires": { - "acorn": "^5.0.3" - } + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true }, "agent-base": { "version": "4.2.1", @@ -289,38 +336,6 @@ "json-schema-traverse": "^0.3.0" } }, - "ajv-keywords": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", - "dev": true - }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true - }, "ansi-escapes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", @@ -337,26 +352,11 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, - "append-transform": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", - "dev": true, - "requires": { - "default-require-extensions": "^2.0.0" - } - }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=" }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, "are-we-there-yet": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", @@ -415,6 +415,12 @@ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, "array-includes": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", @@ -491,7 +497,7 @@ "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha1-5gtrDo8wG9l+U3UhW9pAbIURjAs=", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, "assign-symbols": { @@ -522,10 +528,10 @@ "private": "~0.1.6" } }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, "asynckit": { @@ -559,9 +565,9 @@ "dev": true }, "axobject-query": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.1.tgz", - "integrity": "sha1-Bd+nBa2orZ25k/polvItOVsLCgc=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", "dev": true, "requires": { "ast-types-flow": "0.0.7" @@ -916,43 +922,58 @@ } }, "babel-plugin-istanbul": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", - "integrity": "sha1-NsWbIZLvzoHFs3gyG3QXWt0cmkU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.0.tgz", + "integrity": "sha512-CLoXPRSUWiR8yao8bShqZUIC6qLfZVVY3X1wj+QPNXu0wfmrRRfarh1LYy+dYMVI+bDj0ghy3tuqFFRFZmL1Nw==", "dev": true, "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.13.0", - "find-up": "^2.1.0", - "istanbul-lib-instrument": "^1.10.1", - "test-exclude": "^4.2.1" + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.0.0", + "test-exclude": "^5.0.0" }, "dependencies": { - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } }, - "istanbul-lib-coverage": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz", - "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==", - "dev": true + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } }, - "istanbul-lib-instrument": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz", - "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.0", - "semver": "^5.3.0" + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true } } }, @@ -1804,36 +1825,16 @@ "unset-value": "^1.0.0" } }, - "caching-transform": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-1.0.1.tgz", - "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", - "dev": true, - "requires": { - "md5-hex": "^1.2.0", - "mkdirp": "^0.5.1", - "write-file-atomic": "^1.1.4" - } - }, "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", "dev": true }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "requires": { - "callsites": "^0.2.0" - } - }, "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", + "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", "dev": true }, "camelcase": { @@ -1871,27 +1872,18 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, "chai": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", - "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", "dev": true, "requires": { - "assertion-error": "^1.0.1", - "check-error": "^1.0.1", - "deep-eql": "^3.0.0", + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", "get-func-name": "^2.0.0", - "pathval": "^1.0.0", - "type-detect": "^4.0.0" + "pathval": "^1.1.0", + "type-detect": "^4.0.5" } }, "chai-as-promised": { @@ -1916,9 +1908,9 @@ } }, "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, "charenc": { @@ -1963,7 +1955,7 @@ "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY=", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, "class-utils": { @@ -2060,17 +2052,19 @@ } }, "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { - "color-name": "^1.1.1" + "color-name": "1.1.3" } }, "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "colors": { "version": "0.5.1", @@ -2092,12 +2086,6 @@ "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, "compare-sets": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/compare-sets/-/compare-sets-1.0.1.tgz", @@ -2255,12 +2243,6 @@ "ms": "2.0.0" } }, - "debug-log": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", - "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", - "dev": true - }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -2290,7 +2272,7 @@ "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha1-38lARACtHI/gI+faHfHBR8S0RN8=", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { "type-detect": "^4.0.0" @@ -2313,15 +2295,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "default-require-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", - "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", - "dev": true, - "requires": { - "strip-bom": "^3.0.0" - } - }, "deferred-leveldown": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-4.0.2.tgz", @@ -2383,21 +2356,6 @@ } } }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, - "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2427,6 +2385,33 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "discontinuous-range": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", @@ -2892,31 +2877,32 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.0.1.tgz", - "integrity": "sha512-D5nG2rErquLUstgUaxJlWB5+gu+U/3VDY0fk/Iuq8y9CUFy/7Y6oF4N2cR1tV8knzQvciIbfqfohd359xTLIKQ==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.12.0.tgz", + "integrity": "sha512-LntwyPxtOHrsJdcSwyQKVtHofPHdv+4+mFwEe91r2V13vqpM8yLr7b1sW+Oo/yheOPkWYsYlYJCkzlFAt8KV7g==", "dev": true, "requires": { - "ajv": "^6.5.0", - "babel-code-frame": "^6.26.0", + "@babel/code-frame": "^7.0.0", + "ajv": "^6.5.3", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", - "debug": "^3.1.0", + "debug": "^4.0.1", "doctrine": "^2.1.0", "eslint-scope": "^4.0.0", + "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", + "espree": "^5.0.0", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^2.0.0", "functional-red-black-tree": "^1.0.1", "glob": "^7.1.2", - "globals": "^11.5.0", - "ignore": "^3.3.3", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^5.2.0", - "is-resolvable": "^1.1.0", - "js-yaml": "^3.11.0", + "inquirer": "^6.1.0", + "js-yaml": "^3.12.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", "lodash": "^4.17.5", @@ -2927,26 +2913,24 @@ "path-is-inside": "^1.0.2", "pluralize": "^7.0.0", "progress": "^2.0.0", - "regexpp": "^1.1.0", - "require-uncached": "^1.0.3", - "semver": "^5.5.0", - "string.prototype.matchall": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", "strip-ansi": "^4.0.0", "strip-json-comments": "^2.0.1", - "table": "^4.0.3", + "table": "^5.0.2", "text-table": "^0.2.0" }, "dependencies": { "ajv": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", - "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", + "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.1" + "uri-js": "^4.2.2" } }, "ansi-regex": { @@ -2958,16 +2942,16 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" } }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -2989,12 +2973,12 @@ } }, "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "doctrine": { @@ -3013,9 +2997,9 @@ "dev": true }, "globals": { - "version": "11.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", - "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", + "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==", "dev": true }, "json-schema-traverse": { @@ -3024,6 +3008,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -3034,9 +3024,9 @@ } }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -3081,9 +3071,9 @@ "dev": true }, "eslint-plugin-jsx-a11y": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.1.tgz", - "integrity": "sha512-JsxNKqa3TwmPypeXNnI75FntkUktGzI1wSa1LgNZdSOMI+B4sxnr1lSF8m8lPiz4mKiC+14ysZQM4scewUrP7A==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.2.tgz", + "integrity": "sha512-7gSSmwb3A+fQwtw0arguwMdOdzmKUgnUcbSNlo+GjKLAQFuC2EZxWqG9XHRI8VscBJD5a8raz3RuxQNFW+XJbw==", "dev": true, "requires": { "aria-query": "^3.0.0", @@ -3145,20 +3135,27 @@ "estraverse": "^4.1.1" } }, + "eslint-utils": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", + "dev": true + }, "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", "dev": true }, "espree": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-4.0.0.tgz", - "integrity": "sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.0.tgz", + "integrity": "sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA==", "dev": true, "requires": { - "acorn": "^5.6.0", - "acorn-jsx": "^4.1.1" + "acorn": "^6.0.2", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" } }, "esprima": { @@ -3179,7 +3176,7 @@ "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { "estraverse": "^4.1.0" @@ -3302,16 +3299,25 @@ } }, "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", "dev": true, "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", "tmp": "^0.0.33" }, "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -3537,17 +3543,6 @@ } } }, - "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" - } - }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -3558,14 +3553,14 @@ } }, "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", "dev": true, "requires": { "circular-json": "^0.3.1", - "del": "^2.0.2", "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", "write": "^0.2.1" } }, @@ -3581,32 +3576,6 @@ "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", "dev": true }, - "foreground-child": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", - "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", - "dev": true, - "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "yallist": { - "version": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -3808,21 +3777,36 @@ "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=" }, "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", + "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", "dev": true, "requires": { "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "graceful-fs": { - "version": "4.1.11", + "dir-glob": "^2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, @@ -3860,45 +3844,6 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, - "handlebars": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", - "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", - "dev": true, - "requires": { - "async": "^1.4.0", - "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" - }, - "dependencies": { - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -3934,7 +3879,8 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "has-symbols": { "version": "1.0.0", @@ -4089,9 +4035,9 @@ "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" }, "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha1-Cpf7h2mG6AgcYxFg+PnziRV/AEM=", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "ignore-walk": { @@ -4116,6 +4062,16 @@ "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=", "dev": true }, + "import-fresh": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", + "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -4157,45 +4113,45 @@ "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=" }, "inquirer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", - "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz", + "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==", "dev": true, "requires": { "ansi-escapes": "^3.0.0", "chalk": "^2.0.0", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", - "external-editor": "^2.1.0", + "external-editor": "^3.0.0", "figures": "^2.0.0", - "lodash": "^4.3.0", + "lodash": "^4.17.10", "mute-stream": "0.0.7", "run-async": "^2.2.0", - "rxjs": "^5.5.2", + "rxjs": "^6.1.0", "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", + "strip-ansi": "^5.0.0", "through": "^2.3.6" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", + "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", "dev": true }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" } }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -4203,19 +4159,25 @@ "supports-color": "^5.3.0" } }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", + "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.0.0" } }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -4272,7 +4234,8 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=" + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", + "dev": true }, "is-builtin-module": { "version": "1.0.0", @@ -4420,30 +4383,6 @@ } } }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "dev": true - }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "requires": { - "is-path-inside": "^1.0.0" - } - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } - }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -4467,12 +4406,6 @@ "has": "^1.0.1" } }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", - "dev": true - }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -4522,7 +4455,8 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, "isobject": { "version": "3.0.1", @@ -4555,140 +4489,24 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "istanbul-lib-coverage": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz", - "integrity": "sha512-yMSw5xLIbdaxiVXHk3amfNM2WeBxLrwH/BCyZ9HvA/fylwziAIJOG2rKqWyLqEJqwKT725vxxqidv+SyynnGAA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", + "integrity": "sha512-nPvSZsVlbG9aLhZYaC3Oi1gT/tpyo3Yt5fNyf6NmcKIayz4VV/txxJFFKAK/gU4dcNn8ehsanBbVHVl0+amOLA==", "dev": true }, - "istanbul-lib-hook": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.0.tgz", - "integrity": "sha512-qm3dt628HKpCVtIjbdZLuQyXn0+LO8qz+YHQDfkeXuSk5D+p299SEV5DrnUUnPi2SXvdMmWapMYWiuE75o2rUQ==", - "dev": true, - "requires": { - "append-transform": "^1.0.0" - } - }, "istanbul-lib-instrument": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-2.2.0.tgz", - "integrity": "sha512-ozQGtlIw+/a/F3n6QwWiuuyRAPp64+g2GVsKYsIez0sgIEzkU5ZpL2uZ5pmAzbEJ82anlRaPlOQZzkRXspgJyg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.0.0.tgz", + "integrity": "sha512-eQY9vN9elYjdgN9Iv6NS/00bptm02EBBk70lRMaVjeA6QYocQgenVrSgC28TJurdnZa80AGO3ASdFN+w/njGiQ==", "dev": true, "requires": { - "@babel/generator": "7.0.0-beta.49", - "@babel/parser": "7.0.0-beta.49", - "@babel/template": "7.0.0-beta.49", - "@babel/traverse": "7.0.0-beta.49", - "@babel/types": "7.0.0-beta.49", - "istanbul-lib-coverage": "^2.0.0", + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "istanbul-lib-coverage": "^2.0.1", "semver": "^5.5.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "globals": { - "version": "11.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", - "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==" - }, - "jsesc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", - "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=" - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-report": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.0.tgz", - "integrity": "sha512-RiELmy9oIRYUv36ITOAhVum9PUvuj6bjyXVEKEHNiD1me6qXtxfx7vSEJWnjOGk2QmYw/GRFjLXWJv3qHpLceQ==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.0", - "make-dir": "^1.3.0", - "supports-color": "^5.4.0" - }, - "dependencies": { - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-2.0.0.tgz", - "integrity": "sha512-jenUeC0gMSSMGkvqD9xuNfs3nD7XWeXLhqaIkqHsNZ3DJBWPdlKEydE7Ya5aTgdWjrEQhrCYTv+J606cGC2vuQ==", - "dev": true, - "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^2.0.0", - "make-dir": "^1.3.0", - "rimraf": "^2.6.2", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.0.tgz", - "integrity": "sha512-HeZG0WHretI9FXBni5wZ9DOgNziqDCEwetxnme5k1Vv5e81uTqcsy3fMH99gXGDGKr1ea87TyGseDMa2h4HEUA==", - "dev": true, - "requires": { - "handlebars": "^4.0.11" } }, "iterall": { @@ -4702,9 +4520,9 @@ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" }, "js-yaml": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz", - "integrity": "sha1-WXwai9VxUvJtYizkEXhRpR9euu8=", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", + "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -4722,6 +4540,12 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -4774,9 +4598,9 @@ "dev": true }, "just-extend": { - "version": "1.1.27", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", + "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", "dev": true }, "keytar": { @@ -4794,11 +4618,6 @@ "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", "dev": true }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" - }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -4994,16 +4813,11 @@ "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" }, "lolex": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.1.tgz", - "integrity": "sha1-5AqMTR8UtTaqA+QqU3x6268MIL4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-3.0.0.tgz", + "integrity": "sha512-hcnW80h3j2lbUfFdMArd5UPA/vxZJ+G8vobd+wg3nVEQA0EigStbYcrG030FJxL6xiDDPEkoMatV9xIh5OecQQ==", "dev": true }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" - }, "loose-envify": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", @@ -5026,6 +4840,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", + "dev": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -5034,23 +4849,7 @@ "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true } } @@ -5087,21 +4886,6 @@ "is-buffer": "~1.1.1" } }, - "md5-hex": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz", - "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", - "dev": true, - "requires": { - "md5-o-matic": "^0.1.1" - } - }, - "md5-o-matic": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", - "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", - "dev": true - }, "mem": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", @@ -5204,23 +4988,6 @@ } } }, - "merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, "merge2": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", @@ -5546,16 +5313,24 @@ "dev": true }, "nise": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.2.tgz", - "integrity": "sha512-BxH/DxoQYYdhKgVAfqVy4pzXRZELHOIewzoesxpjYvpU+7YOalQhGNPf7wAx8pLrTNPrHRDlLOkAl8UI0ZpXjw==", + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.8.tgz", + "integrity": "sha512-kGASVhuL4tlAV0tvA34yJYZIVihrUt/5bDwpp4tTluigxUr2bBlJeDXmivb6NuEdFkqvdv/Ybb9dm16PSKUhtw==", "dev": true, "requires": { - "@sinonjs/formatio": "^2.0.0", - "just-extend": "^1.1.27", + "@sinonjs/formatio": "^3.1.0", + "just-extend": "^4.0.2", "lolex": "^2.3.2", "path-to-regexp": "^1.7.0", "text-encoding": "^0.6.4" + }, + "dependencies": { + "lolex": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", + "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", + "dev": true + } } }, "node-abi": { @@ -5663,242 +5438,1061 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nyc": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-13.0.0.tgz", - "integrity": "sha1-4Awm6b0zq16B7emSu+STCEhYmbY=", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-13.1.0.tgz", + "integrity": "sha512-3GyY6TpQ58z9Frpv4GMExE1SV2tAgYqC7HSy2omEhNiCT3mhT9NyiOvIE8zkbuJVFzmvvNTnE4h/7/wQae7xLg==", "dev": true, "requires": { "archy": "^1.0.0", "arrify": "^1.0.1", - "caching-transform": "^1.0.1", - "convert-source-map": "^1.5.1", + "caching-transform": "^2.0.0", + "convert-source-map": "^1.6.0", "debug-log": "^1.0.1", - "find-cache-dir": "^1.0.0", - "find-up": "^2.1.0", + "find-cache-dir": "^2.0.0", + "find-up": "^3.0.0", "foreground-child": "^1.5.6", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.0", - "istanbul-lib-hook": "^2.0.0", - "istanbul-lib-instrument": "^2.2.0", - "istanbul-lib-report": "^2.0.0", - "istanbul-lib-source-maps": "^2.0.0", - "istanbul-reports": "^1.5.0", + "glob": "^7.1.3", + "istanbul-lib-coverage": "^2.0.1", + "istanbul-lib-hook": "^2.0.1", + "istanbul-lib-instrument": "^3.0.0", + "istanbul-lib-report": "^2.0.2", + "istanbul-lib-source-maps": "^2.0.1", + "istanbul-reports": "^2.0.1", "make-dir": "^1.3.0", - "md5-hex": "^2.0.0", "merge-source-map": "^1.1.0", "resolve-from": "^4.0.0", "rimraf": "^2.6.2", "signal-exit": "^3.0.2", "spawn-wrap": "^1.4.2", - "test-exclude": "^4.2.2", + "test-exclude": "^5.0.0", + "uuid": "^3.3.2", "yargs": "11.1.0", "yargs-parser": "^9.0.2" }, "dependencies": { + "align-text": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, + "amdefine": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "bundled": true, "dev": true }, - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "append-transform": { + "version": "1.0.0", + "bundled": true, + "dev": true, "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" - } + "default-require-extensions": "^2.0.0" } }, - "cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", - "requires": { - "lru-cache": "^4.0.1", + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "async": { + "version": "1.5.2", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "caching-transform": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "make-dir": "^1.0.0", + "md5-hex": "^2.0.0", + "package-hash": "^2.0.0", + "write-file-atomic": "^2.0.0" + } + }, + "camelcase": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true + }, + "center-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "cliui": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "commondir": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cross-spawn": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^4.0.1", "which": "^1.2.9" } }, "debug": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "bundled": true, + "dev": true, "requires": { "ms": "2.0.0" } }, + "debug-log": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "default-require-extensions": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, + "error-ex": { + "version": "1.3.2", + "bundled": true, + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es6-error": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "execa": { + "version": "0.7.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } + } + }, + "find-cache-dir": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "foreground-child": { + "version": "1.5.6", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^4", + "signal-exit": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "handlebars": { + "version": "4.0.11", + "bundled": true, + "dev": true, + "requires": { + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "bundled": true, + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "has-flag": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "hosted-git-info": { + "version": "2.7.1", + "bundled": true, + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "bundled": true, + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "istanbul-lib-coverage": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.1", + "make-dir": "^1.3.0", + "supports-color": "^5.4.0" + } + }, + "istanbul-lib-source-maps": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "debug": "^3.1.0", + "istanbul-lib-coverage": "^2.0.1", + "make-dir": "^1.3.0", + "rimraf": "^2.6.2", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "bundled": true, + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "handlebars": "^4.0.11" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "bundled": true, + "dev": true }, "kind-of": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "bundled": true, + "dev": true, "requires": { "is-buffer": "^1.1.5" } }, + "lazy-cache": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "optional": true + }, + "lcid": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash.flattendeep": { + "version": "4.4.0", + "bundled": true, + "dev": true + }, + "longest": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "lru-cache": { + "version": "4.1.3", + "bundled": true, + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, "md5-hex": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz", - "integrity": "sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM=", + "bundled": true, "dev": true, "requires": { "md5-o-matic": "^0.1.1" } }, + "md5-o-matic": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "mem": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "merge-source-map": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "bundled": true, + "dev": true + } + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "version": "0.0.10", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + } + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } }, "optimist": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "bundled": true, + "dev": true, "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" } }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "package-hash": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "lodash.flattendeep": "^4.4.0", + "md5-hex": "^2.0.0", + "release-zalgo": "^1.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "path-type": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "release-zalgo": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "repeat-string": { + "version": "1.6.1", + "bundled": true, + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, "resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "bundled": true, + "dev": true + }, + "right-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, "dev": true }, "semver": { "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "source-map": { + "version": "0.5.7", + "bundled": true, + "dev": true, + "optional": true + }, + "spawn-wrap": { + "version": "1.4.2", + "bundled": true, + "dev": true, + "requires": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } }, "strip-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "bundled": true, "dev": true, "requires": { "ansi-regex": "^3.0.0" } }, + "strip-bom": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, "supports-color": { "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "bundled": true, + "dev": true, "requires": { "has-flag": "^3.0.0" } }, "test-exclude": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.2.tgz", - "integrity": "sha512-2kTGf+3tykCfrWVREgyTR0bmVO0afE6i7zVXi/m+bZZ8ujV89Aulxdcdv32yH+unVFg3Y5o6GA8IzsHnGQuFgQ==", + "version": "5.0.0", + "bundled": true, "dev": true, "requires": { "arrify": "^1.0.1", "minimatch": "^3.0.4", - "read-pkg-up": "^3.0.0", + "read-pkg-up": "^4.0.0", "require-main-filename": "^1.0.1" + } + }, + "uglify-js": { + "version": "2.8.29", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" }, "dependencies": { - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "yargs": { + "version": "3.10.0", + "bundled": true, "dev": true, + "optional": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "dependencies": { - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - } + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "uuid": { + "version": "3.3.2", + "bundled": true, + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "window-size": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "0.0.3", + "bundled": true, + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, "dev": true, "requires": { - "pify": "^3.0.0" + "number-is-nan": "^1.0.0" } }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "string-width": { + "version": "1.0.2", + "bundled": true, "dev": true, "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, - "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "strip-ansi": { + "version": "3.0.1", + "bundled": true, "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "ansi-regex": "^2.0.0" } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true } } }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "y18n": { + "version": "3.2.1", + "bundled": true, + "dev": true + }, "yallist": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + "bundled": true, + "dev": true }, "yargs": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", - "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", + "bundled": true, "dev": true, "requires": { "cliui": "^4.0.0", @@ -5915,16 +6509,9 @@ "yargs-parser": "^9.0.2" }, "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, "cliui": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "bundled": true, "dev": true, "requires": { "string-width": "^2.1.1", @@ -5932,21 +6519,49 @@ "wrap-ansi": "^2.0.0" } }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "find-up": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, "dev": true, "requires": { - "camelcase": "^4.1.0" + "p-limit": "^1.1.0" } + }, + "p-try": { + "version": "1.0.0", + "bundled": true, + "dev": true } } }, "yargs-parser": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "bundled": true, "dev": true, "requires": { "camelcase": "^4.1.0" @@ -5954,8 +6569,7 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "bundled": true, "dev": true } } @@ -6174,6 +6788,15 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, + "parent-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.0.tgz", + "integrity": "sha512-8Mf5juOMmiE4FcmzYc4IaiS9L3+9paz2KOiXzkRviCP6aDmN49Hz6EMWz0lGNp9pX80GvvAuLADtyGfW/Em3TA==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", @@ -6289,15 +6912,6 @@ "pinkie": "^2.0.0" } }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", @@ -6405,7 +7019,8 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true }, "psl": { "version": "1.1.29", @@ -6709,19 +7324,10 @@ } } }, - "regexp.prototype.flags": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz", - "integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==", - "dev": true, - "requires": { - "define-properties": "^1.1.2" - } - }, "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, "relay-compiler": { @@ -6920,7 +7526,8 @@ "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true }, "repeating": { "version": "2.0.1", @@ -6987,16 +7594,6 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - } - }, "resolve": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz", @@ -7007,9 +7604,9 @@ } }, "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "resolve-url": { @@ -7034,14 +7631,6 @@ "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", "dev": true }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "requires": { - "align-text": "^0.1.1" - } - }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", @@ -7070,12 +7659,12 @@ } }, "rxjs": { - "version": "5.5.11", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.11.tgz", - "integrity": "sha512-3bjO7UwWfA2CV7lmwYMBzj4fQ6Cq+ftHc2MvUe+WMS7wcdJ1LosDWmdjPQanYp2dBRj572p7PeU81JUxHKOcBA==", + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", + "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", "dev": true, "requires": { - "symbol-observable": "1.0.1" + "tslib": "^1.9.0" } }, "safe-buffer": { @@ -7092,10 +7681,10 @@ "ret": "~0.1.10" } }, - "samsam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "scheduler": { @@ -7210,24 +7799,24 @@ } }, "sinon": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.0.1.tgz", - "integrity": "sha512-rfszhNcfamK2+ofIPi9XqeH89pH7KGDcAtM+F9CsjHXOK3jzWG99vyhyD2V+r7s4IipmWcWUFYq4ftZ9/Eu2Wg==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.2.2.tgz", + "integrity": "sha512-WLagdMHiEsrRmee3jr6IIDntOF4kbI6N2pfbi8wkv50qaUQcBglkzkjtoOEbeJ2vf1EsrHhLI+5Ny8//WHdMoA==", "dev": true, "requires": { - "@sinonjs/formatio": "^2.0.0", + "@sinonjs/commons": "^1.2.0", + "@sinonjs/formatio": "^3.1.0", + "@sinonjs/samsam": "^3.0.2", "diff": "^3.5.0", - "lodash.get": "^4.4.2", - "lolex": "^2.4.2", - "nise": "^1.3.3", - "supports-color": "^5.4.0", - "type-detect": "^4.0.8" + "lolex": "^3.0.0", + "nise": "^1.4.7", + "supports-color": "^5.5.0" }, "dependencies": { "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -7241,14 +7830,25 @@ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" }, "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.0.0.tgz", + "integrity": "sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ==", "dev": true, "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" }, "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -7257,12 +7857,6 @@ } } }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", - "dev": true - }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -7402,20 +7996,6 @@ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, - "spawn-wrap": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", - "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", - "dev": true, - "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - } - }, "spdx-correct": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", @@ -7562,19 +8142,6 @@ } } }, - "string.prototype.matchall": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-2.0.0.tgz", - "integrity": "sha512-WoZ+B2ypng1dp4iFLF2kmZlwwlE19gmjgKuhL1FJfDgCREWb3ye3SDVHSzLH6bxfnvYmkCxbzkmWcQZHA4P//Q==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.10.0", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "regexp.prototype.flags": "^1.2.0" - } - }, "string.prototype.trim": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", @@ -7642,56 +8209,28 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, - "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", - "dev": true - }, "table": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz", - "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/table/-/table-5.1.1.tgz", + "integrity": "sha512-NUjapYb/qd4PeFW03HnAuOJ7OMcBkJlqeClWxeNlQ0lXGSb52oZXGzkO0/I0ARegQ2eUT1g2VDJH0eUxDRcHmw==", "dev": true, "requires": { - "ajv": "^6.0.1", - "ajv-keywords": "^3.0.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", + "ajv": "^6.6.1", + "lodash": "^4.17.11", + "slice-ansi": "2.0.0", "string-width": "^2.1.1" }, "dependencies": { "ajv": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", - "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", + "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.1" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "uri-js": "^4.2.2" } }, "fast-deep-equal": { @@ -7706,14 +8245,11 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true } } }, @@ -7802,89 +8338,116 @@ } }, "test-exclude": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.1.tgz", - "integrity": "sha1-36Ii8DSAvKaSB8pyizfXS0X3JPo=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.0.0.tgz", + "integrity": "sha512-bO3Lj5+qFa9YLfYW2ZcXMOV1pmQvw+KS/DpjqhyX6Y6UZ8zstpZJ+mA2ERkXfpOqhxsJlQiLeVXD3Smsrs6oLw==", "dev": true, "requires": { "arrify": "^1.0.1", - "micromatch": "^3.1.8", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", "require-main-filename": "^1.0.1" }, "dependencies": { "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "locate-path": "^3.0.0" } }, "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" } }, - "path-exists": { + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { - "pinkie-promise": "^2.0.0" + "p-try": "^2.0.0" } }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "p-limit": "^2.0.0" } }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" } }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "pify": "^3.0.0" } }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { - "is-utf8": "^0.2.0" + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" } } } @@ -8065,6 +8628,12 @@ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -8091,7 +8660,7 @@ "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha1-dkb7XxiHHPu3dJ5pvTmmOI63RQw=", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, "typedarray": { @@ -8105,66 +8674,6 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.14.tgz", "integrity": "sha1-EQ1T+kw/MmwSEpK76skE0uAzh8o=" }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "dev": true, - "optional": true, - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true, - "optional": true - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "optional": true, - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true, - "optional": true - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "optional": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true, - "optional": true - }, "underscore": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", @@ -8396,6 +8905,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -8431,13 +8941,6 @@ } } }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true, - "optional": true - }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", @@ -8480,17 +8983,6 @@ "mkdirp": "^0.5.1" } }, - "write-file-atomic": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", - "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } - }, "x-is-array": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/x-is-array/-/x-is-array-0.1.0.tgz", diff --git a/package.json b/package.json index 7979e96b16..61d7625d5a 100644 --- a/package.json +++ b/package.json @@ -75,10 +75,10 @@ }, "devDependencies": { "@smashwilson/atom-mocha-test-runner": "1.4.0", - "babel-plugin-istanbul": "4.1.6", - "chai": "4.1.2", - "chai-as-promised": "7.1.1", "@smashwilson/codecov": "3.1.1-azure0.0", + "babel-plugin-istanbul": "5.1.0", + "chai": "4.2.0", + "chai-as-promised": "7.1.1", "cross-env": "5.2.0", "cross-unzip": "0.2.1", "dedent-js": "1.0.1", @@ -87,10 +87,10 @@ "electron-mksnapshot": "~2.0", "enzyme": "3.8.0", "enzyme-adapter-react-16": "1.7.1", - "eslint": "5.0.1", + "eslint": "5.12.0", "eslint-config-fbjs-opensource": "1.0.0", - "eslint-plugin-jsx-a11y": "^6.1.1", - "globby": "5.0.0", + "eslint-plugin-jsx-a11y": "6.1.2", + "globby": "8.0.1", "hock": "1.3.3", "lodash.isequalwith": "4.4.0", "mkdirp": "0.5.1", @@ -99,10 +99,10 @@ "mocha-multi-reporters": "^1.1.7", "mocha-stress": "1.0.0", "node-fetch": "2.3.0", - "nyc": "13.0.0", + "nyc": "13.1.0", "relay-compiler": "1.7.0", "semver": "5.6.0", - "sinon": "6.0.1", + "sinon": "7.2.2", "test-until": "1.1.1" }, "consumedServices": { From eed5b9d2714fcd506a817120d30d84f6f9f14272 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 8 Jan 2019 15:18:14 -0500 Subject: [PATCH 2524/4847] Relay changed its generated component names --- .../issueish-detail-controller.test.js | 30 +++++++++---------- test/views/issue-detail-view.test.js | 6 ++-- test/views/issueish-timeline-view.test.js | 10 +++---- test/views/pr-detail-view.test.js | 29 +++++++++--------- test/views/pr-statuses-view.test.js | 2 +- .../commit-comment-thread-view.test.js | 2 +- .../cross-referenced-events-view.test.js | 2 +- 7 files changed, 41 insertions(+), 40 deletions(-) diff --git a/test/controllers/issueish-detail-controller.test.js b/test/controllers/issueish-detail-controller.test.js index 422b6b6aab..b3687ca7d2 100644 --- a/test/controllers/issueish-detail-controller.test.js +++ b/test/controllers/issueish-detail-controller.test.js @@ -105,29 +105,29 @@ describe('IssueishDetailController', function() { }); it('is disabled if the repository is loading or absent', function() { const wrapper = shallow(buildApp({}, {isAbsent: true})); - const op = wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp'); + const op = wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp'); assert.isFalse(op.isEnabled()); assert.strictEqual(op.getMessage(), 'No repository found'); wrapper.setProps({isAbsent: false, isLoading: true}); - const op1 = wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp'); + const op1 = wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp'); assert.isFalse(op1.isEnabled()); assert.strictEqual(op1.getMessage(), 'Loading'); wrapper.setProps({isAbsent: false, isLoading: false, isPresent: false}); - const op2 = wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp'); + const op2 = wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp'); assert.isFalse(op2.isEnabled()); assert.strictEqual(op2.getMessage(), 'No repository found'); }); it('is disabled if the local repository is merging or rebasing', function() { const wrapper = shallow(buildApp({}, {isMerging: true})); - const op0 = wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp'); + const op0 = wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp'); assert.isFalse(op0.isEnabled()); assert.strictEqual(op0.getMessage(), 'Merge in progress'); wrapper.setProps({isMerging: false, isRebasing: true}); - const op1 = wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp'); + const op1 = wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp'); assert.isFalse(op1.isEnabled()); assert.strictEqual(op1.getMessage(), 'Rebase in progress'); }); @@ -135,7 +135,7 @@ describe('IssueishDetailController', function() { const props = issueishDetailControllerProps({}, {}); props.repository.pullRequest.headRepository = null; const wrapper = shallow(buildApp({}, {...props})); - const op = wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp'); + const op = wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp'); assert.isFalse(op.isEnabled()); assert.strictEqual(op.getMessage(), 'Pull request head repository does not exist'); }); @@ -159,7 +159,7 @@ describe('IssueishDetailController', function() { remotes, })); - const op = wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp'); + const op = wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp'); assert.isFalse(op.isEnabled()); assert.strictEqual(op.getMessage(), 'Current'); }); @@ -185,7 +185,7 @@ describe('IssueishDetailController', function() { remotes, })); - const op = wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp'); + const op = wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp'); assert.isFalse(op.isEnabled()); assert.strictEqual(op.getMessage(), 'Current'); }); @@ -217,7 +217,7 @@ describe('IssueishDetailController', function() { })); sinon.spy(reporterProxy, 'incrementCounter'); - await wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp').run(); + await wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp').run(); assert.isTrue(addRemote.calledWith('ccc', 'git@github.com:ccc/ddd.git')); assert.isTrue(fetch.calledWith('refs/heads/feature', {remoteName: 'ccc'})); @@ -255,7 +255,7 @@ describe('IssueishDetailController', function() { })); sinon.spy(reporterProxy, 'incrementCounter'); - await wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp').run(); + await wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp').run(); assert.isTrue(fetch.calledWith('refs/heads/clever-name', {remoteName: 'existing'})); assert.isTrue(checkout.calledWith('pr-789/ccc/clever-name', { @@ -298,7 +298,7 @@ describe('IssueishDetailController', function() { })); sinon.spy(reporterProxy, 'incrementCounter'); - await wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp').run(); + await wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp').run(); assert.isTrue(checkout.calledWith('existing')); assert.isTrue(pull.calledWith('refs/heads/yes', {remoteName: 'upstream', ffOnly: true})); @@ -310,7 +310,7 @@ describe('IssueishDetailController', function() { const wrapper = shallow(buildApp({}, {addRemote})); // Should not throw - await wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp').run(); + await wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp').run(); assert.isTrue(addRemote.called); }); @@ -319,7 +319,7 @@ describe('IssueishDetailController', function() { const wrapper = shallow(buildApp({}, {addRemote})); await assert.isRejected( - wrapper.find('Relay(BarePullRequestDetailView)').prop('checkoutOp').run(), + wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('checkoutOp').run(), /not handled by the pipeline/, ); assert.isTrue(addRemote.called); @@ -329,7 +329,7 @@ describe('IssueishDetailController', function() { describe('openCommit', function() { it('opens a CommitDetailItem in the workspace', async function() { const wrapper = shallow(buildApp({}, {workdirPath: __dirname})); - await wrapper.find('Relay(BarePullRequestDetailView)').prop('openCommit')({sha: '1234'}); + await wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('openCommit')({sha: '1234'}); assert.include( atomEnv.workspace.getPaneItems().map(item => item.getURI()), @@ -341,7 +341,7 @@ describe('IssueishDetailController', function() { sinon.stub(reporterProxy, 'addEvent'); const wrapper = shallow(buildApp({}, {workdirPath: __dirname})); - await wrapper.find('Relay(BarePullRequestDetailView)').prop('openCommit')({sha: '1234'}); + await wrapper.find('ForwardRef(Relay(BarePullRequestDetailView))').prop('openCommit')({sha: '1234'}); assert.isTrue( reporterProxy.addEvent.calledWith( diff --git a/test/views/issue-detail-view.test.js b/test/views/issue-detail-view.test.js index ecf93724e1..9417b269c6 100644 --- a/test/views/issue-detail-view.test.js +++ b/test/views/issue-detail-view.test.js @@ -34,7 +34,7 @@ describe('IssueDetailView', function() { assert.strictEqual(link.text(), 'user1/repo#200'); assert.strictEqual(link.prop('href'), 'https://github.com/user1/repo/issues/200'); - assert.isFalse(wrapper.find('Relay(PrStatuses)').exists()); + assert.isFalse(wrapper.find('ForwardRef(Relay(PrStatuses))').exists()); assert.isFalse(wrapper.find('.github-IssueishDetailView-checkoutButton').exists()); const avatarLink = wrapper.find('.github-IssueishDetailView-avatar'); @@ -49,8 +49,8 @@ describe('IssueDetailView', function() { assert.lengthOf(wrapper.find(EmojiReactionsView), 1); - assert.isNotNull(wrapper.find('Relay(IssueishTimelineView)').prop('issue')); - assert.notOk(wrapper.find('Relay(IssueishTimelineView)').prop('pullRequest')); + assert.isNotNull(wrapper.find('ForwardRef(Relay(IssueishTimelineView))').prop('issue')); + assert.notOk(wrapper.find('ForwardRef(Relay(IssueishTimelineView))').prop('pullRequest')); }); it('renders a placeholder issue body', function() { diff --git a/test/views/issueish-timeline-view.test.js b/test/views/issueish-timeline-view.test.js index 9f3479bbe7..4135f9961c 100644 --- a/test/views/issueish-timeline-view.test.js +++ b/test/views/issueish-timeline-view.test.js @@ -71,19 +71,19 @@ describe('IssueishTimelineView', function() { ], })); - const commitGroup0 = wrapper.find('Relay(BareCommitsView)').filterWhere(c => c.prop('nodes').length === 2); + const commitGroup0 = wrapper.find('ForwardRef(Relay(BareCommitsView))').filterWhere(c => c.prop('nodes').length === 2); assert.deepEqual(commitGroup0.prop('nodes').map(n => n.id), [0, 1]); - const commentGroup0 = wrapper.find('Grouped(Relay(BareIssueCommentView))').filterWhere(c => c.prop('nodes').length === 1); + const commentGroup0 = wrapper.find('Grouped(ForwardRef(Relay(BareIssueCommentView)))').filterWhere(c => c.prop('nodes').length === 1); assert.deepEqual(commentGroup0.prop('nodes').map(n => n.id), [2]); - const mergedGroup = wrapper.find('Grouped(Relay(BareMergedEventView))').filterWhere(c => c.prop('nodes').length === 1); + const mergedGroup = wrapper.find('Grouped(ForwardRef(Relay(BareMergedEventView)))').filterWhere(c => c.prop('nodes').length === 1); assert.deepEqual(mergedGroup.prop('nodes').map(n => n.id), [3]); - const commitGroup1 = wrapper.find('Relay(BareCommitsView)').filterWhere(c => c.prop('nodes').length === 4); + const commitGroup1 = wrapper.find('ForwardRef(Relay(BareCommitsView))').filterWhere(c => c.prop('nodes').length === 4); assert.deepEqual(commitGroup1.prop('nodes').map(n => n.id), [4, 5, 6, 7]); - const commentGroup1 = wrapper.find('Grouped(Relay(BareIssueCommentView))').filterWhere(c => c.prop('nodes').length === 2); + const commentGroup1 = wrapper.find('Grouped(ForwardRef(Relay(BareIssueCommentView)))').filterWhere(c => c.prop('nodes').length === 2); assert.deepEqual(commentGroup1.prop('nodes').map(n => n.id), [8, 9]); }); diff --git a/test/views/pr-detail-view.test.js b/test/views/pr-detail-view.test.js index 33f3a0b55e..62364fe02d 100644 --- a/test/views/pr-detail-view.test.js +++ b/test/views/pr-detail-view.test.js @@ -42,7 +42,7 @@ describe('PullRequestDetailView', function() { assert.isTrue(wrapper.find('.github-IssueishDetailView-checkoutButton').exists()); - assert.isDefined(wrapper.find('Relay(BarePrStatusesView)[displayType="check"]').prop('pullRequest')); + assert.isDefined(wrapper.find('ForwardRef(Relay(BarePrStatusesView))[displayType="check"]').prop('pullRequest')); const avatarLink = wrapper.find('.github-IssueishDetailView-avatar'); assert.strictEqual(avatarLink.prop('href'), 'https://github.com/author0'); @@ -56,9 +56,9 @@ describe('PullRequestDetailView', function() { assert.lengthOf(wrapper.find(EmojiReactionsView), 1); - assert.notOk(wrapper.find('Relay(IssueishTimelineView)').prop('issue')); - assert.isNotNull(wrapper.find('Relay(IssueishTimelineView)').prop('pullRequest')); - assert.isNotNull(wrapper.find('Relay(BarePrStatusesView)[displayType="full"]').prop('pullRequest')); + assert.notOk(wrapper.find('ForwardRef(Relay(IssueishTimelineView))').prop('issue')); + assert.isNotNull(wrapper.find('ForwardRef(Relay(IssueishTimelineView))').prop('pullRequest')); + assert.isNotNull(wrapper.find('ForwardRef(Relay(BarePrStatusesView))[displayType="full"]').prop('pullRequest')); assert.strictEqual(wrapper.find('.github-IssueishDetailView-baseRefName').text(), baseRefName); assert.strictEqual(wrapper.find('.github-IssueishDetailView-headRefName').text(), headRefName); @@ -104,28 +104,29 @@ describe('PullRequestDetailView', function() { checkoutOp: new EnableableOperation(() => {}).disable(checkoutStates.CURRENT), })); - assert.isTrue(wrapper.find('Relay(IssueishTimelineView)').prop('onBranch')); - assert.isTrue(wrapper.find('Relay(PrCommitsView)').prop('onBranch')); + assert.isTrue(wrapper.find('ForwardRef(Relay(IssueishTimelineView))').prop('onBranch')); + assert.isTrue(wrapper.find('ForwardRef(Relay(IssueishTimelineView))').prop('onBranch')); + assert.isTrue(wrapper.find('ForwardRef(Relay(PrCommitsView))').prop('onBranch')); }); it('tells its tabs when the pull request is not checked out', function() { const checkoutOp = new EnableableOperation(() => {}); const wrapper = shallow(buildApp({}, {checkoutOp})); - assert.isFalse(wrapper.find('Relay(IssueishTimelineView)').prop('onBranch')); - assert.isFalse(wrapper.find('Relay(PrCommitsView)').prop('onBranch')); + assert.isFalse(wrapper.find('ForwardRef(Relay(IssueishTimelineView))').prop('onBranch')); + assert.isFalse(wrapper.find('ForwardRef(Relay(PrCommitsView))').prop('onBranch')); wrapper.setProps({checkoutOp: checkoutOp.disable(checkoutStates.HIDDEN, 'message')}); - assert.isFalse(wrapper.find('Relay(IssueishTimelineView)').prop('onBranch')); - assert.isFalse(wrapper.find('Relay(PrCommitsView)').prop('onBranch')); + assert.isFalse(wrapper.find('ForwardRef(Relay(IssueishTimelineView))').prop('onBranch')); + assert.isFalse(wrapper.find('ForwardRef(Relay(PrCommitsView))').prop('onBranch')); wrapper.setProps({checkoutOp: checkoutOp.disable(checkoutStates.DISABLED, 'message')}); - assert.isFalse(wrapper.find('Relay(IssueishTimelineView)').prop('onBranch')); - assert.isFalse(wrapper.find('Relay(PrCommitsView)').prop('onBranch')); + assert.isFalse(wrapper.find('ForwardRef(Relay(IssueishTimelineView))').prop('onBranch')); + assert.isFalse(wrapper.find('ForwardRef(Relay(PrCommitsView))').prop('onBranch')); wrapper.setProps({checkoutOp: checkoutOp.disable(checkoutStates.BUSY, 'message')}); - assert.isFalse(wrapper.find('Relay(IssueishTimelineView)').prop('onBranch')); - assert.isFalse(wrapper.find('Relay(PrCommitsView)').prop('onBranch')); + assert.isFalse(wrapper.find('ForwardRef(Relay(IssueishTimelineView))').prop('onBranch')); + assert.isFalse(wrapper.find('ForwardRef(Relay(PrCommitsView))').prop('onBranch')); }); it('renders pull request information for cross repository PR', function() { diff --git a/test/views/pr-statuses-view.test.js b/test/views/pr-statuses-view.test.js index 65dc150fad..5b6077291f 100644 --- a/test/views/pr-statuses-view.test.js +++ b/test/views/pr-statuses-view.test.js @@ -109,7 +109,7 @@ describe('PrStatusesView', function() { it('renders a context view for each status context', function() { const wrapper = shallow(buildApp({summaryState: 'FAILURE', states: ['SUCCESS', 'FAILURE', 'ERROR']})); - const contextViews = wrapper.find('Relay(BarePrStatusContextView)'); + const contextViews = wrapper.find('ForwardRef(Relay(BarePrStatusContextView))'); assert.deepEqual(contextViews.map(v => v.prop('context').state), ['SUCCESS', 'FAILURE', 'ERROR']); }); diff --git a/test/views/timeline-items/commit-comment-thread-view.test.js b/test/views/timeline-items/commit-comment-thread-view.test.js index b80c1942a4..7c1248288e 100644 --- a/test/views/timeline-items/commit-comment-thread-view.test.js +++ b/test/views/timeline-items/commit-comment-thread-view.test.js @@ -24,7 +24,7 @@ describe('CommitCommentThreadView', function() { ], })); - const commentViews = wrapper.find('Relay(BareCommitCommentView)'); + const commentViews = wrapper.find('ForwardRef(Relay(BareCommitCommentView))'); assert.deepEqual(commentViews.map(c => c.prop('item').author.login), ['user0', 'user1', 'user2']); diff --git a/test/views/timeline-items/cross-referenced-events-view.test.js b/test/views/timeline-items/cross-referenced-events-view.test.js index 4834306516..ed678e91e0 100644 --- a/test/views/timeline-items/cross-referenced-events-view.test.js +++ b/test/views/timeline-items/cross-referenced-events-view.test.js @@ -15,7 +15,7 @@ describe('CrossReferencedEventsView', function() { it('renders a child component for each grouped child event', function() { const wrapper = shallow(buildApp({nodeOpts: [{}, {}, {}]})); - assert.lengthOf(wrapper.find('Relay(BareCrossReferencedEventView)'), 3); + assert.lengthOf(wrapper.find('ForwardRef(Relay(BareCrossReferencedEventView))'), 3); }); it('generates a summary based on a single pull request cross-reference', function() { From 313363ca77f93d3bb408d6f2a9b7f344cbb49189 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 8 Jan 2019 12:33:57 -0800 Subject: [PATCH 2525/4847] test for replying to an outdated comment --- test/controllers/pr-reviews-controller.test.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index 682550dc2b..eee6efb1e6 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -220,5 +220,22 @@ describe('PullRequestReviewsController', function() { assert.strictEqual(threadedComments[1].body, 'reply to OG comment'); }); + it('comments with a replyTo id that does not point to an existing comment are threaded separately', function() { + const outdatedCommentId = 1; + const replyToOutdatedCommentId = 2; + const review = reviewBuilder() + .id(2) + .submittedAt('2018-12-28T20:40:55Z') + .addComment(c => c.id(replyToOutdatedCommentId).path('file0.txt').replyTo(outdatedCommentId).body('reply to outdated comment')) + .build(); + + const wrapper = shallow(buildApp({reviewSpecs: [review]})); + wrapper.instance().collectComments({reviewId: review.id, submittedAt: review.submittedAt, comments: review.comments, fetchingMoreComments: false}); + + const comments = wrapper.instance().state[replyToOutdatedCommentId]; + assert.lengthOf(comments, 1); + assert.strictEqual(comments[0].body, 'reply to outdated comment'); + }); + }); }); From f07d2511f48569b1ce25b4462114668025670e41 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 8 Jan 2019 12:35:56 -0800 Subject: [PATCH 2526/4847] add a const for originalCommentId hopefully this makes the tests easier to understand? IDK. YOLO. --- test/controllers/pr-reviews-controller.test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index eee6efb1e6..e3eceb8df3 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -168,16 +168,17 @@ describe('PullRequestReviewsController', function() { describe('grouping and ordering comments', function() { it('groups the comments into threads based on replyId', function() { + const originalCommentId = 1; const review1 = reviewBuilder() .id(0) .submittedAt('2018-12-27T20:40:55Z') - .addComment(c => c.id(1).path('file0.txt').body('OG comment')) + .addComment(c => c.id(originalCommentId).path('file0.txt').body('OG comment')) .build(); const review2 = reviewBuilder() .id(1) .submittedAt('2018-12-28T20:40:55Z') - .addComment(c => c.id(2).path('file0.txt').replyTo(1).body('reply to OG comment')) + .addComment(c => c.id(2).path('file0.txt').replyTo(originalCommentId).body('reply to OG comment')) .build(); const reviewSpecs = [review1, review2]; From 86e8f2badc5b4c971159a0fd8b441094e9d64070 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 8 Jan 2019 12:56:31 -0800 Subject: [PATCH 2527/4847] :art: extra pedantic comment update --- lib/controllers/pr-reviews-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 140586d79f..428bb38b7b 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -74,8 +74,8 @@ export default class PullRequestReviewsController extends React.Component { * Threads can have comments belonging to multiple reviews. * We need a nested pagination container to fetch comment pages. * Upon fetching new comments, the `collectComments` method is called with all comments fetched for that review. - * Ultimately we want to organize comments based on the root comment they are replies to. - * So `renderCommentFetchingContainers` simply fetches data and doesn't render any DOM elements. + * Ultimately we want to group comments based on the root comment they are replies to. + * `renderCommentFetchingContainers` only fetches data and doesn't render any user visible DOM elements. * `PullRequestReviewCommentsView` renders the aggregated comment thread data. * */ return ( From db38949196b79531f19ad0fd2209575159b24f5c Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 8 Jan 2019 13:01:44 -0800 Subject: [PATCH 2528/4847] don't test sorting comments by date we don't actually sort the comments by date. They come in in order and then we reverse them for some reason. --- .../controllers/pr-reviews-controller.test.js | 35 ++++--------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index e3eceb8df3..d99ded32b1 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -167,8 +167,9 @@ describe('PullRequestReviewsController', function() { }); describe('grouping and ordering comments', function() { - it('groups the comments into threads based on replyId', function() { + it.only('groups the comments into threads based on replyId', function() { const originalCommentId = 1; + const singleCommentId = 5; const review1 = reviewBuilder() .id(0) .submittedAt('2018-12-27T20:40:55Z') @@ -179,6 +180,7 @@ describe('PullRequestReviewsController', function() { .id(1) .submittedAt('2018-12-28T20:40:55Z') .addComment(c => c.id(2).path('file0.txt').replyTo(originalCommentId).body('reply to OG comment')) + .addComment(c => c.id(singleCommentId).path('file0.txt').body('I am single and free')) .build(); const reviewSpecs = [review1, review2]; @@ -189,36 +191,13 @@ describe('PullRequestReviewsController', function() { wrapper.instance().reviewsById.set(review1.id, {submittedAt: review1.submittedAt, comments: review1.comments, fetchingMoreComments: false}); wrapper.instance().collectComments({reviewId: review2.id, submittedAt: review2.submittedAt, comments: review2.comments, fetchingMoreComments: false}); - const threadedComments = wrapper.instance().state[1]; + const threadedComments = wrapper.instance().state[originalCommentId]; assert.lengthOf(threadedComments, 2); assert.strictEqual(threadedComments[0].body, 'OG comment'); assert.strictEqual(threadedComments[1].body, 'reply to OG comment'); - }); - it('sorts replies based on date', function() { - const review1 = reviewBuilder() - .id(0) - .submittedAt('2018-12-27T20:40:55Z') - .addComment(c => c.id(1).path('file0.txt').body('OG comment')) - .build(); - const review2 = reviewBuilder() - .id(1) - .submittedAt('2018-12-28T20:40:55Z') - .addComment(c => c.id(2).path('file0.txt').replyTo(1).body('reply to OG comment')) - .build(); - - const reviewSpecs = [review1, review2]; - - const wrapper = shallow(buildApp({reviewSpecs})); - - // adding this manually to reviewsById because the last time you call collectComments it groups them, and we don't want to do that just yet. - wrapper.instance().reviewsById.set(review1.id, {submittedAt: review1.submittedAt, comments: review1.comments, fetchingMoreComments: false}); - - wrapper.instance().collectComments({reviewId: review2.id, submittedAt: review2.submittedAt, comments: review2.comments, fetchingMoreComments: false}); - const threadedComments = wrapper.instance().state[1]; - assert.lengthOf(threadedComments, 2); - assert.strictEqual(threadedComments[0].body, 'OG comment'); - assert.strictEqual(threadedComments[1].body, 'reply to OG comment'); + const singleComment = wrapper.instance().state[singleCommentId]; + assert.strictEqual(singleComment[0].body, 'I am single and free'); }); it('comments with a replyTo id that does not point to an existing comment are threaded separately', function() { @@ -227,7 +206,7 @@ describe('PullRequestReviewsController', function() { const review = reviewBuilder() .id(2) .submittedAt('2018-12-28T20:40:55Z') - .addComment(c => c.id(replyToOutdatedCommentId).path('file0.txt').replyTo(outdatedCommentId).body('reply to outdated comment')) + .addComment(c => c.id(replyToOutdatedCommentId).path('file0.txt').replyTo(outdatedCommentId).body('reply to outdated comment')) .build(); const wrapper = shallow(buildApp({reviewSpecs: [review]})); From f1557b71a444626829f526e44d848381c686199d Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 8 Jan 2019 13:15:51 -0800 Subject: [PATCH 2529/4847] make review builder actually return `submittedAt` --- test/builder/pr.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/builder/pr.js b/test/builder/pr.js index e7b78ba2db..3616872b77 100644 --- a/test/builder/pr.js +++ b/test/builder/pr.js @@ -108,6 +108,7 @@ class ReviewBuilder { }); return { id: this._id, + submittedAt: this._submittedAt, comments: {edges: comments}, }; } From 26fa6126b20298a99af74b70cdb1f9a72ce7b1d9 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 8 Jan 2019 13:22:05 -0800 Subject: [PATCH 2530/4847] test that comments show up grouped by review submittedAt date --- .../controllers/pr-reviews-controller.test.js | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index d99ded32b1..8392258ad7 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -167,7 +167,7 @@ describe('PullRequestReviewsController', function() { }); describe('grouping and ordering comments', function() { - it.only('groups the comments into threads based on replyId', function() { + it('groups the comments into threads based on replyId', function() { const originalCommentId = 1; const singleCommentId = 5; const review1 = reviewBuilder() @@ -183,9 +183,7 @@ describe('PullRequestReviewsController', function() { .addComment(c => c.id(singleCommentId).path('file0.txt').body('I am single and free')) .build(); - const reviewSpecs = [review1, review2]; - - const wrapper = shallow(buildApp({reviewSpecs})); + const wrapper = shallow(buildApp({reviewSpecs: [review1, review2]})); // adding this manually to reviewsById because the last time you call collectComments it groups them, and we don't want to do that just yet. wrapper.instance().reviewsById.set(review1.id, {submittedAt: review1.submittedAt, comments: review1.comments, fetchingMoreComments: false}); @@ -200,6 +198,42 @@ describe('PullRequestReviewsController', function() { assert.strictEqual(singleComment[0].body, 'I am single and free'); }); + it('comments are ordered based on the order in which their reviews were submitted', function() { + const originalCommentId = 1; + const review1 = reviewBuilder() + .id(0) + .submittedAt('2018-12-20T20:40:55Z') + .addComment(c => c.id(originalCommentId).path('file0.txt').body('OG comment')) + .build(); + + const review2 = reviewBuilder() + .id(1) + .submittedAt('2018-12-22T20:40:55Z') + .addComment(c => c.id(2).path('file0.txt').replyTo(originalCommentId).body('first reply to OG comment')) + .build(); + + const review3 = reviewBuilder() + .id(2) + .submittedAt('2018-12-25T20:40:55Z') + .addComment(c => c.id(3).path('file0.txt').replyTo(originalCommentId).body('second reply to OG comment')) + .build(); + + const wrapper = shallow(buildApp({reviewSpecs: [review1, review2, review3]})); + + // adding this manually to reviewsById because the last time you call collectComments it groups them, and we don't want to do that just yet. + wrapper.instance().reviewsById.set(review2.id, {submittedAt: review2.submittedAt, comments: review2.comments, fetchingMoreComments: false}); + wrapper.instance().reviewsById.set(review1.id, {submittedAt: review1.submittedAt, comments: review1.comments, fetchingMoreComments: false}); + + wrapper.instance().collectComments({reviewId: review3.id, submittedAt: review3.submittedAt, comments: review3.comments, fetchingMoreComments: false}); + const threadedComments = wrapper.instance().state[originalCommentId]; + assert.lengthOf(threadedComments, 3); + + assert.strictEqual(threadedComments[0].body, 'OG comment'); + assert.strictEqual(threadedComments[1].body, 'first reply to OG comment'); + assert.strictEqual(threadedComments[2].body, 'second reply to OG comment'); + }); + + it('comments with a replyTo id that does not point to an existing comment are threaded separately', function() { const outdatedCommentId = 1; const replyToOutdatedCommentId = 2; From bc87b98247c4d70867143e3a4173eec267ceaf53 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Tue, 8 Jan 2019 18:03:26 -0800 Subject: [PATCH 2531/4847] update react component atlas --- docs/react-component-atlas.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/react-component-atlas.md b/docs/react-component-atlas.md index 383e3b78eb..596b3acbb4 100644 --- a/docs/react-component-atlas.md +++ b/docs/react-component-atlas.md @@ -124,6 +124,13 @@ This is a high-level overview of the structure of the React component tree that > > > > > [``](/lib/containers/pr-changed-files-container.js) > > > +> > > Fetch all reviews and comments for a pull request, group comments, and render them. +> > > [``](/lib/containers/pr-reviews-container.js) +> > > [``](/lib/containers/pr-review-comments-container.js) +> > > [``](lib/controllers/pr-reviews-controller.js) +> > > [``](lib/views/pr-review-comments-view.js) +> > > [``](lib/views/pr-review-comments-view.js) +> > > > > > Show all the changes, separated by files, introduced in a pull request. > > > > > > > [``](/lib/controllers/multi-file-patch-controller.js) From fbb72f488244d1fe9a4c4d8e47c15f5c9207be0a Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 9 Jan 2019 14:46:07 +0100 Subject: [PATCH 2532/4847] relay changed where the displayname is stored --- lib/views/issueish-timeline-view.js | 2 +- test/views/issueish-timeline-view.test.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/views/issueish-timeline-view.js b/lib/views/issueish-timeline-view.js index 923f919abc..dcedf15d46 100644 --- a/lib/views/issueish-timeline-view.js +++ b/lib/views/issueish-timeline-view.js @@ -13,7 +13,7 @@ import CommitCommentThreadView from './timeline-items/commit-comment-thread-view export function collectionRenderer(Component, styleAsTimelineItem = true) { return class GroupedComponent extends React.Component { - static displayName = `Grouped(${Component.displayName})` + static displayName = `Grouped(${Component.render.displayName})` static propTypes = { nodes: PropTypes.array.isRequired, diff --git a/test/views/issueish-timeline-view.test.js b/test/views/issueish-timeline-view.test.js index 4135f9961c..90dfbe8e72 100644 --- a/test/views/issueish-timeline-view.test.js +++ b/test/views/issueish-timeline-view.test.js @@ -74,16 +74,16 @@ describe('IssueishTimelineView', function() { const commitGroup0 = wrapper.find('ForwardRef(Relay(BareCommitsView))').filterWhere(c => c.prop('nodes').length === 2); assert.deepEqual(commitGroup0.prop('nodes').map(n => n.id), [0, 1]); - const commentGroup0 = wrapper.find('Grouped(ForwardRef(Relay(BareIssueCommentView)))').filterWhere(c => c.prop('nodes').length === 1); + const commentGroup0 = wrapper.find('Grouped(Relay(BareIssueCommentView))').filterWhere(c => c.prop('nodes').length === 1); assert.deepEqual(commentGroup0.prop('nodes').map(n => n.id), [2]); - const mergedGroup = wrapper.find('Grouped(ForwardRef(Relay(BareMergedEventView)))').filterWhere(c => c.prop('nodes').length === 1); + const mergedGroup = wrapper.find('Grouped(Relay(BareMergedEventView))').filterWhere(c => c.prop('nodes').length === 1); assert.deepEqual(mergedGroup.prop('nodes').map(n => n.id), [3]); const commitGroup1 = wrapper.find('ForwardRef(Relay(BareCommitsView))').filterWhere(c => c.prop('nodes').length === 4); assert.deepEqual(commitGroup1.prop('nodes').map(n => n.id), [4, 5, 6, 7]); - const commentGroup1 = wrapper.find('Grouped(ForwardRef(Relay(BareIssueCommentView)))').filterWhere(c => c.prop('nodes').length === 2); + const commentGroup1 = wrapper.find('Grouped(Relay(BareIssueCommentView))').filterWhere(c => c.prop('nodes').length === 2); assert.deepEqual(commentGroup1.prop('nodes').map(n => n.id), [8, 9]); }); From 8699262ef71b6cc218cee3e913caba8908b17970 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 9 Jan 2019 16:34:04 +0100 Subject: [PATCH 2533/4847] ok this should do it --- lib/views/issueish-timeline-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/issueish-timeline-view.js b/lib/views/issueish-timeline-view.js index dcedf15d46..286d3a5b7e 100644 --- a/lib/views/issueish-timeline-view.js +++ b/lib/views/issueish-timeline-view.js @@ -13,7 +13,7 @@ import CommitCommentThreadView from './timeline-items/commit-comment-thread-view export function collectionRenderer(Component, styleAsTimelineItem = true) { return class GroupedComponent extends React.Component { - static displayName = `Grouped(${Component.render.displayName})` + static displayName = `Grouped(${Component.render ? Component.render.displayName : Component.displayName})` static propTypes = { nodes: PropTypes.array.isRequired, From 5379d104f78040ee9b67b3afdfb7e2d611b62949 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 3 Oct 2018 14:18:38 +0000 Subject: [PATCH 2534/4847] fix(package): update keytar to version 4.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 61d7625d5a..02c41a62aa 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "event-kit": "2.5.3", "fs-extra": "4.0.3", "graphql": "0.13.2", - "keytar": "4.2.1", + "keytar": "4.3.0", "lodash.memoize": "4.1.2", "moment": "2.22.2", "node-emoji": "^1.8.1", From d06eb9f21ea41295523f9127223e9f5a2a9ec441 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 3 Oct 2018 14:18:42 +0000 Subject: [PATCH 2535/4847] chore(package): update lockfile package-lock.json --- package-lock.json | 130 +++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 70 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a11d91370..c5a71bba9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -358,9 +358,9 @@ "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=" }, "are-we-there-yet": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -1773,23 +1773,23 @@ } }, "buffer-alloc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.1.0.tgz", - "integrity": "sha1-BVFNM78WVtNUDGhPZbEgLpDsowM=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", "requires": { - "buffer-alloc-unsafe": "^0.1.0", - "buffer-fill": "^0.1.0" + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" } }, "buffer-alloc-unsafe": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-0.1.1.tgz", - "integrity": "sha1-/+H2dVHdBVc33iUzN7/oU9+rGmo=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" }, "buffer-fill": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-0.1.1.tgz", - "integrity": "sha1-dtglxNblDga3ox61IMBNCMwjUHE=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" }, "buffer-from": { "version": "1.1.1", @@ -2285,9 +2285,9 @@ "dev": true }, "deep-extend": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", - "integrity": "sha1-uJSp3ZDTAj+/HFWjlPuFjrIGbx8=" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, "deep-is": { "version": "0.1.3", @@ -3267,9 +3267,9 @@ } }, "expand-template": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.0.tgz", - "integrity": "sha1-4J77qXe/mPnuDtJavQxpLgKuw/w=" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz", + "integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==" }, "extend": { "version": "3.0.1", @@ -4604,12 +4604,12 @@ "dev": true }, "keytar": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-4.2.1.tgz", - "integrity": "sha1-igamV3/fY3PgqmsRInfmPex3/RI=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-4.3.0.tgz", + "integrity": "sha512-pd++/v+fS0LQKmzWlW6R1lziTXFqhfGeS6sYLfuTIqEy2pDzAbjutbSW8f9tnJdEEMn/9XhAQlT34VAtl9h4MQ==", "requires": { "nan": "2.8.0", - "prebuild-install": "^2.4.1" + "prebuild-install": "^5.0.0" } }, "kind-of": { @@ -5042,9 +5042,9 @@ "dev": true }, "mimic-response": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz", - "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" }, "min-document": { "version": "2.19.0", @@ -5281,6 +5281,11 @@ } } }, + "napi-build-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz", + "integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5334,9 +5339,9 @@ } }, "node-abi": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.0.tgz", - "integrity": "sha1-PCdRXLhC9bvBMqMSVPnx4cVce4M=", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.5.tgz", + "integrity": "sha512-aa/UC6Nr3+tqhHGRsAuw/edz7/q9nnetBrKWxj6rpTtm+0X9T1qU7lIEHMS3yN9JwAbRiKUbRRFy1PLz/y3aaA==", "requires": { "semver": "^5.4.1" } @@ -6925,21 +6930,22 @@ "dev": true }, "prebuild-install": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.5.3.tgz", - "integrity": "sha1-n2XyQngtNwKWNTcQ6byENJDBn2k=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.2.0.tgz", + "integrity": "sha512-cpuyMS8y30Df0bnN+I8pdmpwtZbm8fj9cQADOhSH/qnS1exb80elZ707FTMohFBJax4NyWjJVSg0chRQXzHSvg==", "requires": { "detect-libc": "^1.0.3", "expand-template": "^1.0.2", "github-from-package": "0.0.0", "minimist": "^1.2.0", "mkdirp": "^0.5.1", + "napi-build-utils": "^1.0.1", "node-abi": "^2.2.0", "noop-logger": "^0.1.1", "npmlog": "^4.0.1", "os-homedir": "^1.0.1", "pump": "^2.0.1", - "rc": "^1.1.6", + "rc": "^1.2.7", "simple-get": "^2.7.0", "tar-fs": "^1.13.0", "tunnel-agent": "^0.6.0", @@ -7073,11 +7079,11 @@ } }, "rc": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz", - "integrity": "sha1-ihDKMNWI0ARkNgNyuJDQbazQIpc=", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "requires": { - "deep-extend": "^0.5.1", + "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" @@ -8113,7 +8119,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -8122,20 +8127,17 @@ "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, "requires": { "ansi-regex": "^3.0.0" } @@ -8275,9 +8277,9 @@ } }, "tar-fs": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.2.tgz", - "integrity": "sha1-F+Ujl0fjmffnc0T19TNl8Er1NXc=", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", + "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", "requires": { "chownr": "^1.0.1", "mkdirp": "^0.5.1", @@ -8288,7 +8290,7 @@ "pump": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", - "integrity": "sha1-Xf6DEcM7v2/BgmH580cCxHwIqVQ=", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -8297,16 +8299,16 @@ } }, "tar-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.0.tgz", - "integrity": "sha1-pQ76p7F3YLgsJ7PK5KMBqCVKVxU=", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "requires": { "bl": "^1.0.0", - "buffer-alloc": "^1.1.0", + "buffer-alloc": "^1.2.0", "end-of-stream": "^1.0.0", "fs-constants": "^1.0.0", - "readable-stream": "^2.0.0", - "to-buffer": "^1.1.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", "xtend": "^4.0.0" } }, @@ -8922,23 +8924,11 @@ "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" }, "wide-align": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "requires": { - "string-width": "^1.0.2" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } + "string-width": "^1.0.2 || 2" } }, "wordwrap": { From bf675047374570e22f3c897381743d874ad54f26 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 9 Jan 2019 11:21:10 -0500 Subject: [PATCH 2536/4847] :arrow_up: moment --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a11d91370..3d7f6b35cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5225,9 +5225,9 @@ "dev": true }, "moment": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", - "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz", + "integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==" }, "moo": { "version": "0.4.3", diff --git a/package.json b/package.json index 61d7625d5a..d07d37caeb 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "graphql": "0.13.2", "keytar": "4.2.1", "lodash.memoize": "4.1.2", - "moment": "2.22.2", + "moment": "2.23.0", "node-emoji": "^1.8.1", "prop-types": "15.6.2", "react": "16.7.0", From 95c7d6715aeed2d787fed6b8abec7dec1aea6625 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 9 Jan 2019 09:30:21 -0800 Subject: [PATCH 2537/4847] fussing with the test formatting --- test/controllers/pr-reviews-controller.test.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index 8392258ad7..1fef175c8d 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -220,7 +220,7 @@ describe('PullRequestReviewsController', function() { const wrapper = shallow(buildApp({reviewSpecs: [review1, review2, review3]})); - // adding this manually to reviewsById because the last time you call collectComments it groups them, and we don't want to do that just yet. + // adding these manually to reviewsById because the last time you call collectComments it groups them, and we don't want to do that just yet. wrapper.instance().reviewsById.set(review2.id, {submittedAt: review2.submittedAt, comments: review2.comments, fetchingMoreComments: false}); wrapper.instance().reviewsById.set(review1.id, {submittedAt: review1.submittedAt, comments: review1.comments, fetchingMoreComments: false}); @@ -233,7 +233,6 @@ describe('PullRequestReviewsController', function() { assert.strictEqual(threadedComments[2].body, 'second reply to OG comment'); }); - it('comments with a replyTo id that does not point to an existing comment are threaded separately', function() { const outdatedCommentId = 1; const replyToOutdatedCommentId = 2; @@ -250,6 +249,5 @@ describe('PullRequestReviewsController', function() { assert.lengthOf(comments, 1); assert.strictEqual(comments[0].body, 'reply to outdated comment'); }); - }); }); From 890b74f153d6d37d7f67170fd9d5c2a3a3ccbe18 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 9 Jan 2019 11:18:00 -0500 Subject: [PATCH 2538/4847] :arrow_up: dugite --- package-lock.json | 224 ++++++++++++++++++++++++++-------------------- package.json | 2 +- 2 files changed, 130 insertions(+), 96 deletions(-) diff --git a/package-lock.json b/package-lock.json index 887c84455a..654cd01565 100644 --- a/package-lock.json +++ b/package-lock.json @@ -208,7 +208,7 @@ "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "dev": true, "requires": { "call-me-maybe": "^1.0.1", @@ -253,7 +253,7 @@ "@smashwilson/atom-mocha-test-runner": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@smashwilson/atom-mocha-test-runner/-/atom-mocha-test-runner-1.4.0.tgz", - "integrity": "sha1-AjOAreJPt5xrC7TlXdTuc7LFdfo=", + "integrity": "sha512-Zp50XTy2QZEk53PUxXQ1kLTAkSwEuM2X7JXtMGLRWuU68piFghkXGaopTrjXK3CwgzmmFi26m65sTCrXg3zqbg==", "dev": true, "requires": { "diff": "3.5.0", @@ -329,6 +329,7 @@ "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, "requires": { "co": "^4.6.0", "fast-deep-equal": "^1.0.0", @@ -339,7 +340,7 @@ "ansi-escapes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha1-9zIHu4EgfXX9bIPxJa8m7qN4yjA=", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", "dev": true }, "ansi-regex": { @@ -369,7 +370,7 @@ "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "requires": { "sprintf-js": "~1.0.2" } @@ -464,7 +465,7 @@ "array.prototype.flat": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz", - "integrity": "sha1-gS248CytJNP6tl3WfqvjuJA0lKQ=", + "integrity": "sha512-rVqIs330nLJvfC7JqYvEWwqVr5QjYF1ib02i3YJtR/fICO6527Tjpc/e4Mvmxh3GIePPreRXMdaGyC99YphWEw==", "dev": true, "requires": { "define-properties": "^1.1.2", @@ -496,7 +497,7 @@ "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha1-5gtrDo8wG9l+U3UhW9pAbIURjAs=", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, "assign-symbols": { @@ -547,7 +548,7 @@ "atom-babel6-transpiler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/atom-babel6-transpiler/-/atom-babel6-transpiler-1.2.0.tgz", - "integrity": "sha1-OcgHq8H9WqZDqvCut8DqE3j+Y1Y=", + "integrity": "sha512-lZucrjVyRtPAPPJxvICCEBsAC1qn48wUHaIlieriWCXTXLqtLC2PvkQU7vNvU2w1eZ7tw9m0lojZ8PbpVyWTvg==", "requires": { "babel-core": "6.x" } @@ -1459,7 +1460,7 @@ "babel-preset-fbjs": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-2.2.0.tgz", - "integrity": "sha1-wluHmpFP7v2WQFKxvOTJDukVAjo=", + "integrity": "sha512-jj0KFJDioYZMtPtZf77dQuU+Ad/1BtN0UnAYlHDa8J8f4tGXr3YrPoJImD5MdueaOPeN/jUdrCgu330EfXr0XQ==", "dev": true, "requires": { "babel-plugin-check-es2015-constants": "^6.8.0", @@ -1635,7 +1636,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -1644,7 +1645,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -1653,7 +1654,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -1987,7 +1988,7 @@ "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY=", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, "class-utils": { @@ -2016,7 +2017,7 @@ "classnames": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha1-Q5Nb/90pHzJtrQogUwmzjQD2UM4=" + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" }, "cli-cursor": { "version": "2.1.0", @@ -2066,7 +2067,8 @@ "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true }, "code-point-at": { "version": "1.1.0", @@ -2115,7 +2117,7 @@ "commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha1-30boZ9D8Kuxmo0ZitAapzK//Ww8=", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, "compare-sets": { @@ -2211,7 +2213,7 @@ "cross-env": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz", - "integrity": "sha1-bs1MAV1Xc+YUA57lKQdmabnRJvI=", + "integrity": "sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg==", "dev": true, "requires": { "cross-spawn": "^6.0.5", @@ -2340,7 +2342,7 @@ "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha1-38lARACtHI/gI+faHfHBR8S0RN8=", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { "type-detect": "^4.0.0" @@ -2396,7 +2398,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -2405,7 +2407,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -2414,7 +2416,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -2450,7 +2452,7 @@ "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, "dir-glob": { @@ -2537,7 +2539,7 @@ "domhandler": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM=", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "dev": true, "requires": { "domelementtype": "1" @@ -2554,18 +2556,29 @@ } }, "dugite": { - "version": "1.79.0", - "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.79.0.tgz", - "integrity": "sha512-1iohG+Yj+7wwVNUv+HCWaK5ZeAbqNyxHZf96B65KojBVcvMT29i8Tnh/Ta/KHI7LcI0dQqSqsKJdZozpWjXWKw==", + "version": "1.81.0", + "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.81.0.tgz", + "integrity": "sha512-aH1cVzbEXOHqpiub9PWJUN+R2p7H+tvN+VqyAYHR9Tj/axLDccWJk5aKDN1/US82DkaIYWUZz8x0lAbjfqrq4Q==", "requires": { "checksum": "^0.1.1", "mkdirp": "^0.5.1", - "progress": "^2.0.0", + "progress": "^2.0.3", "request": "^2.88.0", "rimraf": "^2.5.4", - "tar": "^4.4.6" + "tar": "^4.4.7" }, "dependencies": { + "ajv": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", + "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "aws4": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", @@ -2576,15 +2589,25 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, "har-validator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", - "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { - "ajv": "^5.3.0", + "ajv": "^6.5.5", "har-schema": "^2.0.0" } }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, "mime-db": { "version": "1.37.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", @@ -2603,6 +2626,11 @@ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", @@ -2668,7 +2696,7 @@ "electron-devtools-installer": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-2.2.4.tgz", - "integrity": "sha1-JhpQM343Eh0zi5ZvB5IutJOah2M=", + "integrity": "sha512-b5kcM3hmUqn64+RUcHjjr8ZMpHS2WJ5YO0pnG9+P/RTdx46of/JrEjuciHWux6pE+On6ynWhHJF53j/EDJN0PA==", "dev": true, "requires": { "7zip": "0.0.6", @@ -2756,7 +2784,7 @@ "emoji-regex": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz", - "integrity": "sha1-m66pKbFVVlwR6kHGYm6qZc75ksI=", + "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==", "dev": true }, "encoding": { @@ -2874,7 +2902,7 @@ "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "dev": true, "requires": { "prr": "~1.0.1" @@ -3195,7 +3223,7 @@ "eslint-scope": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha1-UL8wcekzi83EMzF5Sgy1M/ATYXI=", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -3211,7 +3239,7 @@ "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", "dev": true }, "espree": { @@ -3233,7 +3261,7 @@ "esquery": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { "estraverse": "^4.0.0" @@ -3242,7 +3270,7 @@ "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { "estraverse": "^4.1.0" @@ -3480,7 +3508,8 @@ "fast-deep-equal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true }, "fast-future": { "version": "1.0.2", @@ -3665,7 +3694,7 @@ "fs-extra": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha1-DYUhIuW8W+tFP7Ao6cDJvzY0DJQ=", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -3675,7 +3704,7 @@ "fs-minipass": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha1-BsJ3IYRU7CiN93raVKA7hwKqy50=", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "requires": { "minipass": "^2.2.1" } @@ -3688,13 +3717,13 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "function.prototype.name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.0.tgz", - "integrity": "sha1-i9djzAr4YKhZzF1JOE10uTLNIyc=", + "integrity": "sha512-Bs0VRrTz4ghD8pTmbJQD1mZ8A/mN0ur/jGz+A6FBxPDUPkm1tNfF6bhTYPA7i7aF4lZJVr+OXTNNrnnIl58Wfg==", "dev": true, "requires": { "define-properties": "^1.1.2", @@ -3889,7 +3918,7 @@ "grim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz", - "integrity": "sha1-52CinKe4NDsMH/r2ziDyGkbuiu0=", + "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==", "dev": true, "requires": { "event-kit": "^2.0.0" @@ -3898,7 +3927,7 @@ "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha1-8nNdwig2dPpnR4sQGBBZNVw2nl4=", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, "har-schema": { @@ -3991,7 +4020,7 @@ "hock": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/hock/-/hock-1.3.3.tgz", - "integrity": "sha1-aWHj3wUpsu08vBPkuNgfvYi5xg0=", + "integrity": "sha512-bEX7KH/KSv2Q5zA+o1EdyeH52+gD2cfpYyAsHMEwjb9txXWttityKVf7cG0y3UVA4D8bxKDzH8LVXCQIr9rClg==", "dev": true, "requires": { "deep-equal": "0.2.1", @@ -4337,7 +4366,7 @@ "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", @@ -4348,7 +4377,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } @@ -4536,7 +4565,7 @@ "node-fetch": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha1-mA9vcthSEaU0fGsrwYxbhMPrR+8=", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { "encoding": "^0.1.11", "is-stream": "^1.0.1" @@ -4613,7 +4642,8 @@ "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -4689,7 +4719,7 @@ "less": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/less/-/less-3.8.1.tgz", - "integrity": "sha1-8xdYWY71oZMN1MrvqeQ0BkHnHh0=", + "integrity": "sha512-8HFGuWmL3FhQR0aH89escFNBQH/nEiYPP2ltDFdQw2chE28Yx2E3lhAIq9Y2saYwLSwa699s4dBVEfCY8Drf7Q==", "dev": true, "requires": { "clone": "^2.1.2", @@ -4706,7 +4736,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } @@ -5077,7 +5107,7 @@ "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, "optional": true }, @@ -5144,9 +5174,9 @@ } }, "minizlib": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.1.tgz", - "integrity": "sha512-TrfjCjk4jLhcJyGMYymBH6oTXcWjYbUAXTHDbtnWHjZC25h0cdajHuPE1zxb4DVmu8crfh+HwH/WMuyLG0nHBg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", "requires": { "minipass": "^2.2.1" } @@ -5190,7 +5220,7 @@ "mocha": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha1-bYrlCPWRZ/lA8rWzxKYSrlDJCuY=", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", "dev": true, "requires": { "browser-stdout": "1.3.1", @@ -5209,7 +5239,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -5218,7 +5248,7 @@ "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -5291,7 +5321,7 @@ "moo": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/moo/-/moo-0.4.3.tgz", - "integrity": "sha1-P4R6JvMc9iWpVqh/KxD7wBO/0Q4=", + "integrity": "sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw==", "dev": true }, "ms": { @@ -5354,7 +5384,7 @@ "nearley": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.15.1.tgz", - "integrity": "sha1-ll5Obsnta4D8gUU+Fh77zrs20kc=", + "integrity": "sha512-8IUY/rUrKz2mIynUGh8k+tul1awMKEjeHHC5G3FHvvyAW6oq4mQfNp2c0BMea+sYZJvYcrrM6GmZVIle/GRXGw==", "dev": true, "requires": { "moo": "^0.4.3", @@ -5408,7 +5438,7 @@ "node-emoji": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz", - "integrity": "sha1-buxr+wdCHiFIx1xrunJCH4UwqCY=", + "integrity": "sha512-+ktMAh1Jwas+TnGodfCfjUbJKoANqPaJFN0z0iqh41eqD8dvguNzcitVSBSVK1pidz0AqGbLKcoVuVLRVZ/aVg==", "requires": { "lodash.toarray": "^4.4.0" } @@ -6685,7 +6715,7 @@ "object-inspect": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha1-xwtsv3LydKq0w0wMgvUWe/gs8Vs=", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", "dev": true }, "object-is": { @@ -6873,7 +6903,7 @@ "parse5": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", - "integrity": "sha1-BC95L/3TaFFVHPTp4Gazh0q0W1w=", + "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", "dev": true, "requires": { "@types/node": "*" @@ -6978,7 +7008,7 @@ "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, "posix-character-classes": { @@ -7040,12 +7070,13 @@ "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "progress": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "dev": true }, "progress-stream": { "version": "1.2.0", @@ -7068,7 +7099,7 @@ "prop-types": { "version": "15.6.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", - "integrity": "sha1-BdXKd7RFPphdYPx/+MhZCUpJcQI=", + "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", "requires": { "loose-envify": "^1.3.1", "object-assign": "^4.1.1" @@ -7087,9 +7118,9 @@ "dev": true }, "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha1-YPWA02AXC7cip5fMcEQR5tqFDGc=" + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" }, "pump": { "version": "2.0.1", @@ -7129,7 +7160,7 @@ "randexp": { "version": "0.4.6", "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", - "integrity": "sha1-6YatXl4x2uE93W97MBmqfIf2DKM=", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", "dev": true, "requires": { "discontinuous-range": "1.0.0", @@ -7658,7 +7689,7 @@ "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "requires": { "glob": "^7.0.5" } @@ -7884,7 +7915,7 @@ "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { "base": "^0.11.1", @@ -7940,7 +7971,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -7949,7 +7980,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -7958,7 +7989,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -8023,7 +8054,7 @@ "spdx-correct": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha1-BaW01xU6GVvJLDxCW2nzsqlSTII=", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -8033,13 +8064,13 @@ "spdx-exceptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha1-LHrmEFbHFKW5ubKyr30xHvXHj+k=", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -8273,19 +8304,24 @@ } }, "tar": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.6.tgz", - "integrity": "sha1-YxEPCcALTmCsi8/hvzyGYCNfvJs=", + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.3.3", - "minizlib": "^1.1.0", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", "yallist": "^3.0.2" }, "dependencies": { + "chownr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -8679,7 +8715,7 @@ "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha1-dkb7XxiHHPu3dJ5pvTmmOI63RQw=", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, "typedarray": { @@ -8702,7 +8738,7 @@ "underscore-plus": { "version": "1.6.8", "resolved": "https://registry.npmjs.org/underscore-plus/-/underscore-plus-1.6.8.tgz", - "integrity": "sha1-iUtRMnY+nlzp1Q8mh7aNumCC3iI=", + "integrity": "sha512-88PrCeMKeAAC1L4xjSiiZ3Fg6kZOYrLpLGVPPeqKq/662DfQe/KTSKdSR/Q/tucKNnfW2MNAUGSCkDf8HmXC5Q==", "requires": { "underscore": "~1.8.3" }, @@ -8803,8 +8839,7 @@ "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", - "dev": true, + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "requires": { "punycode": "^2.1.0" }, @@ -8812,8 +8847,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" } } }, @@ -9020,9 +9054,9 @@ "dev": true }, "yallist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" }, "yargs": { "version": "9.0.1", diff --git a/package.json b/package.json index afe9dd6e37..3fdc822d05 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "bytes": "^3.0.0", "classnames": "2.2.6", "compare-sets": "1.0.1", - "dugite": "^1.79.0", + "dugite": "^1.81.0", "event-kit": "2.5.3", "fs-extra": "4.0.3", "graphql": "0.13.2", From e980dbf29f676f41286f6cc7dcdcff4661fc01b2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 9 Jan 2019 14:09:23 -0500 Subject: [PATCH 2539/4847] :arrow_up: globby --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 654cd01565..1efc2263cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3863,13 +3863,13 @@ "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=" }, "globby": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", - "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", "dev": true, "requires": { "array-union": "^1.0.1", - "dir-glob": "^2.0.0", + "dir-glob": "2.0.0", "fast-glob": "^2.0.2", "glob": "^7.1.2", "ignore": "^3.3.5", diff --git a/package.json b/package.json index 3fdc822d05..9dffa87e11 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "eslint": "5.12.0", "eslint-config-fbjs-opensource": "1.0.0", "eslint-plugin-jsx-a11y": "6.1.2", - "globby": "8.0.1", + "globby": "8.0.2", "hock": "1.3.3", "lodash.isequalwith": "4.4.0", "mkdirp": "0.5.1", From 3ff9662eb05a10bd6babd8889ba714996f877b72 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 9 Jan 2019 15:59:19 -0500 Subject: [PATCH 2540/4847] Document using a "PullRequestReviewsItem" for review navigation. Co-Authored-By: Vanessa Yuen Co-Authored-By: Katrina Uychaco --- .../003-pull-request-review.md | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index a045631c5a..e7c7a45d44 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -26,7 +26,7 @@ Peer review is also a critical part of the path to acceptance for pull requests ![center pane](https://user-images.githubusercontent.com/378023/46985265-75c9fe00-d124-11e8-9b34-572cd1aaf701.png) * Clicking a pull request in the list opens a `PullRequestDetailItem` in the workspace center. - +* Clicking the "Reviews" label or progress bar opens a `PullRequestReviewsItem` in the right dock. ### PullRequestDetailItem @@ -38,14 +38,15 @@ At the top of each `PullRequestDetailItem` is a summary about the pull request, - Overview - Files (**new**) -- Reviews (**new**) - Commits - Build Status -Below the tabs is a "tools bar" for controls to toggle review comments or collapse files. +Below the tabs is a "tools bar" with controls to toggle review comments or collapse files. #### Footer +> TODO: Add "open" button + ![reviews panel](https://user-images.githubusercontent.com/378023/46536010-17ad4780-c8e8-11e8-8338-338bb592efc5.png) A panel at the bottom of the pane shows the progress for resolved review comments. It also has a "Review Changes" button to create a new review. This panel is persistent throughout all sub-views. It allows creating new reviews no matter where you are. Below examples with the existing sub-views: @@ -54,6 +55,7 @@ Overview | Commits | Build Status --- | --- | --- ![overview](https://user-images.githubusercontent.com/378023/46535907-ca30da80-c8e7-11e8-9401-2b8660d56c25.png) | ![commits](https://user-images.githubusercontent.com/378023/46535908-ca30da80-c8e7-11e8-87ca-01637f2554b6.png) | ![build status](https://user-images.githubusercontent.com/378023/46535909-cac97100-c8e7-11e8-8813-47fdaa3ece57.png) +When the pull request is checked out, an "open" button is shown in the review footer. Clicking "open" opens a `PullRequestReviewsItem` for this pull request's review comments as an item in the right workspace dock. ### Files (tab) @@ -70,26 +72,6 @@ Uncollapsed (default) | Collapsed * For large diffs, the files can be collapsed to get a better overview. - -### Reviews (tab) - -Clicking on the "Reviews" tab shows all reviews of a pull request. This is akin to the review summaries that appear on the "Conversation" tab on dotcom. In addition, each review also includes review comments and their diff. - -![reviews](https://user-images.githubusercontent.com/378023/46535563-c81a4c00-c8e6-11e8-9c0b-6ea575556101.png) - -Uncollapsed (default) | Collapsed ---- | --- -![reviews](https://user-images.githubusercontent.com/378023/46535563-c81a4c00-c8e6-11e8-9c0b-6ea575556101.png) | ![collapsed reviews](https://user-images.githubusercontent.com/378023/46926357-62a72780-d06b-11e8-9344-23389d1c727c.png) - -* Comments can be collapsed to get a better overview. -* Reviews get sorted by "urgency". Showing reviews that still need to get adressed at the top: - 1. "recommended" changes - 2. "commented" changes - 3. "no review" (when a reviewer only leaves review comments, but no summary) - 4. "approved" changes - 5. "previous" reviews (when a reviewer made an earlier review and it's now out-dated) -* Within each group, sorting is done by "newest first". - #### Create a new review ##### `+` Button @@ -131,7 +113,39 @@ Clicking "Finish your review" from a comment or clicking "Review Changes" in the * Review comments can be resolved by clicking on the "Resolve conversation" buttons. * If the "reply..." editor has non-whitespace content, it is submitted as a final comment first. -#### Context and navigation +### PullRequestReviewsItem + +This item is opened in the workspace's right dock when the user: + +* Clicks the review progress bar in the GitHub tab. +* Clicks the "open" button on the review summary footer of a `PullRequestDetailItem`. +* Clicks the "<>" button on a review comment in the "Files" tab of a `PullRequestDetailItem`. + +It shows a scrollable view of all of the reviews and comments associated with a specific pull request, + +> TODO: Illustration for the PullRequestReviewsItem + +Reviews are sorted by "urgency," showing reviews that still need to be addressed at the top. Within each group, sorting is done by "newest first". + +1. "recommended" changes +2. "commented" changes +3. "no review" (when a reviewer only leaves review comments, but no summary) +4. "approved" changes +5. "previous" reviews (when a reviewer made an earlier review and it's now out-dated) + +Clicking on a review summary comment expands or collapses the associated review comments. + +Clicking on a review comment opens a `TextEditor` on the corresponding position of the file under review. The clicked review comment is highlighted as the "current" one. + +#### Within an open TextEditor + +If an open `TextEditor` corresponds to a file that has one or more review comments in an open `PullRequestReviewsItem`, gutter and line decorations are added to the lines that match those review comment positions. The "current" one is styled differently to stand out. + +> TODO: Illustrate the "review comment here" gutter and line decorations + +Clicking on the gutter icon reveals the `PullRequestReviewsItem` and highlights that review comment as the "current" one, scrolling to it and expanding its review if necessary. + +### Context and navigation Review comments are shown in 3 different places. The comments themselves have the same functionality, but allow the comment to be seen in a different context, depending on different use cases. For example "reviewing a pull request", "addressing feedback", "editing the entire file". @@ -145,7 +159,7 @@ In order to navigate between comments or switch context, each comment has the fo * Clicking on the `<>` button in a review comment shows the comment in the entire file. If possible, the scroll-position is retained. This allows to quickly get more context about the code. * If the current pull request is not checked out, the `<>` button is disabled, and a tooltip prompts the user to check out the pull request to edit the source. -* Clicking on the "sandwich" button shows the comment under the "Reviews" tab. +* Clicking on the "sandwich" button shows the comment in the corresponding `PullRequestReviewsItem`. * Clicking on the "file-+" button (not shown in above screenshot) shows the comment under the "Files" tab. * The up and down arrow buttons navigate to the next and previous unresolved review comments. * Reaction emoji may be added to each comment with the "emoji" button. Existing emoji reaction tallies are included beneath each comment. From 3bc411e730e7677d9ceacbce20b9ca9834f8c749 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 9 Jan 2019 16:00:17 -0500 Subject: [PATCH 2541/4847] We actually called it "Files Changed," not "Files" --- docs/feature-requests/003-pull-request-review.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index e7c7a45d44..fdc7654fec 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -57,9 +57,9 @@ Overview | Commits | Build Status When the pull request is checked out, an "open" button is shown in the review footer. Clicking "open" opens a `PullRequestReviewsItem` for this pull request's review comments as an item in the right workspace dock. -### Files (tab) +### Files Changed (tab) -Clicking on the "Files" tab displays the full, multi-file diff associated with the pull request. This is akin to the "Files changed" tab on dotcom. +Clicking on the "Files Changed" tab displays the full, multi-file diff associated with the pull request. This is akin to the "Files changed" tab on dotcom. ![files](https://user-images.githubusercontent.com/378023/46536560-d3bb4200-c8e9-11e8-9764-dca0b84245cf.png) @@ -119,7 +119,7 @@ This item is opened in the workspace's right dock when the user: * Clicks the review progress bar in the GitHub tab. * Clicks the "open" button on the review summary footer of a `PullRequestDetailItem`. -* Clicks the "<>" button on a review comment in the "Files" tab of a `PullRequestDetailItem`. +* Clicks the "<>" button on a review comment in the "Files Changed" tab of a `PullRequestDetailItem`. It shows a scrollable view of all of the reviews and comments associated with a specific pull request, @@ -160,7 +160,7 @@ In order to navigate between comments or switch context, each comment has the fo * Clicking on the `<>` button in a review comment shows the comment in the entire file. If possible, the scroll-position is retained. This allows to quickly get more context about the code. * If the current pull request is not checked out, the `<>` button is disabled, and a tooltip prompts the user to check out the pull request to edit the source. * Clicking on the "sandwich" button shows the comment in the corresponding `PullRequestReviewsItem`. -* Clicking on the "file-+" button (not shown in above screenshot) shows the comment under the "Files" tab. +* Clicking on the "file-+" button (not shown in above screenshot) shows the comment under the "Files Changed" tab. * The up and down arrow buttons navigate to the next and previous unresolved review comments. * Reaction emoji may be added to each comment with the "emoji" button. Existing emoji reaction tallies are included beneath each comment. From 56f0eae8e422f6a32086cb04d4b0087af5ea408e Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 9 Jan 2019 13:06:30 -0800 Subject: [PATCH 2542/4847] explicitly test date comparator --- .../controllers/pr-reviews-controller.test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index 1fef175c8d..4edf917316 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -250,4 +250,23 @@ describe('PullRequestReviewsController', function() { assert.strictEqual(comments[0].body, 'reply to outdated comment'); }); }); + describe('compareReviewsByDate', function() { + let wrapper; + const reviewA = reviewBuilder().submittedAt('2018-12-28T20:40:55Z').build(); + const reviewB = reviewBuilder().submittedAt('2018-12-27T20:40:55Z').build(); + + beforeEach(function() { + wrapper = shallow(buildApp()); + }); + + it('returns 1 if reviewA is older', function() { + assert.strictEqual(wrapper.instance().compareReviewsByDate(reviewA, reviewB), 1); + }); + it('return -1 if reviewB is older', function() { + assert.strictEqual(wrapper.instance().compareReviewsByDate(reviewB, reviewA), -1); + }); + it('returns 0 if reviews have the same date', function() { + assert.strictEqual(wrapper.instance().compareReviewsByDate(reviewA, reviewA), 0); + }); + }); }); From 11fb55898d9adf0f48b6121fadfa3a9d0dbd6a0d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 9 Jan 2019 16:07:48 -0500 Subject: [PATCH 2543/4847] Describe the review summary panel within the "Files Changed" tab Co-Authored-By: Vanessa Yuen Co-Authored-By: Katrina Uychaco --- docs/feature-requests/003-pull-request-review.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index fdc7654fec..23244c0a45 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -61,17 +61,24 @@ When the pull request is checked out, an "open" button is shown in the review fo Clicking on the "Files Changed" tab displays the full, multi-file diff associated with the pull request. This is akin to the "Files changed" tab on dotcom. +> TODO: Change "Show review comments" checkbox to an expand/collapse review summaries control + ![files](https://user-images.githubusercontent.com/378023/46536560-d3bb4200-c8e9-11e8-9764-dca0b84245cf.png) -* Diffs are editable. -* Editing the diff is _only_ possible if the pull request branch is checked out and the local branch history has not diverged from the remote branch history. +Clicking on the "Expand review summaries" control in the filter bar reveals an inline panel that displays the summary of each review created on this pull request, including the review's author, the review's current state, its summary comment, and a progress bar showing how many of the review comments associated with this review have been marked as resolved. + +> TODO: Illustrate the "review summary" list panel + +Clicking the checkbox within each review summary block hides or reveals the review summary comments associated with that review in diff on this tab. Clicking the "Collapse review summaries" control conceals the review summary panel again. + +Beneath the review summary panel is the pull request's combined diff. Diffs are editable, but _only_ if the pull request branch is checked out and the local branch history has not diverged incompatibly from the remote branch history. + +For large diffs, the files can be collapsed to get a better overview. Uncollapsed (default) | Collapsed --- | --- ![files](https://user-images.githubusercontent.com/378023/46536560-d3bb4200-c8e9-11e8-9764-dca0b84245cf.png) | ![collapsed files](https://user-images.githubusercontent.com/378023/46931273-7069a680-d085-11e8-9ea7-c96a1772fe27.png) -* For large diffs, the files can be collapsed to get a better overview. - #### Create a new review ##### `+` Button From 4696ec6fff3c236da0101784be4e3f5f6cd5ed34 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 9 Jan 2019 16:45:16 -0500 Subject: [PATCH 2544/4847] "Review summary list panel" concept --- docs/feature-requests/003-pull-request-review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 23244c0a45..2eaf6dd336 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -67,7 +67,7 @@ Clicking on the "Files Changed" tab displays the full, multi-file diff associate Clicking on the "Expand review summaries" control in the filter bar reveals an inline panel that displays the summary of each review created on this pull request, including the review's author, the review's current state, its summary comment, and a progress bar showing how many of the review comments associated with this review have been marked as resolved. -> TODO: Illustrate the "review summary" list panel +![review summary list panel](https://user-images.githubusercontent.com/17565/50930369-e172ed00-142d-11e9-8ae4-00106dde80f5.png) Clicking the checkbox within each review summary block hides or reveals the review summary comments associated with that review in diff on this tab. Clicking the "Collapse review summaries" control conceals the review summary panel again. From 7ff898fc09625abb84bd0d70fb5176379e6e582a Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 9 Jan 2019 13:49:17 -0800 Subject: [PATCH 2545/4847] t e s t c o v e r a g e --- test/controllers/pr-reviews-controller.test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index 4edf917316..11a1ff9729 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -250,6 +250,18 @@ describe('PullRequestReviewsController', function() { assert.strictEqual(comments[0].body, 'reply to outdated comment'); }); }); + + describe('handleError', function() { + it('attempts to load more reviews', function() { + const wrapper = shallow(buildApp()); + + const loadMoreStub = sinon.stub(wrapper.instance(), '_attemptToLoadMoreReviews'); + wrapper.instance().handleError(); + + assert.strictEqual(loadMoreStub.callCount, 1); + }); + }); + describe('compareReviewsByDate', function() { let wrapper; const reviewA = reviewBuilder().submittedAt('2018-12-28T20:40:55Z').build(); From 3aeb59e0ca3feb8dce1b32e8f78911dd9a7469d8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 9 Jan 2019 17:01:29 -0500 Subject: [PATCH 2546/4847] What I'm picturing for the PullRequestReviewsItem --- docs/feature-requests/003-pull-request-review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 2eaf6dd336..2fc225648d 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -130,7 +130,7 @@ This item is opened in the workspace's right dock when the user: It shows a scrollable view of all of the reviews and comments associated with a specific pull request, -> TODO: Illustration for the PullRequestReviewsItem +![pull request reviews item](https://user-images.githubusercontent.com/17565/50931285-213ad400-1430-11e9-8dd2-bd0cc98216fa.png) Reviews are sorted by "urgency," showing reviews that still need to be addressed at the top. Within each group, sorting is done by "newest first". From f805399bf505e5b304fead82cc5a26202a9325da Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Wed, 9 Jan 2019 16:27:30 -0800 Subject: [PATCH 2547/4847] add ugly ForwardRef thing to fix tests --- test/controllers/pr-reviews-controller.test.js | 2 +- test/views/multi-file-patch-view.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index 11a1ff9729..d6210d07bc 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -64,7 +64,7 @@ describe('PullRequestReviewsController', function() { const reviewSpecs = [review1, review2]; const wrapper = shallow(buildApp({reviewSpecs})); - const containers = wrapper.find('Relay(BarePullRequestReviewCommentsContainer)'); + const containers = wrapper.find('ForwardRef(Relay(BarePullRequestReviewCommentsContainer))'); assert.strictEqual(containers.length, 2); assert.strictEqual(containers.at(0).prop('review').id, review1.id); diff --git a/test/views/multi-file-patch-view.test.js b/test/views/multi-file-patch-view.test.js index 813c206af9..d3436debf5 100644 --- a/test/views/multi-file-patch-view.test.js +++ b/test/views/multi-file-patch-view.test.js @@ -137,7 +137,7 @@ describe('MultiFilePatchView', function() { it('renders a PullRequestsReviewsContainer if itemType is IssueishDetailItem', function() { const wrapper = shallow(buildApp({itemType: IssueishDetailItem})); - assert.lengthOf(wrapper.find('Relay(PullRequestReviewsController)'), 1); + assert.lengthOf(wrapper.find('ForwardRef(Relay(PullRequestReviewsController))'), 1); }); it('renders the file patch within an editor', function() { From 9e6e82e7a4adbf82a76fc589aa506b628fe75dd5 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 10 Jan 2019 16:15:05 +0900 Subject: [PATCH 2548/4847] Add screenshot/gif section --- PULL_REQUEST_TEMPLATE.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index c6d8eb658e..09e071659a 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -13,6 +13,10 @@ We must be able to understand the design of your change from this description. I --> +### Screenshot/Gif + + + ### Alternate Designs From a8bd864bcf1b75aa8dfba29e053be35c630f531e Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 10 Jan 2019 16:24:57 +0900 Subject: [PATCH 2549/4847] Add a comma --- PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 09e071659a..7e2f5af7de 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -15,7 +15,7 @@ We must be able to understand the design of your change from this description. I ### Screenshot/Gif - + ### Alternate Designs From a6149058a12f9feec97bbd13a825f0acf35c7721 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 11:27:44 -0500 Subject: [PATCH 2550/4847] Ignore conditionals that are too much of a pain to test --- lib/git-shell-out-strategy.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index d8ad54d16a..2df45a5051 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -119,6 +119,7 @@ export default class GitShellOutStrategy { // Attempt to collect the --exec-path from a native git installation. execPathPromise = new Promise((resolve, reject) => { childProcess.exec('git --exec-path', (error, stdout, stderr) => { + /* istanbul ignore if */ if (error) { // Oh well resolve(null); @@ -202,6 +203,7 @@ export default class GitShellOutStrategy { env.ATOM_GITHUB_GPG_PROMPT = 'true'; } + /* istanbul ignore if */ if (diagnosticsEnabled) { env.GIT_TRACE = 'true'; env.GIT_TRACE_CURL = 'true'; @@ -214,9 +216,11 @@ export default class GitShellOutStrategy { opts.stdinEncoding = 'utf8'; } + /* istanbul ignore if */ if (process.env.PRINT_GIT_TIMES) { console.time(`git:${formattedArgs}`); } + return new Promise(async (resolve, reject) => { if (options.beforeRun) { const newArgsOpts = await options.beforeRun({args, opts}); @@ -236,6 +240,7 @@ export default class GitShellOutStrategy { // chance to fall back to GIT_ASKPASS from the credential handler. await new Promise((resolveKill, rejectKill) => { require('tree-kill')(handlerPid, 'SIGTERM', err => { + /* istanbul ignore if */ if (err) { rejectKill(err); } else { resolveKill(); } }); }); @@ -258,14 +263,18 @@ export default class GitShellOutStrategy { timingMarker.mark('ipc', now - ipcTime); } timingMarker.finalize(); + + /* istanbul ignore if */ if (process.env.PRINT_GIT_TIMES) { console.timeEnd(`git:${formattedArgs}`); } + if (gitPromptServer) { gitPromptServer.terminate(); } subscriptions.dispose(); + /* istanbul ignore if */ if (diagnosticsEnabled) { const exposeControlCharacters = raw => { if (!raw) { return ''; } @@ -374,6 +383,7 @@ export default class GitShellOutStrategy { options.processCallback = child => { childPid = child.pid; + /* istanbul ignore next */ child.stdin.on('error', err => { throw new Error( `Error writing to stdin: git ${args.join(' ')} in ${this.workingDir}\n${options.stdin}\n${err}`); @@ -385,12 +395,14 @@ export default class GitShellOutStrategy { return { promise, cancel: () => { + /* istanbul ignore if */ if (!childPid) { return Promise.resolve(); } return new Promise((resolve, reject) => { require('tree-kill')(childPid, 'SIGTERM', err => { + /* istanbul ignore if */ if (err) { reject(err); } else { resolve(); } }); }); From 3b5e0b2fb046b383dbfb52d634d6ceca422806d2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 11:29:39 -0500 Subject: [PATCH 2551/4847] git rev-parse --resolve-git-dir will always return an absolute path --- lib/git-shell-out-strategy.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 2df45a5051..323a11fecf 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -423,11 +423,7 @@ export default class GitShellOutStrategy { await fs.stat(this.workingDir); // fails if folder doesn't exist const output = await this.exec(['rev-parse', '--resolve-git-dir', path.join(this.workingDir, '.git')]); const dotGitDir = output.trim(); - if (path.isAbsolute(dotGitDir)) { - return toNativePathSep(dotGitDir); - } else { - return toNativePathSep(path.resolve(path.join(this.workingDir, dotGitDir))); - } + return toNativePathSep(dotGitDir); } catch (e) { return null; } From 3313d22bde5fc1d457c78b0b34359dfd06f7e5be Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 11:30:09 -0500 Subject: [PATCH 2552/4847] "unfold" parameter is never used --- lib/git-shell-out-strategy.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 323a11fecf..68ac46c68e 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -815,11 +815,8 @@ export default class GitShellOutStrategy { } } - mergeTrailers(commitMessage, trailers, unfold) { + mergeTrailers(commitMessage, trailers) { const args = ['interpret-trailers']; - if (unfold) { - args.push('--unfold'); - } for (const trailer of trailers) { args.push('--trailer', `${trailer.token}=${trailer.value}`); } From df55ac0ddec0ec9122409ad1d73f7296a2c82b95 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 11:32:05 -0500 Subject: [PATCH 2553/4847] Cover throwing LargeRepoError from getStatusBundle() --- test/git-strategies.test.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 6dbd031fdf..8aa15ed933 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -8,7 +8,7 @@ import hock from 'hock'; import {GitProcess} from 'dugite'; import CompositeGitStrategy from '../lib/composite-git-strategy'; -import GitShellOutStrategy from '../lib/git-shell-out-strategy'; +import GitShellOutStrategy, {LargeRepoError} from '../lib/git-shell-out-strategy'; import WorkerManager from '../lib/worker-manager'; import {cloneRepository, initRepository, assertDeepPropertyVals, setUpLocalAndRemoteRepositories} from './helpers'; @@ -119,8 +119,9 @@ import * as reporterProxy from '../lib/reporter-proxy'; }); }); - if (process.platform === 'win32') { - describe('getStatusBundle()', function() { + + describe('getStatusBundle()', function() { + if (process.platform === 'win32') { it('normalizes the path separator on Windows', async function() { const workingDir = await cloneRepository('three-files'); const git = createTestStrategy(workingDir); @@ -135,8 +136,17 @@ import * as reporterProxy from '../lib/reporter-proxy'; const changedPaths = changedEntries.map(entry => entry.filePath); assert.deepEqual(changedPaths, [relPathA, relPathB]); }); + } + + it('throws a LargeRepoError when the status output is too large', async function() { + const workingDir = await cloneRepository('three-files'); + const git = createTestStrategy(workingDir); + + sinon.stub(git, 'exec').resolves({length: 1024 * 1024 * 10 + 1}); + + await assert.isRejected(git.getStatusBundle(), LargeRepoError); }); - } + }); describe('getHeadCommit()', function() { it('gets the SHA and message of the most recent commit', async function() { From 3c2b06f3bc5edd62766bf98beb59212fc52fd571 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 11:32:51 -0500 Subject: [PATCH 2554/4847] Cover codepaths in exec() --- test/git-strategies.test.js | 59 ++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 8aa15ed933..eb123cc51e 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -29,6 +29,48 @@ import * as reporterProxy from '../lib/reporter-proxy'; }; describe(`Git commands for CompositeGitStrategy made of [${strategies.map(s => s.name).join(', ')}]`, function() { + describe('exec', function() { + let git, incrementCounterStub; + + beforeEach(async function() { + const workingDir = await cloneRepository(); + git = createTestStrategy(workingDir); + incrementCounterStub = sinon.stub(reporterProxy, 'incrementCounter'); + }); + + describe('when the WorkerManager is not ready or disabled', function() { + beforeEach(function() { + sinon.stub(WorkerManager.getInstance(), 'isReady').returns(false); + }); + + it('kills the git process when cancel is triggered by the prompt server', async function() { + const promptStub = sinon.stub().rejects(); + git.setPromptCallback(promptStub); + + const stdin = dedent` + host=noway.com + username=me + + `; + await git.exec(['credential', 'fill'], {useGitPromptServer: true, stdin}); + + assert.isTrue(promptStub.called); + }); + }); + + it('does not call incrementCounter when git command is on the ignore list', async function() { + await git.exec(['status']); + assert.equal(incrementCounterStub.callCount, 0); + }); + + it('does call incrementCounter when git command is NOT on the ignore list', async function() { + await git.exec(['commit', '--allow-empty', '-m', 'make an empty commit']); + + assert.equal(incrementCounterStub.callCount, 1); + assert.deepEqual(incrementCounterStub.lastCall.args, ['commit']); + }); + }); + // https://github.com/atom/github/issues/1051 // https://github.com/atom/github/issues/898 it('passes all environment variables to spawned git process', async function() { @@ -1534,24 +1576,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; }); }); }); - describe('exec', function() { - let workingDirPath, git, incrementCounterStub; - beforeEach(async function() { - workingDirPath = await cloneRepository('three-files'); - git = createTestStrategy(workingDirPath); - incrementCounterStub = sinon.stub(reporterProxy, 'incrementCounter'); - }); - it('does not call incrementCounter when git command is on the ignore list', async function() { - await git.exec(['status']); - assert.equal(incrementCounterStub.callCount, 0); - }); - it('does call incrementCounter when git command is NOT on the ignore list', async function() { - await git.exec(['commit', '--allow-empty', '-m', 'make an empty commit']); - assert.equal(incrementCounterStub.callCount, 1); - assert.deepEqual(incrementCounterStub.lastCall.args, ['commit']); - }); - }); describe('executeGitCommand', function() { it('shells out in process until WorkerManager instance is ready', async function() { if (process.env.ATOM_GITHUB_INLINE_GIT_EXEC) { From 240ccdf0afac8353cf59f27021ed0289cd031266 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 11:33:24 -0500 Subject: [PATCH 2555/4847] Cover fetchCommitMessageTemplate() --- test/git-strategies.test.js | 45 ++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index eb123cc51e..f713da487b 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -1,6 +1,7 @@ import fs from 'fs-extra'; import path from 'path'; import http from 'http'; +import os from 'os'; import mkdirp from 'mkdirp'; import dedent from 'dedent-js'; @@ -128,11 +129,15 @@ import * as reporterProxy from '../lib/reporter-proxy'; }); describe('fetchCommitMessageTemplate', function() { - it('gets commit message from template', async function() { - const workingDirPath = await cloneRepository('three-files'); - const git = createTestStrategy(workingDirPath); - const templateText = 'some commit message'; + let git, workingDirPath, templateText; + + beforeEach(async function() { + workingDirPath = await cloneRepository('three-files'); + git = createTestStrategy(workingDirPath); + templateText = 'some commit message'; + }); + it('gets commit message from template', async function() { const commitMsgTemplatePath = path.join(workingDirPath, '.gitmessage'); await fs.writeFile(commitMsgTemplatePath, templateText, {encoding: 'utf8'}); @@ -141,17 +146,11 @@ import * as reporterProxy from '../lib/reporter-proxy'; }); it('if config is not set return null', async function() { - const workingDirPath = await cloneRepository('three-files'); - const git = createTestStrategy(workingDirPath); - assert.isNotOk(await git.getConfig('commit.template')); // falsy value of null or '' assert.isNull(await git.fetchCommitMessageTemplate()); }); it('if config is set but file does not exist throw an error', async function() { - const workingDirPath = await cloneRepository('three-files'); - const git = createTestStrategy(workingDirPath); - const nonExistentCommitTemplatePath = path.join(workingDirPath, 'file-that-doesnt-exist'); await git.setConfig('commit.template', nonExistentCommitTemplatePath); await assert.isRejected( @@ -159,6 +158,32 @@ import * as reporterProxy from '../lib/reporter-proxy'; `Invalid commit template path set in Git config: ${nonExistentCommitTemplatePath}`, ); }); + + it('replaces ~ with your home directory', async function() { + await git.setConfig('commit.template', '~/does-not-exist.txt'); + await assert.isRejected( + git.fetchCommitMessageTemplate(), + `Invalid commit template path set in Git config: ${path.join(os.homedir(), 'does-not-exist.txt')}`, + ); + }); + + it("replaces ~user with user's home directory", async function() { + const expectedFullPath = path.join(path.dirname(os.homedir()), 'nope/does-not-exist.txt'); + await git.setConfig('commit.template', '~nope/does-not-exist.txt'); + await assert.isRejected( + git.fetchCommitMessageTemplate(), + `Invalid commit template path set in Git config: ${expectedFullPath}`, + ); + }); + + it('interprets relative paths local to the working directory', async function() { + const subDir = path.join(workingDirPath, 'abc/def/ghi'); + const subPath = path.join(subDir, 'template.txt'); + await fs.mkdirs(subDir); + await fs.writeFile(subPath, templateText, {encoding: 'utf8'}); + await git.setConfig('commit.template', path.join('abc/def/ghi/template.txt')); + assert.strictEqual(await git.fetchCommitMessageTemplate(), templateText); + }); }); From 0b454873767d356403d75920216eeb2506079797 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 11:34:47 -0500 Subject: [PATCH 2556/4847] Cover handling of unexpected git errors --- test/git-strategies.test.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index f713da487b..bb8d9456c3 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -503,6 +503,14 @@ import * as reporterProxy from '../lib/reporter-proxy'; const authors = await git.getAuthors({max: 1}); assert.deepEqual(authors, []); }); + + it('propagates other git errors', async function() { + const workingDirPath = await cloneRepository('multiple-commits'); + const git = createTestStrategy(workingDirPath); + sinon.stub(git, 'exec').rejects(new Error('oh no')); + + await assert.isRejected(git.getAuthors(), /oh no/); + }); }); describe('diffFileStatus', function() { @@ -1059,6 +1067,14 @@ import * as reporterProxy from '../lib/reporter-proxy'; await git.setConfig('awesome.devs', 'BinaryMuse,kuychaco,smashwilson'); assert.equal('BinaryMuse,kuychaco,smashwilson', await git.getConfig('awesome.devs')); }); + + it('propagates unexpected git errors', async function() { + const workingDirPath = await cloneRepository('three-files'); + const git = createTestStrategy(workingDirPath); + sinon.stub(git, 'exec').rejects(new Error('AHHHH')); + + await assert.isRejected(git.getConfig('some.key'), /AHHHH/); + }); }); describe('commit(message, options)', function() { @@ -1447,6 +1463,14 @@ import * as reporterProxy from '../lib/reporter-proxy'; const contents = await git.exec(['cat-file', '-p', sha]); assert.equal(contents, 'foo\n'); }); + + it('propagates unexpected git errors from hash-object', async function() { + const workingDirPath = await cloneRepository(); + const git = createTestStrategy(workingDirPath); + sinon.stub(git, 'exec').rejects(new Error('shiiiit')); + + await assert.isRejected(git.createBlob({filePath: 'a.txt'}), /shiiiit/); + }); }); describe('expandBlobToFile(absFilePath, sha)', function() { @@ -1542,6 +1566,14 @@ import * as reporterProxy from '../lib/reporter-proxy'; assert.isTrue(contents.includes('<<<<<<<')); assert.isTrue(contents.includes('>>>>>>>')); }); + + it('propagates unexpected git errors', async function() { + const workingDirPath = await cloneRepository('three-files'); + const git = createTestStrategy(workingDirPath); + sinon.stub(git, 'exec').rejects(new Error('ouch')); + + await assert.isRejected(git.mergeFile('a.txt', 'b.txt', 'c.txt', 'result.txt'), /ouch/); + }); }); describe('updateIndex(filePath, commonBaseSha, oursSha, theirsSha)', function() { From 24da545a9180ebbb271fc1f1260baefb6820e311 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 11:35:34 -0500 Subject: [PATCH 2557/4847] Cover unexpected git diff output --- test/git-strategies.test.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index bb8d9456c3..852064efd1 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -609,6 +609,42 @@ import * as reporterProxy from '../lib/reporter-proxy'; assert.isDefined(diffOutput); }); + it('rejects if an unexpected number of diffs is returned', async function() { + const workingDirPath = await cloneRepository(); + const git = createTestStrategy(workingDirPath); + sinon.stub(git, 'exec').resolves(dedent` + diff --git aaa.txt aaa.txt + index df565d30..244a7225 100644 + --- aaa.txt + +++ aaa.txt + @@ -100,3 +100,3 @@ + 000 + -001 + +002 + 003 + diff --git aaa.txt aaa.txt + index df565d30..244a7225 100644 + --- aaa.txt + +++ aaa.txt + @@ -100,3 +100,3 @@ + 000 + -001 + +002 + 003 + diff --git aaa.txt aaa.txt + index df565d30..244a7225 100644 + --- aaa.txt + +++ aaa.txt + @@ -100,3 +100,3 @@ + 000 + -001 + +002 + 003 + `); + + await assert.isRejected(git.getDiffsForFilePath('aaa.txt'), /Expected between 0 and 2 diffs/); + }); + describe('when the file is unstaged', function() { it('returns a diff comparing the working directory copy of the file and the version on the index', async function() { const workingDirPath = await cloneRepository('three-files'); From 97200a16e93c7c858ca4c4f8a253045df7962e44 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 11:35:51 -0500 Subject: [PATCH 2558/4847] Input argument validation tests --- test/git-strategies.test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 852064efd1..378f24abf0 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -971,6 +971,12 @@ import * as reporterProxy from '../lib/reporter-proxy'; assert.deepEqual(stagedChange.hunks[0].lines, [' foo', '+bar']); }); }); + + it('fails when an invalid type is passed', async function() { + const workingDirPath = await cloneRepository('three-files'); + const git = createTestStrategy(workingDirPath); + assert.throws(() => git.reset('scrambled'), /Invalid type scrambled/); + }); }); describe('deleteRef()', function() { @@ -1507,6 +1513,12 @@ import * as reporterProxy from '../lib/reporter-proxy'; await assert.isRejected(git.createBlob({filePath: 'a.txt'}), /shiiiit/); }); + + it('rejects if neither file path or stdin are provided', async function() { + const workingDirPath = await cloneRepository(); + const git = createTestStrategy(workingDirPath); + await assert.isRejected(git.createBlob(), /Must supply file path or stdin/); + }); }); describe('expandBlobToFile(absFilePath, sha)', function() { From 8bf9385ac242da5f4849da714933d4983d2ff68c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 11:36:10 -0500 Subject: [PATCH 2559/4847] Fail correctly when amending an unborn commit --- test/git-strategies.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 378f24abf0..9cb81fb169 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -1198,6 +1198,13 @@ import * as reporterProxy from '../lib/reporter-proxy'; assert.strictEqual(amendedCommit.messageSubject, 'first'); assert.strictEqual(amendedCommit.messageBody, 'second\n\nthird'); }); + + it('attempts to amend an unborn commit', async function() { + const workingDirPath = await initRepository(); + const git = createTestStrategy(workingDirPath); + + await assert.isRejected(git.commit('', {amend: true, allowEmpty: true}), /You have nothing to amend/); + }); }); }); From 4860e97ddfc46d5b3a128ef3daa76ec1036dfb28 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 11:36:27 -0500 Subject: [PATCH 2560/4847] Test degenerate case of checkoutSide() --- test/git-strategies.test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 9cb81fb169..aa9ade3c8a 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -1302,6 +1302,17 @@ import * as reporterProxy from '../lib/reporter-proxy'; }); }); + describe('checkoutSide', function() { + it('is a no-op when no paths are provided', async function() { + const workdir = await cloneRepository(); + const git = await createTestStrategy(workdir); + sinon.spy(git, 'exec'); + + await git.checkoutSide('ours', []); + assert.isFalse(git.exec.called); + }); + }); + // Only needs to be tested on strategies that actually implement gpgExec describe('GPG signing', function() { let git; From 6539e2b2ad7767ef16ed6a37686f2dcd75cb8e90 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 13:19:09 -0500 Subject: [PATCH 2561/4847] Cover git process spawn rejection --- test/git-strategies.test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index aa9ade3c8a..8620ea1010 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -59,6 +59,11 @@ import * as reporterProxy from '../lib/reporter-proxy'; }); }); + it('rejects if the process fails to spawn for an unexpected reason', async function() { + sinon.stub(git, 'executeGitCommand').returns({promise: Promise.reject(new Error('wat'))}); + await assert.isRejected(git.exec(['version']), /wat/); + }); + it('does not call incrementCounter when git command is on the ignore list', async function() { await git.exec(['status']); assert.equal(incrementCounterStub.callCount, 0); From f99e1e22e09e81a22c3fe0cb6520db0a565fa71e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 13:38:50 -0500 Subject: [PATCH 2562/4847] Use correct path separators in fake template paths --- test/git-strategies.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 8620ea1010..d782777f19 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -165,7 +165,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; }); it('replaces ~ with your home directory', async function() { - await git.setConfig('commit.template', '~/does-not-exist.txt'); + await git.setConfig('commit.template', path.join('~/does-not-exist.txt')); await assert.isRejected( git.fetchCommitMessageTemplate(), `Invalid commit template path set in Git config: ${path.join(os.homedir(), 'does-not-exist.txt')}`, @@ -174,7 +174,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; it("replaces ~user with user's home directory", async function() { const expectedFullPath = path.join(path.dirname(os.homedir()), 'nope/does-not-exist.txt'); - await git.setConfig('commit.template', '~nope/does-not-exist.txt'); + await git.setConfig('commit.template', path.join('~nope/does-not-exist.txt')); await assert.isRejected( git.fetchCommitMessageTemplate(), `Invalid commit template path set in Git config: ${expectedFullPath}`, From 73a6354530563d574f3bc9394e78605c1b3c2a14 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 14:10:18 -0500 Subject: [PATCH 2563/4847] Handle either path separator in EXPAND_TILDE_REGEX --- lib/git-shell-out-strategy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 68ac46c68e..a8cde05c5c 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -61,9 +61,9 @@ const DISABLE_COLOR_FLAGS = [ * Ex: on Mac ~kuychaco/ is expanded to the specified user’s home directory (/Users/kuychaco) * Regex translation: * ^~ line starts with tilde - * ([^/]*)/ captures non-forwardslash characters before first slash + * ([^/]*)[\\/] captures non-forwardslash characters before first slash */ -const EXPAND_TILDE_REGEX = new RegExp('^~([^/]*)/'); +const EXPAND_TILDE_REGEX = new RegExp('^~([^/]*)[\\/]'); export default class GitShellOutStrategy { static defaultExecArgs = { From 9658e1eb10974c19bf2dc4837cc476e32943b1df Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 14:27:04 -0500 Subject: [PATCH 2564/4847] Test coverage for GitTempDir --- test/git-temp-dir.test.js | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 test/git-temp-dir.test.js diff --git a/test/git-temp-dir.test.js b/test/git-temp-dir.test.js new file mode 100644 index 0000000000..f5746c0375 --- /dev/null +++ b/test/git-temp-dir.test.js @@ -0,0 +1,71 @@ +import fs from 'fs-extra'; +import path from 'path'; + +import GitTempDir, {BIN_SCRIPTS} from '../lib/git-temp-dir'; + +describe('GitTempDir', function() { + it('ensures that a temporary directory is populated', async function() { + const tempDir = new GitTempDir(); + await tempDir.ensure(); + + const root = tempDir.getRootPath(); + for (const scriptName in BIN_SCRIPTS) { + const script = BIN_SCRIPTS[scriptName]; + const stat = await fs.stat(path.join(root, script)); + assert.isTrue(stat.isFile()); + if (script.endsWith('.sh') && process.platform !== 'win32') { + // eslint-disable-next-line no-bitwise + assert.isTrue((stat.mode & fs.constants.S_IXUSR) === fs.constants.S_IXUSR); + } + } + + await tempDir.ensure(); + assert.strictEqual(root, tempDir.getRootPath()); + }); + + it('generates getters for script paths', async function() { + const tempDir = new GitTempDir(); + await tempDir.ensure(); + + const scriptPath = tempDir.getScriptPath('git-credential-atom.js'); + assert.isTrue(scriptPath.startsWith(tempDir.getRootPath())); + assert.isTrue(scriptPath.endsWith('git-credential-atom.js')); + + assert.strictEqual(tempDir.getCredentialHelperJs(), tempDir.getScriptPath('git-credential-atom.js')); + assert.strictEqual(tempDir.getCredentialHelperSh(), tempDir.getScriptPath('git-credential-atom.sh')); + assert.strictEqual(tempDir.getAskPassJs(), tempDir.getScriptPath('git-askpass-atom.js')); + }); + + it('fails when the temp dir is not yet created', function() { + const tempDir = new GitTempDir(); + assert.throws(() => tempDir.getAskPassJs(), /uninitialized GitTempDir/); + }); + + if (process.platform === 'win32') { + it('generates a valid named pipe path for its socket', async function() { + const tempDir = new GitTempDir(); + await tempDir.ensure(); + + assert.match(tempDir.getSocketPath(), /^\\\\\?\\pipe\\/); + }); + } else { + it('generates a socket path within the directory', async function() { + const tempDir = new GitTempDir(); + await tempDir.ensure(); + + assert.isTrue(tempDir.getSocketPath().startsWith(tempDir.getRootPath())); + }); + } + + it('deletes the directory on dispose', async function() { + const tempDir = new GitTempDir(); + await tempDir.ensure(); + + const beforeStat = await fs.stat(tempDir.getRootPath()); + assert.isTrue(beforeStat.isDirectory()); + + await tempDir.dispose(); + + await assert.isRejected(fs.stat(tempDir.getRootPath()), /ENOENT/); + }); +}); From 3d34f7e008245a5a2152fc0a858b17acf9ce6013 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 14:50:42 -0500 Subject: [PATCH 2565/4847] path.join() looks like it's resolving the path on Windows? --- test/git-strategies.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index d782777f19..56aaf34248 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -165,7 +165,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; }); it('replaces ~ with your home directory', async function() { - await git.setConfig('commit.template', path.join('~/does-not-exist.txt')); + await git.setConfig('commit.template', `~${path.sep}does-not-exist.txt`); await assert.isRejected( git.fetchCommitMessageTemplate(), `Invalid commit template path set in Git config: ${path.join(os.homedir(), 'does-not-exist.txt')}`, @@ -174,7 +174,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; it("replaces ~user with user's home directory", async function() { const expectedFullPath = path.join(path.dirname(os.homedir()), 'nope/does-not-exist.txt'); - await git.setConfig('commit.template', path.join('~nope/does-not-exist.txt')); + await git.setConfig('commit.template', `~nope${path.sep}does-not-exist.txt`); await assert.isRejected( git.fetchCommitMessageTemplate(), `Invalid commit template path set in Git config: ${expectedFullPath}`, From efb6ddcecda891f2d3018a1894df792bb0504d30 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 15:36:15 -0500 Subject: [PATCH 2566/4847] More Regexp tries --- lib/git-shell-out-strategy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index a8cde05c5c..36dd15fbaf 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -61,9 +61,9 @@ const DISABLE_COLOR_FLAGS = [ * Ex: on Mac ~kuychaco/ is expanded to the specified user’s home directory (/Users/kuychaco) * Regex translation: * ^~ line starts with tilde - * ([^/]*)[\\/] captures non-forwardslash characters before first slash + * ([^\\/]*)[\\/] captures non-slash characters before first slash */ -const EXPAND_TILDE_REGEX = new RegExp('^~([^/]*)[\\/]'); +const EXPAND_TILDE_REGEX = new RegExp('^~([^\\/]*)[\\/]'); export default class GitShellOutStrategy { static defaultExecArgs = { From 89be380251dba8a6951d22df806e828fd8651f98 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 10 Jan 2019 16:12:50 -0500 Subject: [PATCH 2567/4847] Grrr --- lib/git-shell-out-strategy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 36dd15fbaf..dd4280aeba 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -61,9 +61,9 @@ const DISABLE_COLOR_FLAGS = [ * Ex: on Mac ~kuychaco/ is expanded to the specified user’s home directory (/Users/kuychaco) * Regex translation: * ^~ line starts with tilde - * ([^\\/]*)[\\/] captures non-slash characters before first slash + * ([^\\\\/]*)[\\\\/] captures non-slash characters before first slash */ -const EXPAND_TILDE_REGEX = new RegExp('^~([^\\/]*)[\\/]'); +const EXPAND_TILDE_REGEX = new RegExp('^~([^\\\\/]*)[\\\\/]'); export default class GitShellOutStrategy { static defaultExecArgs = { From 5428bb21f51a4f9ea68590e49520244df6c5eee6 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 10 Jan 2019 13:19:22 -0800 Subject: [PATCH 2568/4847] use default git cleanup configuration if commit template exists. in https://github.com/atom/github/issues/1817, there is a bug where we are not stripping commented lines if a git message template exists. The `verbatim` flag is passed if the commit is made from a mini editor. The mini editor is meant to be analagous of `git commit -m`, a quick and dirty sort of affair. As much as I don't want to add special cases here, it seemed like the cleanest to ignore `verbatim` if you have a template set. --- lib/git-shell-out-strategy.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index d8ad54d16a..40cade6d87 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -506,8 +506,12 @@ export default class GitShellOutStrategy { msg = rawMessage; } + // if commit template is used, that will not play nicely with `verbatim` + // because we want to strip commented lines from templates. + const template = await this.fetchCommitMessageTemplate(); + // Determine the cleanup mode. - if (verbatim) { + if (verbatim && !template) { args.push('--cleanup=verbatim'); } else { const configured = await this.getConfig('commit.cleanup'); From 5cf450782a87f19aca3da1c8ecb474b46deebd49 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 10 Jan 2019 13:39:43 -0800 Subject: [PATCH 2569/4847] add unit test to ensure that comments are stripped if commit message is used --- test/git-strategies.test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 6dbd031fdf..9d9583b481 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -1036,6 +1036,24 @@ import * as reporterProxy from '../lib/reporter-proxy'; 'and things', ].join('\n')); }); + it('ignores verbatim flag if commit template is used', async function() { + const workingDirPath = await cloneRepository('three-files'); + const git = createTestStrategy(workingDirPath); + const templateText = '# this line should be stripped'; + + const commitMsgTemplatePath = path.join(workingDirPath, '.gitmessage'); + await fs.writeFile(commitMsgTemplatePath, templateText, {encoding: 'utf8'}); + + await git.setConfig('commit.template', commitMsgTemplatePath); + await git.setConfig('commit.cleanup', 'default'); + const commitMessage = ['this line should not be stripped', '', 'neither should this one', templateText].join('\n'); + await git.commit(commitMessage, {allowEmpty: true, verbatim: true}); + + const lastCommit = await git.getHeadCommit(); + assert.strictEqual(lastCommit.messageSubject, 'this line should not be stripped'); + // message body should not contain the template text + assert.strictEqual(lastCommit.messageBody, 'neither should this one'); + }); }); describe('when amend option is true', function() { From a9a7ecd6c347d205f59318c03f99d3c031a5b7b7 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 10 Jan 2019 14:50:07 -0800 Subject: [PATCH 2570/4847] move clock inside the only test that needs it it's cleaner, and the tests were stalling when run all together (the individual tests worked fine) --- test/controllers/pr-reviews-controller.test.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index d6210d07bc..eaba38f15c 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -108,15 +108,6 @@ describe('PullRequestReviewsController', function() { }); describe('attemptToLoadMoreReviews', function() { - let clock; - beforeEach(function() { - clock = sinon.useFakeTimers(); - }); - - afterEach(function() { - clock = sinon.restore(); - }); - it('does not call loadMore if hasMore is false', function() { const relayLoadMoreStub = sinon.stub(); const wrapper = shallow(buildApp({relayLoadMore: relayLoadMoreStub})); @@ -138,6 +129,7 @@ describe('PullRequestReviewsController', function() { }); it('calls loadMore after a timeout if hasMore is true and isLoading is true', function() { + const clock = sinon.useFakeTimers(); const relayLoadMoreStub = sinon.stub(); const relayHasMore = () => { return true; }; const relayIsLoading = () => { return true; }; @@ -153,6 +145,7 @@ describe('PullRequestReviewsController', function() { clock.tick(PAGINATION_WAIT_TIME_MS); assert.strictEqual(relayLoadMoreStub.callCount, 1); assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleError]); + sinon.restore(); }); }); From 888979372d6c6e27026d29caf2e4405bec6f6a73 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 10 Jan 2019 14:51:18 -0800 Subject: [PATCH 2571/4847] `accumulate` is totes a better name for those functions Co-Authored-By: Ash Wilson --- lib/containers/pr-review-comments-container.js | 6 +++--- lib/controllers/pr-reviews-controller.js | 4 ++-- test/containers/pr-review-comments-container.test.js | 10 +++++----- test/controllers/pr-reviews-controller.test.js | 10 +++++----- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index c514c9f313..9ab65f7e10 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -21,10 +21,10 @@ export class BarePullRequestReviewCommentsContainer extends React.Component { } componentDidMount() { - this.handleComments(); + this.accumulateComments(); } - handleComments = error => { + accumulateComments = error => { /* istanbul ignore if */ if (error) { // eslint-disable-next-line no-console @@ -58,7 +58,7 @@ export class BarePullRequestReviewCommentsContainer extends React.Component { _loadMoreComments = () => { this.props.relay.loadMore( PAGE_SIZE, - this.handleComments, + this.accumulateComments, ); } diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 428bb38b7b..d7c3acd62c 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -43,7 +43,7 @@ export default class PullRequestReviewsController extends React.Component { } } - handleError = error => { + accumulateReviews = error => { /* istanbul ignore if */ if (error) { // eslint-disable-next-line no-console @@ -54,7 +54,7 @@ export default class PullRequestReviewsController extends React.Component { } _loadMoreReviews = () => { - this.props.relay.loadMore(PAGE_SIZE, this.handleError); + this.props.relay.loadMore(PAGE_SIZE, this.accumulateReviews); } render() { diff --git a/test/containers/pr-review-comments-container.test.js b/test/containers/pr-review-comments-container.test.js index 8eb7916221..164124640b 100644 --- a/test/containers/pr-review-comments-container.test.js +++ b/test/containers/pr-review-comments-container.test.js @@ -60,18 +60,18 @@ describe('PullRequestReviewCommentsContainer', function() { const wrapper = shallow(buildApp({relayLoadMore: relayLoadMoreStub})); wrapper.instance()._loadMoreComments(); - assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleComments]); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().accumulateComments]); }); }); - describe('handleComments', function() { + describe('accumulateComments', function() { it('collects comments and attempts to load more comments', function() { const collectCommentsStub = sinon.stub(); const wrapper = shallow(buildApp({}, {collectComments: collectCommentsStub})); // collect comments is called when mounted, we don't care about that in this test so reset the count collectCommentsStub.reset(); sinon.stub(wrapper.instance(), '_attemptToLoadMoreComments'); - wrapper.instance().handleComments(); + wrapper.instance().accumulateComments(); assert.strictEqual(collectCommentsStub.callCount, 1); @@ -112,7 +112,7 @@ describe('PullRequestReviewCommentsContainer', function() { wrapper.instance()._attemptToLoadMoreComments(); assert.strictEqual(relayLoadMoreStub.callCount, 1); - assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleComments]); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().accumulateComments]); }); it('calls loadMore after a timeout if hasMore is true and isLoading is true', function() { @@ -130,7 +130,7 @@ describe('PullRequestReviewCommentsContainer', function() { clock.tick(PAGINATION_WAIT_TIME_MS); assert.strictEqual(relayLoadMoreStub.callCount, 1); - assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleComments]); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().accumulateComments]); }); }); }); diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index eaba38f15c..83cfa8eadd 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -125,7 +125,7 @@ describe('PullRequestReviewsController', function() { wrapper.instance()._attemptToLoadMoreReviews(); assert.strictEqual(relayLoadMoreStub.callCount, 1); - assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleError]); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().accumulateReviews]); }); it('calls loadMore after a timeout if hasMore is true and isLoading is true', function() { @@ -144,7 +144,7 @@ describe('PullRequestReviewsController', function() { clock.tick(PAGINATION_WAIT_TIME_MS); assert.strictEqual(relayLoadMoreStub.callCount, 1); - assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleError]); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().accumulateReviews]); sinon.restore(); }); }); @@ -155,7 +155,7 @@ describe('PullRequestReviewsController', function() { const wrapper = shallow(buildApp({relayLoadMore: relayLoadMoreStub})); wrapper.instance()._loadMoreReviews(); - assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().handleError]); + assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().accumulateReviews]); }); }); @@ -244,12 +244,12 @@ describe('PullRequestReviewsController', function() { }); }); - describe('handleError', function() { + describe('accumulateReviews', function() { it('attempts to load more reviews', function() { const wrapper = shallow(buildApp()); const loadMoreStub = sinon.stub(wrapper.instance(), '_attemptToLoadMoreReviews'); - wrapper.instance().handleError(); + wrapper.instance().accumulateReviews(); assert.strictEqual(loadMoreStub.callCount, 1); }); From 7155d25a71f0523c2bb26891ab753447f3089a84 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 10 Jan 2019 14:53:35 -0800 Subject: [PATCH 2572/4847] move other fake :clock: inside test too --- .../containers/pr-review-comments-container.test.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/test/containers/pr-review-comments-container.test.js b/test/containers/pr-review-comments-container.test.js index 164124640b..df3d9ea318 100644 --- a/test/containers/pr-review-comments-container.test.js +++ b/test/containers/pr-review-comments-container.test.js @@ -86,15 +86,6 @@ describe('PullRequestReviewCommentsContainer', function() { }); describe('attemptToLoadMoreComments', function() { - let clock; - beforeEach(function() { - clock = sinon.useFakeTimers(); - }); - - afterEach(function() { - clock = sinon.restore(); - }); - it('does not call loadMore if hasMore is false', function() { const relayLoadMoreStub = sinon.stub(); const wrapper = shallow(buildApp({relayLoadMore: relayLoadMoreStub})); @@ -116,6 +107,7 @@ describe('PullRequestReviewCommentsContainer', function() { }); it('calls loadMore after a timeout if hasMore is true and isLoading is true', function() { + const clock = sinon.useFakeTimers(); const relayLoadMoreStub = sinon.stub(); const relayHasMore = () => { return true; }; const relayIsLoading = () => { return true; }; @@ -131,6 +123,9 @@ describe('PullRequestReviewCommentsContainer', function() { clock.tick(PAGINATION_WAIT_TIME_MS); assert.strictEqual(relayLoadMoreStub.callCount, 1); assert.deepEqual(relayLoadMoreStub.lastCall.args, [PAGE_SIZE, wrapper.instance().accumulateComments]); + + // buybye fake timer it was nice knowing you + sinon.restore(); }); }); }); From 615df63c31fd0432b5245e95f48ae4c6cd40451d Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 10 Jan 2019 16:50:02 -0800 Subject: [PATCH 2573/4847] deal with minimized comments you can mark comments as spammy, or even abusive, so I'm really glad we caught this before shipping. --- .../issueishDetailContainerQuery.graphql.js | 12 ++++- .../prReviewCommentsContainerQuery.graphql.js | 12 ++++- ...rReviewCommentsContainer_review.graphql.js | 10 +++- .../prReviewsContainerQuery.graphql.js | 12 ++++- .../pr-review-comments-container.js | 1 + .../prDetailViewRefetchQuery.graphql.js | 12 ++++- lib/views/pr-review-comments-view.js | 46 ++++++++++++------- styles/pr-comment.less | 8 ++++ 8 files changed, 88 insertions(+), 25 deletions(-) diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 08c8d4132a..2ec6a9595d 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash b2844afc76c2e9c390039931a9af7d40 + * @relayHash aa9982b03c50cc4fd52b07a4206b1eb0 */ /* eslint-disable */ @@ -559,6 +559,7 @@ fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { } } bodyHTML + isMinimized path position replyTo { @@ -1207,7 +1208,7 @@ return { "operationKind": "query", "name": "issueishDetailContainerQuery", "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_3D8CP9 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_3D8CP9 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1647,6 +1648,13 @@ return { v2, v26, v12, + { + "kind": "ScalarField", + "alias": null, + "name": "isMinimized", + "args": null, + "storageKey": null + }, v39, v40, { diff --git a/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js index 0904ea42ba..6fa92aa46b 100644 --- a/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 5e0b465f16f55322d70100cd893a1c04 + * @relayHash d372fbac67c0b387985686b68db27130 */ /* eslint-disable */ @@ -63,6 +63,7 @@ fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { } } bodyHTML + isMinimized path position replyTo { @@ -139,7 +140,7 @@ return { "operationKind": "query", "name": "prReviewCommentsContainerQuery", "id": null, - "text": "query prReviewCommentsContainerQuery(\n $commentCount: Int!\n $commentCursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequestReview {\n ...prReviewCommentsContainer_review_1VbUmL\n }\n id\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "text": "query prReviewCommentsContainerQuery(\n $commentCount: Int!\n $commentCursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequestReview {\n ...prReviewCommentsContainer_review_1VbUmL\n }\n id\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -306,6 +307,13 @@ return { "args": null, "storageKey": null }, + { + "kind": "ScalarField", + "alias": null, + "name": "isMinimized", + "args": null, + "storageKey": null + }, { "kind": "ScalarField", "alias": null, diff --git a/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js b/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js index aec8134452..ebe2215fea 100644 --- a/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js +++ b/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js @@ -27,6 +27,7 @@ export type prReviewCommentsContainer_review = {| +login: string, |}, +bodyHTML: any, + +isMinimized: boolean, +path: string, +position: ?number, +replyTo: ?{| @@ -181,6 +182,13 @@ return { "args": null, "storageKey": null }, + { + "kind": "ScalarField", + "alias": null, + "name": "isMinimized", + "args": null, + "storageKey": null + }, { "kind": "ScalarField", "alias": null, @@ -238,5 +246,5 @@ return { }; })(); // prettier-ignore -(node/*: any*/).hash = '63492273ddd049ed59809581c7795811'; +(node/*: any*/).hash = 'ccea6475d7b22690b4aa61757b705968'; module.exports = node; diff --git a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js index 7e64650ea5..19537cca71 100644 --- a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 455845bc2fe2987a2c32d72dbc9247b6 + * @relayHash a3845eb13d831f5f140cc6adc98de1df */ /* eslint-disable */ @@ -108,6 +108,7 @@ fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { } } bodyHTML + isMinimized path position replyTo { @@ -263,7 +264,7 @@ return { "operationKind": "query", "name": "prReviewsContainerQuery", "id": null, - "text": "query prReviewsContainerQuery(\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_y4qc0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "text": "query prReviewsContainerQuery(\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_y4qc0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -492,6 +493,13 @@ return { "args": null, "storageKey": null }, + { + "kind": "ScalarField", + "alias": null, + "name": "isMinimized", + "args": null, + "storageKey": null + }, { "kind": "ScalarField", "alias": null, diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 9ab65f7e10..16051026bd 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -94,6 +94,7 @@ export default createPaginationContainer(BarePullRequestReviewCommentsContainer, login } bodyHTML + isMinimized path position replyTo { diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index 8b5d424baa..42e336a55a 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 631a28049723f0b6b8a3f8eb25a4f955 + * @relayHash c9c759b66c17ed333ce2946f8675ee19 */ /* eslint-disable */ @@ -475,6 +475,7 @@ fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { } } bodyHTML + isMinimized path position replyTo { @@ -885,7 +886,7 @@ return { "operationKind": "query", "name": "prDetailViewRefetchQuery", "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {}, "fragment": { "kind": "Fragment", @@ -1133,6 +1134,13 @@ return { v6, v24, v25, + { + "kind": "ScalarField", + "alias": null, + "name": "isMinimized", + "args": null, + "storageKey": null + }, v26, v27, { diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index 09f8bc9bf9..80e89af272 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -5,6 +5,8 @@ import {Point, Range} from 'atom'; import {toNativePathSep} from '../helpers'; import Marker from '../atom/marker'; import Decoration from '../atom/decoration'; +import Octicon from '../atom/octicon'; + import GithubDotcomMarkdown from './github-dotcom-markdown'; import Timeago from './timeago'; @@ -65,25 +67,37 @@ export class PullRequestCommentView extends React.Component { bodyHTML: PropTypes.string, url: PropTypes.string, createdAt: PropTypes.string.isRequired, + isMinimized: PropTypes.bool.isRequired, }).isRequired, } render() { - const author = this.props.comment.author; - const login = author ? author.login : 'someone'; - return ( -
    -
    - {login} - {login} commented{' '} - - - -
    -
    - -
    -
    - ); + if (this.props.comment.isMinimized) { + return ( +
    + + + This comment was hidden + +
    + ); + } else { + const author = this.props.comment.author; + const login = author ? author.login : 'someone'; + return ( +
    +
    + {login} + {login} commented{' '} + + + +
    +
    + +
    +
    + ); + } } } diff --git a/styles/pr-comment.less b/styles/pr-comment.less index f2ff654985..f71f9f097f 100644 --- a/styles/pr-comment.less +++ b/styles/pr-comment.less @@ -50,4 +50,12 @@ margin-left: @avatar-size + @avatar-spacing; // avatar + margin } + &-hidden { + font-size: 14px; + } + + &-icon { + vertical-align: middle; + } + } From b346a451b0e637f9969203e02a10dbffc36e0e86 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 11 Jan 2019 09:02:25 -0500 Subject: [PATCH 2574/4847] Normalize commit template paths on Windows --- lib/git-shell-out-strategy.js | 1 + test/git-strategies.test.js | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index dd4280aeba..f431a44961 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -454,6 +454,7 @@ export default class GitShellOutStrategy { // if no user is specified, fall back to using the home directory. return `${user ? path.join(path.dirname(homeDir), user) : homeDir}/`; }); + templatePath = toNativePathSep(templatePath); if (!path.isAbsolute(templatePath)) { templatePath = path.join(this.workingDir, templatePath); diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 56aaf34248..7ed32ece11 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -165,7 +165,8 @@ import * as reporterProxy from '../lib/reporter-proxy'; }); it('replaces ~ with your home directory', async function() { - await git.setConfig('commit.template', `~${path.sep}does-not-exist.txt`); + // Fun fact: even on Windows, git does not accept "~\does-not-exist.txt" + await git.setConfig('commit.template', '~/does-not-exist.txt'); await assert.isRejected( git.fetchCommitMessageTemplate(), `Invalid commit template path set in Git config: ${path.join(os.homedir(), 'does-not-exist.txt')}`, @@ -174,7 +175,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; it("replaces ~user with user's home directory", async function() { const expectedFullPath = path.join(path.dirname(os.homedir()), 'nope/does-not-exist.txt'); - await git.setConfig('commit.template', `~nope${path.sep}does-not-exist.txt`); + await git.setConfig('commit.template', '~nope/does-not-exist.txt'); await assert.isRejected( git.fetchCommitMessageTemplate(), `Invalid commit template path set in Git config: ${expectedFullPath}`, From adf996ec3bae29e53253b1f540d1e311e1cebf0d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 11 Jan 2019 09:37:21 -0500 Subject: [PATCH 2575/4847] Handle path separator normalization on Windows --- lib/containers/pr-changed-files-container.js | 9 +++++---- lib/models/patch/multi-file-patch.js | 1 - test/containers/pr-changed-files-container.test.js | 8 ++++++++ test/fixtures/diffs/raw-diff.js | 6 +++--- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/containers/pr-changed-files-container.js b/lib/containers/pr-changed-files-container.js index beb3c5d38b..539c7a3b82 100644 --- a/lib/containers/pr-changed-files-container.js +++ b/lib/containers/pr-changed-files-container.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import {parse as parseDiff} from 'what-the-diff'; import {ItemTypePropType, EndpointPropType} from '../prop-types'; +import {toNativePathSep} from '../helpers'; import MultiFilePatchController from '../controllers/multi-file-patch-controller'; import LoadingView from '../views/loading-view'; import ErrorView from '../views/error-view'; @@ -60,13 +61,13 @@ export default class PullRequestChangedFilesContainer extends React.Component { buildPatch(rawDiff) { const diffs = parseDiff(rawDiff).map(diff => { - // diff coming from API will have the defaul git diff prefixes a/ and b/ - // e.g. a/file1.js and b/file2.js + // diff coming from API will have the defaul git diff prefixes a/ and b/ and use *nix-style / path separators. + // e.g. a/dir/file1.js and b/dir/file2.js // see https://git-scm.com/docs/git-diff#_generating_patches_with_p return { ...diff, - newPath: diff.newPath ? diff.newPath.replace(/^[a|b]\//, '') : diff.newPath, - oldPath: diff.oldPath ? diff.oldPath.replace(/^[a|b]\//, '') : diff.oldPath, + newPath: diff.newPath ? toNativePathSep(diff.newPath.replace(/^[a|b]\//, '')) : diff.newPath, + oldPath: diff.oldPath ? toNativePathSep(diff.oldPath.replace(/^[a|b]\//, '')) : diff.oldPath, }; }); return buildMultiFilePatch(diffs); diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index e04a498416..e21ae6158f 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -340,7 +340,6 @@ export default class MultiFilePatch { } getBufferRowForDiffPosition = (fileName, diffRow) => { - // TODO verify that this works on Windows const {startBufferRow, index} = this.diffRowOffsetIndices.get(fileName); const {offset} = index.lowerBound({diffRow}).data(); return startBufferRow + diffRow - offset; diff --git a/test/containers/pr-changed-files-container.test.js b/test/containers/pr-changed-files-container.test.js index af252cb56c..47896dcfb4 100644 --- a/test/containers/pr-changed-files-container.test.js +++ b/test/containers/pr-changed-files-container.test.js @@ -1,6 +1,7 @@ import React from 'react'; import {shallow} from 'enzyme'; import {parse as parseDiff} from 'what-the-diff'; +import path from 'path'; import {rawDiff, rawDiffWithPathPrefix} from '../fixtures/diffs/raw-diff'; import {buildMultiFilePatch} from '../../lib/models/patch'; @@ -79,6 +80,13 @@ describe('PullRequestChangedFilesContainer', function() { assert.notMatch(filePatches[0].oldFile.path, /^[a|b]\//); }); + it('converts file paths to use native path separators', function() { + const wrapper = shallow(buildApp()); + const {filePatches} = wrapper.instance().buildPatch(rawDiffWithPathPrefix); + assert.strictEqual(filePatches[0].newFile.path, path.join('bad/path.txt')); + assert.strictEqual(filePatches[0].oldFile.path, path.join('bad/path.txt')); + }); + it('passes loaded diff data through to the controller', async function() { const wrapper = shallow(buildApp({ token: '4321', diff --git a/test/fixtures/diffs/raw-diff.js b/test/fixtures/diffs/raw-diff.js index 0d57194fec..473df75cb5 100644 --- a/test/fixtures/diffs/raw-diff.js +++ b/test/fixtures/diffs/raw-diff.js @@ -12,10 +12,10 @@ const rawDiff = dedent` line3 `; const rawDiffWithPathPrefix = dedent` - diff --git a/badpath.txt b/badpath.txt + diff --git a/bad/path.txt b/bad/path.txt index af607bb..cfac420 100644 - --- a/badpath.txt - +++ b/badpath.txt + --- a/bad/path.txt + +++ b/bad/path.txt @@ -1,2 +1,3 @@ line0 -line1 From 185d096e010f00947bbecd766bb9e985a43b7881 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 11 Jan 2019 10:30:35 -0500 Subject: [PATCH 2576/4847] Cover uncovered lines in Side --- lib/models/conflicts/banner.js | 1 + lib/models/conflicts/side.js | 1 + .../single-2way-diff-empty.txt | 8 + test/models/conflicts/conflict.test.js | 369 +++++++++++++++++- 4 files changed, 370 insertions(+), 9 deletions(-) create mode 100644 test/fixtures/conflict-marker-examples/single-2way-diff-empty.txt diff --git a/lib/models/conflicts/banner.js b/lib/models/conflicts/banner.js index 47080ca2ce..25630fe329 100644 --- a/lib/models/conflicts/banner.js +++ b/lib/models/conflicts/banner.js @@ -26,6 +26,7 @@ export default class Banner { revert() { const range = this.getMarker().getBufferRange(); this.editor.setTextInBufferRange(range, this.originalText); + this.getMarker().setBufferRange(range); } delete() { diff --git a/lib/models/conflicts/side.js b/lib/models/conflicts/side.js index e99174c89a..17585511a0 100644 --- a/lib/models/conflicts/side.js +++ b/lib/models/conflicts/side.js @@ -98,6 +98,7 @@ export default class Side { revert() { const range = this.getMarker().getBufferRange(); this.editor.setTextInBufferRange(range, this.originalText); + this.getMarker().setBufferRange(range); } deleteBanner() { diff --git a/test/fixtures/conflict-marker-examples/single-2way-diff-empty.txt b/test/fixtures/conflict-marker-examples/single-2way-diff-empty.txt new file mode 100644 index 0000000000..802eb878f7 --- /dev/null +++ b/test/fixtures/conflict-marker-examples/single-2way-diff-empty.txt @@ -0,0 +1,8 @@ +Before the start + +<<<<<<< HEAD +These are my changes +======= +>>>>>>> master + +Past the end diff --git a/test/models/conflicts/conflict.test.js b/test/models/conflicts/conflict.test.js index f8ac15018d..8a1c877a8a 100644 --- a/test/models/conflicts/conflict.test.js +++ b/test/models/conflicts/conflict.test.js @@ -21,10 +21,10 @@ describe('Conflict', function() { return atomEnv.workspace.open(fullPath); }; - const assertConflictOnRows = function(conflict, description, message) { + const assertConflictOnRows = function(conflict, description) { const isRangeOnRows = function(range, startRow, endRow, rangeName) { - assert( - range.start.row === startRow && range.start.column === 0 && range.end.row === endRow && range.end.column === 0, + assert.isTrue( + range.start.row === startRow && range.end.row === endRow, `expected conflict's ${rangeName} range to cover rows ${startRow} to ${endRow}, but it was ${range}`, ); }; @@ -33,27 +33,37 @@ describe('Conflict', function() { return isRangeOnRows(range, row, row + 1, rangeName); }; - const ourBannerRange = conflict.getSide(OURS).banner.marker.getBufferRange(); + const isPointOnRow = function(range, row, rangeName) { + return isRangeOnRows(range, row, row, rangeName); + }; + + const ourBannerRange = conflict.getSide(OURS).getBannerMarker().getBufferRange(); isRangeOnRow(ourBannerRange, description.ourBannerRow, '"ours" banner'); - const ourSideRange = conflict.getSide(OURS).marker.getBufferRange(); + const ourSideRange = conflict.getSide(OURS).getMarker().getBufferRange(); isRangeOnRows(ourSideRange, description.ourSideRows[0], description.ourSideRows[1], '"ours"'); assert.strictEqual(conflict.getSide(OURS).position, description.ourPosition || TOP, '"ours" in expected position'); - const theirBannerRange = conflict.getSide(THEIRS).banner.marker.getBufferRange(); + const ourBlockRange = conflict.getSide(OURS).getBlockMarker().getBufferRange(); + isPointOnRow(ourBlockRange, description.ourBannerRow, '"ours" block range'); + + const theirBannerRange = conflict.getSide(THEIRS).getBannerMarker().getBufferRange(); isRangeOnRow(theirBannerRange, description.theirBannerRow, '"theirs" banner'); - const theirSideRange = conflict.getSide(THEIRS).marker.getBufferRange(); + const theirSideRange = conflict.getSide(THEIRS).getMarker().getBufferRange(); isRangeOnRows(theirSideRange, description.theirSideRows[0], description.theirSideRows[1], '"theirs"'); assert.strictEqual(conflict.getSide(THEIRS).position, description.theirPosition || BOTTOM, '"theirs" in expected position'); + const theirBlockRange = conflict.getSide(THEIRS).getBlockMarker().getBufferRange(); + isPointOnRow(theirBlockRange, description.theirBannerRow, '"theirs" block range'); + if (description.baseBannerRow || description.baseSideRows) { assert.isNotNull(conflict.getSide(BASE), "expected conflict's base side to be non-null"); - const baseBannerRange = conflict.getSide(BASE).banner.marker.getBufferRange(); + const baseBannerRange = conflict.getSide(BASE).getBannerMarker().getBufferRange(); isRangeOnRow(baseBannerRange, description.baseBannerRow, '"base" banner'); - const baseSideRange = conflict.getSide(BASE).marker.getBufferRange(); + const baseSideRange = conflict.getSide(BASE).getMarker().getBufferRange(); isRangeOnRows(baseSideRange, description.baseSideRows[0], description.baseSideRows[1], '"base"'); assert.strictEqual(conflict.getSide(BASE).position, MIDDLE, '"base" in MIDDLE position'); } else { @@ -277,4 +287,345 @@ end assert.isTrue(conflict.getSeparator().isModified()); }); }); + + describe('contextual block position and CSS class generation', function() { + let editor, conflict; + + describe('from a merge', function() { + beforeEach(async function() { + editor = await editorOnFixture('single-3way-diff.txt'); + conflict = Conflict.allFromEditor(editor, editor.getDefaultMarkerLayer(), false)[0]; + }); + + it('accesses the block decoration position', function() { + assert.strictEqual(conflict.getSide(OURS).getBlockPosition(), 'before'); + assert.strictEqual(conflict.getSide(BASE).getBlockPosition(), 'before'); + assert.strictEqual(conflict.getSide(THEIRS).getBlockPosition(), 'after'); + }); + + it('accesses the line decoration CSS class', function() { + assert.strictEqual(conflict.getSide(OURS).getLineCSSClass(), 'github-ConflictOurs'); + assert.strictEqual(conflict.getSide(BASE).getLineCSSClass(), 'github-ConflictBase'); + assert.strictEqual(conflict.getSide(THEIRS).getLineCSSClass(), 'github-ConflictTheirs'); + }); + + it('accesses the line decoration CSS class when modified', function() { + for (const position of [[5, 1], [3, 1], [1, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual(conflict.getSide(OURS).getLineCSSClass(), 'github-ConflictModified'); + assert.strictEqual(conflict.getSide(BASE).getLineCSSClass(), 'github-ConflictModified'); + assert.strictEqual(conflict.getSide(THEIRS).getLineCSSClass(), 'github-ConflictModified'); + }); + + it('accesses the line decoration CSS class when the banner is modified', function() { + for (const position of [[6, 1], [2, 1], [0, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual(conflict.getSide(OURS).getLineCSSClass(), 'github-ConflictModified'); + assert.strictEqual(conflict.getSide(BASE).getLineCSSClass(), 'github-ConflictModified'); + assert.strictEqual(conflict.getSide(THEIRS).getLineCSSClass(), 'github-ConflictModified'); + }); + + it('accesses the banner CSS class', function() { + assert.strictEqual(conflict.getSide(OURS).getBannerCSSClass(), 'github-ConflictOursBanner'); + assert.strictEqual(conflict.getSide(BASE).getBannerCSSClass(), 'github-ConflictBaseBanner'); + assert.strictEqual(conflict.getSide(THEIRS).getBannerCSSClass(), 'github-ConflictTheirsBanner'); + }); + + it('accesses the banner CSS class when modified', function() { + for (const position of [[5, 1], [3, 1], [1, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual(conflict.getSide(OURS).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + assert.strictEqual(conflict.getSide(BASE).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + assert.strictEqual(conflict.getSide(THEIRS).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + }); + + it('accesses the banner CSS class when the banner is modified', function() { + for (const position of [[6, 1], [2, 1], [0, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual(conflict.getSide(OURS).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + assert.strictEqual(conflict.getSide(BASE).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + assert.strictEqual(conflict.getSide(THEIRS).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + }); + + it('accesses the block CSS classes', function() { + assert.strictEqual( + conflict.getSide(OURS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictOursBlock github-ConflictTopBlock', + ); + assert.strictEqual( + conflict.getSide(BASE).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictBaseBlock github-ConflictMiddleBlock', + ); + assert.strictEqual( + conflict.getSide(THEIRS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictTheirsBlock github-ConflictBottomBlock', + ); + }); + + it('accesses the block CSS classes when modified', function() { + for (const position of [[5, 1], [3, 1], [1, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual( + conflict.getSide(OURS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictOursBlock github-ConflictTopBlock github-ConflictModifiedBlock', + ); + assert.strictEqual( + conflict.getSide(BASE).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictBaseBlock github-ConflictMiddleBlock github-ConflictModifiedBlock', + ); + assert.strictEqual( + conflict.getSide(THEIRS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictTheirsBlock github-ConflictBottomBlock github-ConflictModifiedBlock', + ); + }); + + it('accesses the block CSS classes when the banner is modified', function() { + for (const position of [[6, 1], [2, 1], [0, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual( + conflict.getSide(OURS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictOursBlock github-ConflictTopBlock github-ConflictModifiedBlock', + ); + assert.strictEqual( + conflict.getSide(BASE).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictBaseBlock github-ConflictMiddleBlock github-ConflictModifiedBlock', + ); + assert.strictEqual( + conflict.getSide(THEIRS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictTheirsBlock github-ConflictBottomBlock github-ConflictModifiedBlock', + ); + }); + }); + + describe('from a rebase', function() { + beforeEach(async function() { + editor = await editorOnFixture('single-3way-diff.txt'); + conflict = Conflict.allFromEditor(editor, editor.getDefaultMarkerLayer(), true)[0]; + }); + + it('accesses the block decoration position', function() { + assert.strictEqual(conflict.getSide(THEIRS).getBlockPosition(), 'before'); + assert.strictEqual(conflict.getSide(BASE).getBlockPosition(), 'before'); + assert.strictEqual(conflict.getSide(OURS).getBlockPosition(), 'after'); + }); + + it('accesses the line decoration CSS class', function() { + assert.strictEqual(conflict.getSide(THEIRS).getLineCSSClass(), 'github-ConflictTheirs'); + assert.strictEqual(conflict.getSide(BASE).getLineCSSClass(), 'github-ConflictBase'); + assert.strictEqual(conflict.getSide(OURS).getLineCSSClass(), 'github-ConflictOurs'); + }); + + it('accesses the line decoration CSS class when modified', function() { + for (const position of [[5, 1], [3, 1], [1, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual(conflict.getSide(THEIRS).getLineCSSClass(), 'github-ConflictModified'); + assert.strictEqual(conflict.getSide(BASE).getLineCSSClass(), 'github-ConflictModified'); + assert.strictEqual(conflict.getSide(OURS).getLineCSSClass(), 'github-ConflictModified'); + }); + + it('accesses the line decoration CSS class when the banner is modified', function() { + for (const position of [[6, 1], [2, 1], [0, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual(conflict.getSide(THEIRS).getLineCSSClass(), 'github-ConflictModified'); + assert.strictEqual(conflict.getSide(BASE).getLineCSSClass(), 'github-ConflictModified'); + assert.strictEqual(conflict.getSide(OURS).getLineCSSClass(), 'github-ConflictModified'); + }); + + it('accesses the banner CSS class', function() { + assert.strictEqual(conflict.getSide(THEIRS).getBannerCSSClass(), 'github-ConflictTheirsBanner'); + assert.strictEqual(conflict.getSide(BASE).getBannerCSSClass(), 'github-ConflictBaseBanner'); + assert.strictEqual(conflict.getSide(OURS).getBannerCSSClass(), 'github-ConflictOursBanner'); + }); + + it('accesses the banner CSS class when modified', function() { + for (const position of [[5, 1], [3, 1], [1, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual(conflict.getSide(THEIRS).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + assert.strictEqual(conflict.getSide(BASE).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + assert.strictEqual(conflict.getSide(OURS).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + }); + + it('accesses the banner CSS class when the banner is modified', function() { + for (const position of [[6, 1], [2, 1], [0, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual(conflict.getSide(THEIRS).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + assert.strictEqual(conflict.getSide(BASE).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + assert.strictEqual(conflict.getSide(OURS).getBannerCSSClass(), 'github-ConflictModifiedBanner'); + }); + + it('accesses the block CSS classes', function() { + assert.strictEqual( + conflict.getSide(THEIRS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictTheirsBlock github-ConflictTopBlock', + ); + assert.strictEqual( + conflict.getSide(BASE).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictBaseBlock github-ConflictMiddleBlock', + ); + assert.strictEqual( + conflict.getSide(OURS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictOursBlock github-ConflictBottomBlock', + ); + }); + + it('accesses the block CSS classes when modified', function() { + for (const position of [[5, 1], [3, 1], [1, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual( + conflict.getSide(THEIRS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictTheirsBlock github-ConflictTopBlock github-ConflictModifiedBlock', + ); + assert.strictEqual( + conflict.getSide(BASE).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictBaseBlock github-ConflictMiddleBlock github-ConflictModifiedBlock', + ); + assert.strictEqual( + conflict.getSide(OURS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictOursBlock github-ConflictBottomBlock github-ConflictModifiedBlock', + ); + }); + + it('accesses the block CSS classes when the banner is modified', function() { + for (const position of [[6, 1], [2, 1], [0, 1]]) { + editor.setCursorBufferPosition(position); + editor.insertText('change'); + } + + assert.strictEqual( + conflict.getSide(THEIRS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictTheirsBlock github-ConflictTopBlock github-ConflictModifiedBlock', + ); + assert.strictEqual( + conflict.getSide(BASE).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictBaseBlock github-ConflictMiddleBlock github-ConflictModifiedBlock', + ); + assert.strictEqual( + conflict.getSide(OURS).getBlockCSSClasses(), + 'github-ConflictBlock github-ConflictOursBlock github-ConflictBottomBlock github-ConflictModifiedBlock', + ); + }); + }); + }); + + it('accesses a side range that encompasses the banner and content', async function() { + const editor = await editorOnFixture('single-3way-diff.txt'); + const conflict = Conflict.allFromEditor(editor, editor.getDefaultMarkerLayer(), false)[0]; + + assert.deepEqual(conflict.getSide(OURS).getRange().serialize(), [[0, 0], [2, 0]]); + assert.deepEqual(conflict.getSide(BASE).getRange().serialize(), [[2, 0], [4, 0]]); + assert.deepEqual(conflict.getSide(THEIRS).getRange().serialize(), [[5, 0], [7, 0]]); + }); + + it('determines the inclusion of points', async function() { + const editor = await editorOnFixture('single-3way-diff.txt'); + const conflict = Conflict.allFromEditor(editor, editor.getDefaultMarkerLayer(), false)[0]; + + assert.isTrue(conflict.getSide(OURS).includesPoint([0, 1])); + assert.isTrue(conflict.getSide(OURS).includesPoint([1, 3])); + assert.isFalse(conflict.getSide(OURS).includesPoint([2, 1])); + }); + + it('detects when a side is empty', async function() { + const editor = await editorOnFixture('single-2way-diff-empty.txt'); + const conflict = Conflict.allFromEditor(editor, editor.getDefaultMarkerLayer(), false)[0]; + + assert.isFalse(conflict.getSide(OURS).isEmpty()); + assert.isTrue(conflict.getSide(THEIRS).isEmpty()); + }); + + it('reverts a modified Side', async function() { + const editor = await editorOnFixture('single-3way-diff.txt'); + const conflict = Conflict.allFromEditor(editor, editor.getDefaultMarkerLayer(), false)[0]; + + editor.setCursorBufferPosition([5, 10]); + editor.insertText('MY-CHANGE'); + + assert.isTrue(conflict.getSide(THEIRS).isModified()); + assert.match(editor.getText(), /MY-CHANGE/); + + conflict.getSide(THEIRS).revert(); + + assert.isFalse(conflict.getSide(THEIRS).isModified()); + assert.notMatch(editor.getText(), /MY-CHANGE/); + }); + + it('reverts a modified Side banner', async function() { + const editor = await editorOnFixture('single-3way-diff.txt'); + const conflict = Conflict.allFromEditor(editor, editor.getDefaultMarkerLayer(), false)[0]; + + editor.setCursorBufferPosition([6, 4]); + editor.insertText('MY-CHANGE'); + + assert.isTrue(conflict.getSide(THEIRS).isBannerModified()); + assert.match(editor.getText(), /MY-CHANGE/); + + conflict.getSide(THEIRS).revertBanner(); + + assert.isFalse(conflict.getSide(THEIRS).isBannerModified()); + assert.notMatch(editor.getText(), /MY-CHANGE/); + }); + + it('deletes a banner', async function() { + const editor = await editorOnFixture('single-3way-diff.txt'); + const conflict = Conflict.allFromEditor(editor, editor.getDefaultMarkerLayer(), false)[0]; + + assert.match(editor.getText(), /<<<<<<< HEAD/); + conflict.getSide(OURS).deleteBanner(); + assert.notMatch(editor.getText(), /<<<<<<< HEAD/); + }); + + it('deletes a side', async function() { + const editor = await editorOnFixture('single-3way-diff.txt'); + const conflict = Conflict.allFromEditor(editor, editor.getDefaultMarkerLayer(), false)[0]; + + assert.match(editor.getText(), /your/); + conflict.getSide(THEIRS).delete(); + assert.notMatch(editor.getText(), /your/); + }); + + it('appends text to a side', async function() { + const editor = await editorOnFixture('single-3way-diff.txt'); + const conflict = Conflict.allFromEditor(editor, editor.getDefaultMarkerLayer(), false)[0]; + + assert.notMatch(editor.getText(), /APPENDED/); + conflict.getSide(THEIRS).appendText('APPENDED\n'); + assert.match(editor.getText(), /APPENDED/); + + assert.isTrue(conflict.getSide(THEIRS).isModified()); + assert.strictEqual(conflict.getSide(THEIRS).getText(), 'These are your changes\nAPPENDED\n'); + assert.isFalse(conflict.getSide(THEIRS).isBannerModified()); + }); }); From 00ff5d0838b38a549f81761e05b56f301e10ff27 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 11 Jan 2019 16:36:12 +0100 Subject: [PATCH 2577/4847] add hidden comment test --- test/views/pr-comments-view.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index 3a87f20737..15e2562626 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -118,4 +118,10 @@ describe('PullRequestCommentView', function() { const wrapper = shallow(buildApp({author: null})); assert.isTrue(wrapper.text().includes('someone commented')); }); + + it('hides minimized comment', function() { + const wrapper = shallow(buildApp({isMinimized: true})); + assert.isTrue(wrapper.find('.github-PrComment-hidden').exists()); + assert.isFalse(wrapper.find('.github-PrComment-header').exists()); + }); }); From 94cb39ccb623bbb4d7f23f4f009f5e02c6bb8076 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 11 Jan 2019 11:32:59 -0500 Subject: [PATCH 2578/4847] Full coverage for Decoration --- lib/atom/decoration.js | 10 +++--- test/atom/decoration.test.js | 63 ++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/lib/atom/decoration.js b/lib/atom/decoration.js index cd3cbead27..9da22e42ac 100644 --- a/lib/atom/decoration.js +++ b/lib/atom/decoration.js @@ -64,12 +64,12 @@ class BareDecoration extends React.Component { componentDidUpdate(prevProps) { if (this.props.editorHolder !== prevProps.editorHolder) { this.editorSub.dispose(); - this.editorSub = this.state.editorHolder.observe(this.observeParents); + this.editorSub = this.props.editorHolder.observe(this.observeParents); } if (this.props.decorableHolder !== prevProps.decorableHolder) { this.decorableSub.dispose(); - this.decorableSub = this.state.decorableHolder.observe(this.observeParents); + this.decorableSub = this.props.decorableHolder.observe(this.observeParents); } if ( @@ -95,10 +95,10 @@ class BareDecoration extends React.Component { this.decorationHolder.map(decoration => decoration.destroy()); const editorValid = this.props.editorHolder.map(editor => !editor.isDestroyed()).getOr(false); - const markableValid = this.props.decorableHolder.map(decorable => !decorable.isDestroyed()).getOr(false); + const decorableValid = this.props.decorableHolder.map(decorable => !decorable.isDestroyed()).getOr(false); // Ensure the Marker or MarkerLayer corresponds to the context's TextEditor - const markableMatches = this.props.decorableHolder.map(decorable => this.props.editorHolder.map(editor => { + const decorableMatches = this.props.decorableHolder.map(decorable => this.props.editorHolder.map(editor => { const layer = decorable.layer || decorable; const displayLayer = editor.getMarkerLayer(layer.id); if (!displayLayer) { @@ -110,7 +110,7 @@ class BareDecoration extends React.Component { return true; }).getOr(false)).getOr(false); - if (!editorValid || !markableValid || !markableMatches) { + if (!editorValid || !decorableValid || !decorableMatches) { return; } diff --git a/test/atom/decoration.test.js b/test/atom/decoration.test.js index 2e9fd4fdcd..db187dfdcb 100644 --- a/test/atom/decoration.test.js +++ b/test/atom/decoration.test.js @@ -99,6 +99,69 @@ describe('Decoration', function() { }); }); + describe('when called with changed props', function() { + let wrapper, originalDecoration; + + beforeEach(function() { + const app = ( + + ); + wrapper = mount(app); + + originalDecoration = editor.getLineDecorations({position: 'head', class: 'something'})[0]; + }); + + it('redecorates when a new Editor and Marker are provided', async function() { + const newEditor = await workspace.open(require.resolve('../../package.json')); + const newMarker = newEditor.markBufferRange([[0, 0], [2, 0]]); + + wrapper.setProps({editor: newEditor, decorable: newMarker}); + + assert.isTrue(originalDecoration.isDestroyed()); + assert.lengthOf(editor.getLineDecorations({position: 'head', class: 'something'}), 0); + assert.lengthOf(newEditor.getLineDecorations({position: 'head', class: 'something'}), 1); + }); + + it('redecorates when a new MarkerLayer is provided', function() { + const newLayer = editor.addMarkerLayer(); + + wrapper.setProps({decorable: newLayer, decorateMethod: 'decorateMarkerLayer'}); + + assert.isTrue(originalDecoration.isDestroyed()); + assert.lengthOf(editor.getLineDecorations({position: 'head', class: 'something'}), 0); + + // Turns out Atom doesn't provide any public way to query the markers on a layer. + assert.lengthOf( + Array.from(editor.decorationManager.layerDecorationsByMarkerLayer.get(newLayer)), + 1, + ); + }); + + it('updates decoration properties', function() { + wrapper.setProps({className: 'different'}); + + assert.lengthOf(editor.getLineDecorations({position: 'head', class: 'something'}), 0); + assert.lengthOf(editor.getLineDecorations({position: 'head', class: 'different'}), 1); + assert.isFalse(originalDecoration.isDestroyed()); + assert.strictEqual(originalDecoration.getProperties().class, 'different'); + }); + + it('does not redecorate when the decorable is on the wrong TextEditor', async function() { + const newEditor = await workspace.open(require.resolve('../../package.json')); + + wrapper.setProps({editor: newEditor}); + + assert.isTrue(originalDecoration.isDestroyed()); + assert.lengthOf(editor.getLineDecorations({}), 0); + }); + }); + it('destroys its decoration on unmount', function() { const app = ( Date: Fri, 11 Jan 2019 13:59:25 -0500 Subject: [PATCH 2579/4847] Cover EditorConflictController --- lib/controllers/editor-conflict-controller.js | 9 +-- .../editor-conflict-controller.test.js | 71 +++++++++++++++++++ 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/lib/controllers/editor-conflict-controller.js b/lib/controllers/editor-conflict-controller.js index 728cfc5021..79f7309512 100644 --- a/lib/controllers/editor-conflict-controller.js +++ b/lib/controllers/editor-conflict-controller.js @@ -18,11 +18,7 @@ export default class EditorConflictController extends React.Component { commandRegistry: PropTypes.object.isRequired, resolutionProgress: PropTypes.object.isRequired, isRebase: PropTypes.bool.isRequired, - refreshResolutionProgress: PropTypes.func, - } - - static defaultProps = { - refreshResolutionProgress: () => {}, + refreshResolutionProgress: PropTypes.func.isRequired, } constructor(props, context) { @@ -49,7 +45,6 @@ export default class EditorConflictController extends React.Component { const buffer = this.props.editor.getBuffer(); this.subscriptions.add( - this.props.editor.onDidStopChanging(() => this.forceUpdate()), this.props.editor.onDidDestroy(() => this.props.refreshResolutionProgress(this.props.editor.getPath())), buffer.onDidReload(() => this.reparseConflicts()), ); @@ -171,7 +166,7 @@ export default class EditorConflictController extends React.Component { } dismissConflicts(conflicts) { - this.setState((prevState, props) => { + this.setState(prevState => { const {added} = compareSets(new Set(conflicts), prevState.conflicts); return {conflicts: added}; }); diff --git a/test/controllers/editor-conflict-controller.test.js b/test/controllers/editor-conflict-controller.test.js index 61ef4b376c..872acb70f2 100644 --- a/test/controllers/editor-conflict-controller.test.js +++ b/test/controllers/editor-conflict-controller.test.js @@ -166,6 +166,49 @@ describe('EditorConflictController', function() { assert.strictEqual(conflicts[2].getChosenSide(), conflicts[2].getSide(THEIRS)); }); + it('resolves multiple conflicts as "ours"', function() { + assert.isFalse(conflicts[0].isResolved()); + assert.isFalse(conflicts[1].isResolved()); + assert.isFalse(conflicts[2].isResolved()); + + editor.setCursorBufferPosition([8, 3]); // On "Your changes" + editor.addCursorAtBufferPosition([11, 2]); // On "Text in between 0 and 1." + editor.addCursorAtBufferPosition([14, 5]); // On "My middle changes" + editor.addCursorAtBufferPosition([15, 0]); // On "=======" + commandRegistry.dispatch(editorView, 'github:resolve-as-ours'); + + assert.isTrue(conflicts[0].isResolved()); + assert.strictEqual(conflicts[0].getChosenSide(), conflicts[0].getSide(OURS)); + assert.deepEqual(conflicts[0].getUnchosenSides(), [conflicts[0].getSide(THEIRS)]); + + assert.isTrue(conflicts[1].isResolved()); + assert.strictEqual(conflicts[1].getChosenSide(), conflicts[1].getSide(OURS)); + assert.deepEqual(conflicts[1].getUnchosenSides(), [conflicts[1].getSide(THEIRS)]); + + assert.isFalse(conflicts[2].isResolved()); + }); + + it('resolves multiple conflicts as "theirs"', function() { + assert.isFalse(conflicts[0].isResolved()); + assert.isFalse(conflicts[1].isResolved()); + assert.isFalse(conflicts[2].isResolved()); + + editor.setCursorBufferPosition([8, 3]); // On "Your changes" + editor.addCursorAtBufferPosition([11, 2]); // On "Text in between 0 and 1." + editor.addCursorAtBufferPosition([22, 5]); // On "More of my changes" + commandRegistry.dispatch(editorView, 'github:resolve-as-theirs'); + + assert.isTrue(conflicts[0].isResolved()); + assert.strictEqual(conflicts[0].getChosenSide(), conflicts[0].getSide(THEIRS)); + assert.deepEqual(conflicts[0].getUnchosenSides(), [conflicts[0].getSide(OURS)]); + + assert.isFalse(conflicts[1].isResolved()); + + assert.isTrue(conflicts[2].isResolved()); + assert.strictEqual(conflicts[2].getChosenSide(), conflicts[2].getSide(THEIRS)); + assert.deepEqual(conflicts[2].getUnchosenSides(), [conflicts[2].getSide(OURS)]); + }); + it('disregards conflicts with cursors on both sides', function() { editor.setCursorBufferPosition([6, 3]); // On "Multi-line even" editor.addCursorAtBufferPosition([14, 1]); // On "My middle changes" @@ -316,6 +359,26 @@ describe('EditorConflictController', function() { await assert.async.isTrue(refreshResolutionProgress.calledWith(fixtureFile)); }); + + it('performs a resolution from the context menu', function() { + const conflict = conflicts[1]; + assert.isFalse(conflict.isResolved()); + + wrapper.find('ConflictController').at(1).prop('resolveAsSequence')([OURS]); + + assert.isTrue(conflict.isResolved()); + assert.strictEqual(conflict.getChosenSide(), conflict.getSide(OURS)); + }); + + it('dismisses a conflict from the context menu', function() { + const conflict = conflicts[2]; + + wrapper.find('ConflictController').at(2).prop('dismiss')(); + wrapper.update(); + + assert.lengthOf(wrapper.find(ConflictController), 2); + assert.isFalse(wrapper.find(ConflictController).someWhere(cc => cc.prop('conflict') === conflict)); + }); }); describe('on a file with 3-way diff markers', function() { @@ -442,4 +505,12 @@ describe('EditorConflictController', function() { assert.equal(editor.getText(), 'These are my changes\nThese are your changes\n\nPast the end\n'); }); }); + + it('cleans up its subscriptions when unmounting', async function() { + await useFixture('triple-2way-diff.txt'); + wrapper.unmount(); + + editor.destroy(); + assert.isFalse(refreshResolutionProgress.called); + }); }); From 9f5c577d57b9bac3b0f61af7b205653241a4eedf Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 11 Jan 2019 11:50:59 -0800 Subject: [PATCH 2580/4847] :art: comment. --- lib/controllers/pr-reviews-controller.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index d7c3acd62c..d10839eb69 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -122,12 +122,15 @@ export default class PullRequestReviewsController extends React.Component { if (!comment.replyTo) { state[comment.id] = [comment]; } else { - // TODO: look at this more closely... - // When comment being replied to is outdated...?? Not 100% sure... - // Why would we even get an outdated comment or a response to one here? // Ran into this error when viewing files for https://github.com/numpy/numpy/pull/9998 // for comment MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE1MzA1NTUzMw, - // who's replyTo comment is an outdated comment + // who's replyTo comment does not exist. + // Not sure how we'd get into this state -- tried replying to outdated, + // hidden, deleted, and resolved comments but none of those conditions + // got us here. + // It may be that this only affects older pull requests, before something + // changed with oudated comment behavior. + // anyhow, do this check and move on with our lives. if (!state[comment.replyTo.id]) { state[comment.id] = [comment]; } else { From a8a5d6168d03fb091f977f3eff569c889613314b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 11 Jan 2019 14:55:03 -0500 Subject: [PATCH 2581/4847] Coverage for the Present state --- lib/models/repository-states/present.js | 10 +-- test/models/repository.test.js | 81 +++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index 830c18280e..8d93ffb7b8 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -610,9 +610,6 @@ export default class Present extends State { const bundle = await this.git().getStatusBundle(); const results = await this.formatChangedFiles(bundle); results.branch = bundle.branch; - if (!results.branch.aheadBehind) { - results.branch.aheadBehind = {ahead: null, behind: null}; - } return results; } catch (err) { if (err instanceof LargeRepoError) { @@ -855,7 +852,7 @@ export default class Present extends State { // Direct blob access getBlobContents(sha) { - return this.cache.getOrSet(Keys.blob(sha), () => { + return this.cache.getOrSet(Keys.blob.oneWith(sha), () => { return this.git().getBlobContents(sha); }); } @@ -876,6 +873,7 @@ export default class Present extends State { // Cache + /* istanbul ignore next */ getCache() { return this.cache; } @@ -974,6 +972,7 @@ class Cache { this.didUpdate(); } + /* istanbul ignore next */ [Symbol.iterator]() { return this.storage[Symbol.iterator](); } @@ -988,6 +987,7 @@ class Cache { this.emitter.emit('did-update'); } + /* istanbul ignore next */ onDidUpdate(callback) { return this.emitter.on('did-update', callback); } @@ -1025,6 +1025,7 @@ class CacheKey { } } + /* istanbul ignore next */ toString() { return `CacheKey(${this.primary})`; } @@ -1041,6 +1042,7 @@ class GroupKey { } } + /* istanbul ignore next */ toString() { return `GroupKey(${this.group})`; } diff --git a/test/models/repository.test.js b/test/models/repository.test.js index cfbf9df9b0..e802d8cdd8 100644 --- a/test/models/repository.test.js +++ b/test/models/repository.test.js @@ -7,6 +7,7 @@ import isEqualWith from 'lodash.isequalwith'; import Repository from '../../lib/models/repository'; import CompositeGitStrategy from '../../lib/composite-git-strategy'; +import {LargeRepoError} from '../../lib/git-shell-out-strategy'; import {nullCommit} from '../../lib/models/commit'; import {nullOperationStates} from '../../lib/models/operation-states'; import Author from '../../lib/models/author'; @@ -444,6 +445,60 @@ describe('Repository', function() { }); }); + describe('getStatusBundle', function() { + it('transitions to the TooLarge state and returns empty status when too large', async function() { + const workdir = await cloneRepository(); + const repository = new Repository(workdir); + await repository.getLoadPromise(); + + sinon.stub(repository.git, 'getStatusBundle').rejects(new LargeRepoError()); + + const result = await repository.getStatusBundle(); + + assert.isTrue(repository.isInState('TooLarge')); + assert.deepEqual(result.branch, {}); + assert.deepEqual(result.stagedFiles, {}); + assert.deepEqual(result.unstagedFiles, {}); + assert.deepEqual(result.mergeConflictFiles, {}); + }); + + it('propagates unrecognized git errors', async function() { + const workdir = await cloneRepository(); + const repository = new Repository(workdir); + await repository.getLoadPromise(); + + sinon.stub(repository.git, 'getStatusBundle').rejects(new Error('oh no')); + + await assert.isRejected(repository.getStatusBundle(), /oh no/); + }); + + it('post-processes renamed files to an addition and a deletion', async function() { + const workdir = await cloneRepository(); + const repository = new Repository(workdir); + await repository.getLoadPromise(); + + sinon.stub(repository.git, 'getStatusBundle').resolves({ + changedEntries: [], + untrackedEntries: [], + renamedEntries: [ + {stagedStatus: 'R', origFilePath: 'from0.txt', filePath: 'to0.txt'}, + {unstagedStatus: 'R', origFilePath: 'from1.txt', filePath: 'to1.txt'}, + {stagedStatus: 'C', filePath: 'c2.txt'}, + {unstagedStatus: 'C', filePath: 'c3.txt'}, + ], + unmergedEntries: [], + }); + + const result = await repository.getStatusBundle(); + assert.strictEqual(result.stagedFiles['from0.txt'], 'deleted'); + assert.strictEqual(result.stagedFiles['to0.txt'], 'added'); + assert.strictEqual(result.unstagedFiles['from1.txt'], 'deleted'); + assert.strictEqual(result.unstagedFiles['to1.txt'], 'added'); + assert.strictEqual(result.stagedFiles['c2.txt'], 'added'); + assert.strictEqual(result.unstagedFiles['c3.txt'], 'added'); + }); + }); + describe('getFilePatchForPath', function() { it('returns cached MultiFilePatch objects if they exist', async function() { const workingDirPath = await cloneRepository('multiple-commits'); @@ -931,6 +986,20 @@ describe('Repository', function() { }); }); + describe('unsetConfig', function() { + it('unsets a git config option', async function() { + const workingDirPath = await cloneRepository('three-files'); + const repository = new Repository(workingDirPath); + await repository.getLoadPromise(); + + await repository.setConfig('some.key', 'value'); + assert.strictEqual(await repository.getConfig('some.key'), 'value'); + + await repository.unsetConfig('some.key'); + assert.isNull(await repository.getConfig('some.key')); + }); + }); + describe('getCommitter', function() { it('returns user name and email if they exist', async function() { const workingDirPath = await cloneRepository('three-files'); @@ -1435,6 +1504,18 @@ describe('Repository', function() { }); }); + describe('getBlobContents(sha)', function() { + it('returns blob contents for sha', async function() { + const workingDirPath = await cloneRepository('three-files'); + const repository = new Repository(workingDirPath); + await repository.getLoadPromise(); + + const sha = await repository.createBlob({stdin: 'aa\nbb\ncc\n'}); + const contents = await repository.getBlobContents(sha); + assert.strictEqual(contents, 'aa\nbb\ncc\n'); + }); + }); + describe('discardWorkDirChangesForPaths()', function() { it('can discard working directory changes in modified files', async function() { const workingDirPath = await cloneRepository('three-files'); From 0838da6ce1332af8f9ca531e5b26a3b1e8f89bd8 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 11 Jan 2019 13:15:48 -0800 Subject: [PATCH 2582/4847] strip commented lines instead of using the verbatim flag --- lib/git-shell-out-strategy.js | 9 ++++++--- test/git-strategies.test.js | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 40cade6d87..df4b160685 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -506,12 +506,15 @@ export default class GitShellOutStrategy { msg = rawMessage; } - // if commit template is used, that will not play nicely with `verbatim` - // because we want to strip commented lines from templates. + // if commit template is used, strip commented lines from commit + // to be consistent with command line git. const template = await this.fetchCommitMessageTemplate(); + if (template) { + msg = msg.split('\n').filter(line => !line.startsWith('#')).join('\n'); + } // Determine the cleanup mode. - if (verbatim && !template) { + if (verbatim) { args.push('--cleanup=verbatim'); } else { const configured = await this.getConfig('commit.cleanup'); diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 9d9583b481..c1634d6bf1 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -1036,7 +1036,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; 'and things', ].join('\n')); }); - it('ignores verbatim flag if commit template is used', async function() { + it('strips commented lines if commit template is used', async function() { const workingDirPath = await cloneRepository('three-files'); const git = createTestStrategy(workingDirPath); const templateText = '# this line should be stripped'; From 3cde57a89051170d831f56c948561ef6f37e5f73 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 11 Jan 2019 15:19:13 -0800 Subject: [PATCH 2583/4847] fix GPG signing tests --- test/git-strategies.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index c1634d6bf1..f5e6dcf894 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -1186,6 +1186,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; beforeEach(async function() { const workingDirPath = await cloneRepository('multiple-commits'); git = createTestStrategy(workingDirPath); + sinon.stub(git, 'fetchCommitMessageTemplate').returns(null); }); const operations = [ From 85e502ea53bc8238cce04647ac91fe3904f904bb Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 11 Jan 2019 16:32:10 -0800 Subject: [PATCH 2584/4847] fetch commit author name from git --- lib/git-shell-out-strategy.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index d8ad54d16a..5f6a1d9ce8 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -700,12 +700,13 @@ export default class GitShellOutStrategy { // %x00 - null byte // %H - commit SHA // %ae - author email + // %an = author full name // %at - timestamp, UNIX timestamp // %s - subject // %b - body const args = [ 'log', - '--pretty=format:%H%x00%ae%x00%at%x00%s%x00%b%x00', + '--pretty=format:%H%x00%ae%x00%an%x00%at%x00%s%x00%b%x00', '--no-abbrev-commit', '--no-prefix', '--no-ext-diff', @@ -733,13 +734,14 @@ export default class GitShellOutStrategy { } const fields = output.trim().split('\0'); + console.log('fields', fields) const commits = []; - for (let i = 0; i < fields.length; i += 6) { - const body = fields[i + 4].trim(); + for (let i = 0; i < fields.length; i += 7) { + const body = fields[i + 5].trim(); let patch = []; if (includePatch) { - const diffs = fields[i + 5]; + const diffs = fields[i + 6]; patch = parseDiff(diffs.trim()); } @@ -748,8 +750,9 @@ export default class GitShellOutStrategy { commits.push({ sha: fields[i] && fields[i].trim(), authorEmail: fields[i + 1] && fields[i + 1].trim(), - authorDate: parseInt(fields[i + 2], 10), - messageSubject: fields[i + 3], + authorName: fields[i + 2] && fields[i + 2].trim(), + authorDate: parseInt(fields[i + 3], 10), + messageSubject: fields[i + 4], messageBody, coAuthors, unbornRef: false, From da316e835017855f415ad701c457a3920135bb66 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 11 Jan 2019 16:32:37 -0800 Subject: [PATCH 2585/4847] render author name in `CommitDetailView` --- lib/views/commit-detail-view.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index 304efe8672..d0fc77b578 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -56,6 +56,7 @@ export default class CommitDetailView extends React.Component {

    {emojify(commit.getMessageSubject())}

    +
    {this.props.commit.authorName}
    {this.renderAuthors()} From b30ca92e57081d5c7e9b09b15e91f540f3ef3f25 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 11 Jan 2019 16:33:38 -0800 Subject: [PATCH 2586/4847] models and builders, oh my! --- lib/models/commit.js | 7 ++++++- test/builder/commit.js | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/models/commit.js b/lib/models/commit.js index 281d909367..b0edb038d8 100644 --- a/lib/models/commit.js +++ b/lib/models/commit.js @@ -16,9 +16,10 @@ export default class Commit { return new Commit({unbornRef: UNBORN}); } - constructor({sha, authorEmail, coAuthors, authorDate, messageSubject, messageBody, unbornRef, patch}) { + constructor({sha, authorEmail, authorName, coAuthors, authorDate, messageSubject, messageBody, unbornRef, patch}) { this.sha = sha; this.authorEmail = authorEmail; + this.authorName = authorName; this.coAuthors = coAuthors || []; this.authorDate = authorDate; this.messageSubject = messageSubject; @@ -36,6 +37,10 @@ export default class Commit { return this.authorEmail; } + getAuthorName() { + return this.authorName; + } + getAuthorDate() { return this.authorDate; } diff --git a/test/builder/commit.js b/test/builder/commit.js index d9dd960bb7..aaf0b78093 100644 --- a/test/builder/commit.js +++ b/test/builder/commit.js @@ -7,6 +7,7 @@ class CommitBuilder { constructor() { this._sha = '0123456789abcdefghij0123456789abcdefghij'; this._authorEmail = 'default@email.com'; + this._authorName = 'Tilde Ann Thurium' this._authorDate = moment('2018-11-28T12:00:00', moment.ISO_8601).unix(); this._coAuthors = []; this._messageSubject = 'subject'; @@ -25,6 +26,11 @@ class CommitBuilder { return this; } + authorName(newName) { + this._authorName = newName; + return this; + } + authorDate(timestamp) { this._authorDate = timestamp; return this; @@ -56,6 +62,7 @@ class CommitBuilder { const commit = new Commit({ sha: this._sha, authorEmail: this._authorEmail, + authorName: thus._authorName, authorDate: this._authorDate, coAuthors: this._coAuthors, messageSubject: this._messageSubject, From c27ec98a6da1e8ec947fcb976231b3130e7d17bf Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 11 Jan 2019 16:36:12 -0800 Subject: [PATCH 2587/4847] :shirt: --- lib/git-shell-out-strategy.js | 1 - test/builder/commit.js | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 5f6a1d9ce8..4f18e1b5fa 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -734,7 +734,6 @@ export default class GitShellOutStrategy { } const fields = output.trim().split('\0'); - console.log('fields', fields) const commits = []; for (let i = 0; i < fields.length; i += 7) { diff --git a/test/builder/commit.js b/test/builder/commit.js index aaf0b78093..43898bf6fc 100644 --- a/test/builder/commit.js +++ b/test/builder/commit.js @@ -7,7 +7,7 @@ class CommitBuilder { constructor() { this._sha = '0123456789abcdefghij0123456789abcdefghij'; this._authorEmail = 'default@email.com'; - this._authorName = 'Tilde Ann Thurium' + this._authorName = 'Tilde Ann Thurium'; this._authorDate = moment('2018-11-28T12:00:00', moment.ISO_8601).unix(); this._coAuthors = []; this._messageSubject = 'subject'; @@ -62,7 +62,7 @@ class CommitBuilder { const commit = new Commit({ sha: this._sha, authorEmail: this._authorEmail, - authorName: thus._authorName, + authorName: this._authorName, authorDate: this._authorDate, coAuthors: this._coAuthors, messageSubject: this._messageSubject, From e0a49666ed74287e273e4c153ac7710d0eb00c28 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 11 Jan 2019 16:55:37 -0800 Subject: [PATCH 2588/4847] fix git-strategies tests --- test/git-strategies.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 6dbd031fdf..0d65c7c993 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -188,6 +188,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; assert.deepEqual(commits[0], { sha: '90b17a8e3fa0218f42afc1dd24c9003e285f4a82', authorEmail: 'kuychaco@github.com', + authorName: 'Katrina Uychaco', authorDate: 1471113656, messageSubject: 'third commit', messageBody: '', @@ -198,6 +199,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; assert.deepEqual(commits[1], { sha: '18920c900bfa6e4844853e7e246607a31c3e2e8c', authorEmail: 'kuychaco@github.com', + authorName: 'Katrina Uychaco', authorDate: 1471113642, messageSubject: 'second commit', messageBody: '', @@ -208,6 +210,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; assert.deepEqual(commits[2], { sha: '46c0d7179fc4e348c3340ff5e7957b9c7d89c07f', authorEmail: 'kuychaco@github.com', + authorName: 'Katrina Uychaco', authorDate: 1471113625, messageSubject: 'first commit', messageBody: '', From a8bea5f424eb82f0bd8337c95ede19c8adc8a75e Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 14 Jan 2019 19:45:59 +0100 Subject: [PATCH 2589/4847] when diff is decided to be "too large", we skip hunk building and return a placeholder filepatch. --- lib/models/patch/builder.js | 32 +++++++++++++++++++++++++++++--- lib/models/patch/file-patch.js | 5 +++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index e8e18982a7..511d15c5a6 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -10,6 +10,8 @@ import MultiFilePatch from './multi-file-patch'; export function buildFilePatch(diffs) { const layeredBuffer = initializeBuffer(); + isDiffLarge(diffs); + let filePatch; if (diffs.length === 0) { filePatch = emptyDiffFilePatch(); @@ -80,8 +82,6 @@ function singleDiffFilePatch(diff, layeredBuffer) { const wasSymlink = diff.oldMode === File.modes.SYMLINK; const isSymlink = diff.newMode === File.modes.SYMLINK; - const [hunks, patchMarker] = buildHunks(diff, layeredBuffer); - let oldSymlink = null; let newSymlink = null; if (wasSymlink && !isSymlink) { @@ -99,6 +99,12 @@ function singleDiffFilePatch(diff, layeredBuffer) { const newFile = diff.newPath !== null || diff.newMode !== null ? new File({path: diff.newPath, mode: diff.newMode, symlink: newSymlink}) : nullFile; + + if (isDiffLarge([diff])) { + return FilePatch.createPlaceholder(oldFile, newFile); + } + + const [hunks, patchMarker] = buildHunks(diff, layeredBuffer); const patch = new Patch({status: diff.status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); return new FilePatch(oldFile, newFile, patch); @@ -114,7 +120,6 @@ function dualDiffFilePatch(diff1, diff2, layeredBuffer) { contentChangeDiff = diff1; } - const [hunks, patchMarker] = buildHunks(contentChangeDiff, layeredBuffer); const filePath = contentChangeDiff.oldPath || contentChangeDiff.newPath; const symlink = modeChangeDiff.hunks[0].lines[0].slice(1); @@ -140,6 +145,12 @@ function dualDiffFilePatch(diff1, diff2, layeredBuffer) { const oldFile = new File({path: filePath, mode: oldMode, symlink: oldSymlink}); const newFile = new File({path: filePath, mode: newMode, symlink: newSymlink}); + + if (isDiffLarge([diff1, diff2])) { + return FilePatch.createPlaceholder(oldFile, newFile); + } + + const [hunks, patchMarker] = buildHunks(contentChangeDiff, layeredBuffer); const patch = new Patch({status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); return new FilePatch(oldFile, newFile, patch); @@ -252,3 +263,18 @@ function buildHunks(diff, {buffer, layers}) { return [hunks, patchMarker]; } + +function isDiffLarge(diffs) { + const DIFF_BYTE_THRESHOLD = 32768; + + const size = diffs.reduce((diffSizeCounter, diff) => { + return diffSizeCounter + diff.hunks.reduce((hunkSizeCounter, hunk) => { + return hunkSizeCounter + hunk.lines.reduce((lineSizeCounter, line) => { + return lineSizeCounter + Buffer.byteLength(line, 'utf8'); + }, 0); + }, 0); + }, 0); + + console.log(diffs, `size: ${size}`); + return size > DIFF_BYTE_THRESHOLD; +} diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index c40bd48dd3..9d3c0c3ce9 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -7,6 +7,11 @@ export default class FilePatch { return new this(nullFile, nullFile, Patch.createNull()); } + // TODO: explain what this is for + static createPlaceholder(oldFile, newFile) { + return new this(oldFile, newFile, Patch.createNull()); + } + constructor(oldFile, newFile, patch) { this.oldFile = oldFile; this.newFile = newFile; From e2862ea0515ae40c361fb466b2401006b370d77a Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 14 Jan 2019 20:49:00 +0100 Subject: [PATCH 2590/4847] visually display the diff gate --- lib/models/patch/builder.js | 2 -- lib/models/patch/file-patch.js | 5 +++++ lib/views/multi-file-patch-view.js | 13 +++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 511d15c5a6..b34ae9c3cd 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -10,8 +10,6 @@ import MultiFilePatch from './multi-file-patch'; export function buildFilePatch(diffs) { const layeredBuffer = initializeBuffer(); - isDiffLarge(diffs); - let filePatch; if (diffs.length === 0) { filePatch = emptyDiffFilePatch(); diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index 9d3c0c3ce9..b70fbfc3f2 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -22,6 +22,11 @@ export default class FilePatch { return this.oldFile.isPresent() || this.newFile.isPresent() || this.patch.isPresent(); } + isLarge() { + // TODO: fix this + return (this.oldFile.isPresent() || this.newFile.isPresent()) && !this.patch.isPresent(); + } + getOldFile() { return this.oldFile; } diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 9d0655b770..a8c50824ec 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -353,11 +353,24 @@ export default class MultiFilePatchView extends React.Component { + {filePatch.isLarge() && this.renderDiffGate(filePatch)} + {this.renderHunkHeaders(filePatch)} ); } + renderDiffGate(filePatch) { + // TODO: startRange is incorrect here + return ( + + +

    Diff is too large to be displayed.

    +
    +
    + ); + } + renderExecutableModeChangeMeta(filePatch) { if (!filePatch.didChangeExecutableMode()) { return null; From 44f48c5b92140b72aaff8e17624e955df420c91b Mon Sep 17 00:00:00 2001 From: annthurium Date: Mon, 14 Jan 2019 13:09:52 -0800 Subject: [PATCH 2591/4847] test for authorName on commit model --- lib/models/commit.js | 3 ++- test/models/commit.test.js | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/models/commit.js b/lib/models/commit.js index b0edb038d8..81d681d14b 100644 --- a/lib/models/commit.js +++ b/lib/models/commit.js @@ -149,7 +149,8 @@ export default class Commit { isEqual(other) { // Directly comparable properties - for (const property of ['sha', 'authorEmail', 'authorDate', 'messageSubject', 'messageBody', 'unbornRef']) { + const properties = ['sha', 'authorEmail', 'authorDate', 'messageSubject', 'messageBody', 'unbornRef', 'authorName']; + for (const property of properties) { if (this[property] !== other[property]) { return false; } diff --git a/test/models/commit.test.js b/test/models/commit.test.js index 778b89884f..eba27394aa 100644 --- a/test/models/commit.test.js +++ b/test/models/commit.test.js @@ -178,6 +178,13 @@ describe('Commit', function() { assert.isFalse(a.isEqual(b)); }); + it('returns false if author differs', function() { + const a = commitBuilder().authorName('Tilde Ann Thurium').build(); + + const b = commitBuilder().authorName('Vanessa Yuen').build(); + assert.isFalse(a.isEqual(b)); + }); + it('returns false if a co-author differs', function() { const a = commitBuilder().addCoAuthor('me', 'me@email.com').build(); From ba37d1ae3a725359239afb83e2ef3f170a38b23a Mon Sep 17 00:00:00 2001 From: annthurium Date: Mon, 14 Jan 2019 13:37:10 -0800 Subject: [PATCH 2592/4847] add test for authorName in CommitDetailView --- lib/views/commit-detail-view.js | 2 +- test/views/commit-detail-view.test.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index d0fc77b578..aae2457461 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -56,7 +56,7 @@ export default class CommitDetailView extends React.Component {

    {emojify(commit.getMessageSubject())}

    -
    {this.props.commit.authorName}
    +
    {this.props.commit.authorName}
    {this.renderAuthors()} diff --git a/test/views/commit-detail-view.test.js b/test/views/commit-detail-view.test.js index 29434b3135..19d619cb8a 100644 --- a/test/views/commit-detail-view.test.js +++ b/test/views/commit-detail-view.test.js @@ -62,6 +62,7 @@ describe('CommitDetailView', function() { const commit = commitBuilder() .sha('420') .authorEmail('very@nice.com') + .authorName('Forthe Win') .authorDate(moment().subtract(2, 'days').unix()) .messageSubject('subject') .messageBody('body') @@ -69,6 +70,7 @@ describe('CommitDetailView', function() { .build(); const wrapper = shallow(buildApp({commit})); + assert.strictEqual(wrapper.find('.github-CommitDetailView-authorName').text(), 'Forthe Win'); assert.strictEqual(wrapper.find('.github-CommitDetailView-title').text(), 'subject'); assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), 'body'); assert.strictEqual(wrapper.find('.github-CommitDetailView-metaText').text(), 'very@nice.com committed 2 days ago'); From c34440f126ee15938f0448f6b41d5a249cb0c3b1 Mon Sep 17 00:00:00 2001 From: annthurium Date: Mon, 14 Jan 2019 13:50:44 -0800 Subject: [PATCH 2593/4847] fix unrelated commented out assertion --- test/views/commit-detail-view.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/views/commit-detail-view.test.js b/test/views/commit-detail-view.test.js index 19d619cb8a..4ea5988430 100644 --- a/test/views/commit-detail-view.test.js +++ b/test/views/commit-detail-view.test.js @@ -75,7 +75,7 @@ describe('CommitDetailView', function() { assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), 'body'); assert.strictEqual(wrapper.find('.github-CommitDetailView-metaText').text(), 'very@nice.com committed 2 days ago'); assert.strictEqual(wrapper.find('.github-CommitDetailView-sha').text(), '420'); - // assert.strictEqual(wrapper.find('.github-CommitDetailView-sha a').prop('href'), '420'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-sha a').prop('href'), 'https://github.com/atom/github/commit/420'); assert.strictEqual( wrapper.find('img.github-RecentCommit-avatar').prop('src'), 'https://avatars.githubusercontent.com/u/e?email=very%40nice.com&s=32', From e217687cc859f6c3ba8b172e69b5f0e30c7f2663 Mon Sep 17 00:00:00 2001 From: annthurium Date: Mon, 14 Jan 2019 14:40:52 -0800 Subject: [PATCH 2594/4847] add test for getter to make codecov happy --- test/models/commit.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/models/commit.test.js b/test/models/commit.test.js index eba27394aa..1e1fc305bf 100644 --- a/test/models/commit.test.js +++ b/test/models/commit.test.js @@ -146,6 +146,12 @@ describe('Commit', function() { }); }); + it('returns the author name', function() { + const authorName = 'Tilde Ann Thurium'; + const commit = commitBuilder().authorName(authorName).build(); + assert.strictEqual(commit.getAuthorName(), authorName) + }); + describe('isEqual()', function() { it('returns true when commits are identical', function() { const a = commitBuilder() From 35948ae6ad23bd1b56473a274096e393bfa08f23 Mon Sep 17 00:00:00 2001 From: annthurium Date: Mon, 14 Jan 2019 15:38:14 -0800 Subject: [PATCH 2595/4847] :shirt: --- test/models/commit.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/models/commit.test.js b/test/models/commit.test.js index 1e1fc305bf..d4c540b1e5 100644 --- a/test/models/commit.test.js +++ b/test/models/commit.test.js @@ -147,9 +147,9 @@ describe('Commit', function() { }); it('returns the author name', function() { - const authorName = 'Tilde Ann Thurium'; - const commit = commitBuilder().authorName(authorName).build(); - assert.strictEqual(commit.getAuthorName(), authorName) + const authorName = 'Tilde Ann Thurium'; + const commit = commitBuilder().authorName(authorName).build(); + assert.strictEqual(commit.getAuthorName(), authorName); }); describe('isEqual()', function() { From 63c5f99d895a5f98d789d444d21f411d62dc444f Mon Sep 17 00:00:00 2001 From: annthurium Date: Tue, 15 Jan 2019 13:28:54 -0800 Subject: [PATCH 2596/4847] show name instead of email address --- lib/views/commit-detail-view.js | 7 +++---- test/views/commit-detail-view.test.js | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index aae2457461..7f8975c339 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -56,7 +56,6 @@ export default class CommitDetailView extends React.Component {

    {emojify(commit.getMessageSubject())}

    -
    {this.props.commit.authorName}
    {this.renderAuthors()} @@ -132,11 +131,11 @@ export default class CommitDetailView extends React.Component { const commit = this.props.commit; const coAuthorCount = commit.getCoAuthors().length; if (coAuthorCount === 0) { - return commit.getAuthorEmail(); + return commit.getAuthorName(); } else if (coAuthorCount === 1) { - return `${commit.getAuthorEmail()} and ${commit.getCoAuthors()[0].email}`; + return `${commit.getAuthorName()} and ${commit.getCoAuthors()[0].name}`; } else { - return `${commit.getAuthorEmail()} and ${coAuthorCount} others`; + return `${commit.getAuthorName()} and ${coAuthorCount} others`; } } diff --git a/test/views/commit-detail-view.test.js b/test/views/commit-detail-view.test.js index 4ea5988430..4264576bc9 100644 --- a/test/views/commit-detail-view.test.js +++ b/test/views/commit-detail-view.test.js @@ -10,7 +10,7 @@ import Remote, {nullRemote} from '../../lib/models/remote'; import {cloneRepository, buildRepository} from '../helpers'; import {commitBuilder} from '../builder/commit'; -describe('CommitDetailView', function() { +describe.only('CommitDetailView', function() { let repository, atomEnv; beforeEach(async function() { @@ -70,10 +70,9 @@ describe('CommitDetailView', function() { .build(); const wrapper = shallow(buildApp({commit})); - assert.strictEqual(wrapper.find('.github-CommitDetailView-authorName').text(), 'Forthe Win'); assert.strictEqual(wrapper.find('.github-CommitDetailView-title').text(), 'subject'); assert.strictEqual(wrapper.find('.github-CommitDetailView-moreText').text(), 'body'); - assert.strictEqual(wrapper.find('.github-CommitDetailView-metaText').text(), 'very@nice.com committed 2 days ago'); + assert.strictEqual(wrapper.find('.github-CommitDetailView-metaText').text(), 'Forthe Win committed 2 days ago'); assert.strictEqual(wrapper.find('.github-CommitDetailView-sha').text(), '420'); assert.strictEqual(wrapper.find('.github-CommitDetailView-sha a').prop('href'), 'https://github.com/atom/github/commit/420'); assert.strictEqual( @@ -162,33 +161,34 @@ describe('CommitDetailView', function() { describe('when there are no co-authors', function() { it('returns only the author', function() { const commit = commitBuilder() - .authorEmail('blaze@it.com') + .authorName('Steven Universe') + .authorEmail('steven@universe.com') .build(); const wrapper = shallow(buildApp({commit})); - assert.strictEqual(wrapper.instance().getAuthorInfo(), 'blaze@it.com'); + assert.strictEqual(wrapper.instance().getAuthorInfo(), 'Steven Universe'); }); }); describe('when there is one co-author', function() { it('returns author and the co-author', function() { const commit = commitBuilder() - .authorEmail('blaze@it.com') - .addCoAuthor('two', 'two@coauthor.com') + .authorName('Ruby') + .addCoAuthor('Sapphire', 'sapphire@thecrystalgems.party') .build(); const wrapper = shallow(buildApp({commit})); - assert.strictEqual(wrapper.instance().getAuthorInfo(), 'blaze@it.com and two@coauthor.com'); + assert.strictEqual(wrapper.instance().getAuthorInfo(), 'Ruby and Sapphire'); }); }); describe('when there is more than one co-author', function() { it('returns the author and number of co-authors', function() { const commit = commitBuilder() - .authorEmail('blaze@it.com') - .addCoAuthor('two', 'two@coauthor.com') - .addCoAuthor('three', 'three@coauthor.com') + .authorName('Amethyst') + .addCoAuthor('Peridot', 'peri@youclods.horse') + .addCoAuthor('Pearl', 'p@pinkhair.club') .build(); const wrapper = shallow(buildApp({commit})); - assert.strictEqual(wrapper.instance().getAuthorInfo(), 'blaze@it.com and 2 others'); + assert.strictEqual(wrapper.instance().getAuthorInfo(), 'Amethyst and 2 others'); }); }); }); From eff754a9eb74ae85ee590079e5ef5cf4084602a8 Mon Sep 17 00:00:00 2001 From: annthurium Date: Tue, 15 Jan 2019 13:29:25 -0800 Subject: [PATCH 2597/4847] :shirt: againnn --- lib/views/commit-detail-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/commit-detail-view.js b/lib/views/commit-detail-view.js index 7f8975c339..eada68313f 100644 --- a/lib/views/commit-detail-view.js +++ b/lib/views/commit-detail-view.js @@ -131,7 +131,7 @@ export default class CommitDetailView extends React.Component { const commit = this.props.commit; const coAuthorCount = commit.getCoAuthors().length; if (coAuthorCount === 0) { - return commit.getAuthorName(); + return commit.getAuthorName(); } else if (coAuthorCount === 1) { return `${commit.getAuthorName()} and ${commit.getCoAuthors()[0].name}`; } else { From 1c82c2f84251330bd7c710193ac02fd78589b92d Mon Sep 17 00:00:00 2001 From: annthurium Date: Tue, 15 Jan 2019 13:39:40 -0800 Subject: [PATCH 2598/4847] :fire: .only --- test/views/commit-detail-view.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/views/commit-detail-view.test.js b/test/views/commit-detail-view.test.js index 4264576bc9..ca5166333b 100644 --- a/test/views/commit-detail-view.test.js +++ b/test/views/commit-detail-view.test.js @@ -10,7 +10,7 @@ import Remote, {nullRemote} from '../../lib/models/remote'; import {cloneRepository, buildRepository} from '../helpers'; import {commitBuilder} from '../builder/commit'; -describe.only('CommitDetailView', function() { +describe('CommitDetailView', function() { let repository, atomEnv; beforeEach(async function() { From 825e36e216c1658c8e724cddfe01313fdfc767d3 Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 16 Jan 2019 11:43:25 +0900 Subject: [PATCH 2599/4847] Add a bit more space for multiple avatars --- styles/commit-detail.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styles/commit-detail.less b/styles/commit-detail.less index 9f9bcc4762..dc1b9b84f3 100644 --- a/styles/commit-detail.less +++ b/styles/commit-detail.less @@ -41,7 +41,7 @@ &-metaText { flex: 1; - margin-left: @avatar-dimensions * 1.3; // leave some space for the avatars + margin-left: @avatar-dimensions * 1.4; // leave some space for the avatars line-height: @avatar-dimensions; color: @text-color-subtle; } From a9db48f084e1c4c65cebc7288f61ae90f1101aef Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 16 Jan 2019 14:20:30 +0100 Subject: [PATCH 2600/4847] experimenting wiht a DelayedPatch but idk --- lib/models/patch/builder.js | 14 ++++++++++---- lib/models/patch/file-patch.js | 5 ++--- lib/models/patch/patch.js | 22 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index b34ae9c3cd..4a8679bb76 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -1,4 +1,4 @@ -import {TextBuffer} from 'atom'; +import {TextBuffer, Point} from 'atom'; import Hunk from './hunk'; import File, {nullFile} from './file'; @@ -99,7 +99,12 @@ function singleDiffFilePatch(diff, layeredBuffer) { : nullFile; if (isDiffLarge([diff])) { - return FilePatch.createPlaceholder(oldFile, newFile); + const delayed = FilePatch.createDelayedFilePatch( + oldFile, newFile, diff, + new Point(layeredBuffer.buffer.getLastRow(), 0), + ); + console.log(delayed.getPatch()); + return delayed; } const [hunks, patchMarker] = buildHunks(diff, layeredBuffer); @@ -145,7 +150,7 @@ function dualDiffFilePatch(diff1, diff2, layeredBuffer) { const newFile = new File({path: filePath, mode: newMode, symlink: newSymlink}); if (isDiffLarge([diff1, diff2])) { - return FilePatch.createPlaceholder(oldFile, newFile); + // TODO: do something with large diff too } const [hunks, patchMarker] = buildHunks(contentChangeDiff, layeredBuffer); @@ -263,7 +268,8 @@ function buildHunks(diff, {buffer, layers}) { } function isDiffLarge(diffs) { - const DIFF_BYTE_THRESHOLD = 32768; + // TODO: fixme + const DIFF_BYTE_THRESHOLD = 500; const size = diffs.reduce((diffSizeCounter, diff) => { return diffSizeCounter + diff.hunks.reduce((hunkSizeCounter, hunk) => { diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index b70fbfc3f2..4882c2760f 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -7,9 +7,8 @@ export default class FilePatch { return new this(nullFile, nullFile, Patch.createNull()); } - // TODO: explain what this is for - static createPlaceholder(oldFile, newFile) { - return new this(oldFile, newFile, Patch.createNull()); + static createDelayedFilePatch(oldFile, newFile, diff, insertPoint) { + return new this(oldFile, newFile, Patch.createDelayedPatch(diff, insertPoint)); } constructor(oldFile, newFile, patch) { diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index 0fdafa0011..57bd975dad 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -8,6 +8,10 @@ export default class Patch { return new NullPatch(); } + static createDelayedPatch(diff, insertPoint) { + return new DelayedPatch(diff, insertPoint); + } + constructor({status, hunks, marker}) { this.status = status; this.hunks = hunks; @@ -346,6 +350,24 @@ class NullPatch { } } +// TODO: it prob shouldn't extend NullPatch +class DelayedPatch extends NullPatch { + // should know: + // where to insert + // what the diff is + // reason it's delayed (???) + constructor(diff, insertPoint) { + super(); + this.insertPoint = insertPoint; + this.diff = diff; + } + + getStartRange() { + return new Range(this.insertPoint, this.insertPoint); + } + +} + class BufferBuilder { constructor(original, originalBaseOffset, nextLayeredBuffer) { this.originalBuffer = original; From f621d491fbbf67e53db0b29e7e6d643ec5343a30 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 09:54:07 -0500 Subject: [PATCH 2601/4847] Delayed patch parsing Co-Authored-By: Vanessa Yuen --- lib/models/patch/builder.js | 63 +++++++++++++--------- lib/models/patch/file-patch.js | 13 +++-- lib/models/patch/patch.js | 38 +++++++++++--- test/models/patch/builder.test.js | 86 +++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 36 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 4a8679bb76..30adefe7f2 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -2,21 +2,29 @@ import {TextBuffer, Point} from 'atom'; import Hunk from './hunk'; import File, {nullFile} from './file'; -import Patch from './patch'; +import Patch, {TOO_LARGE} from './patch'; import {Unchanged, Addition, Deletion, NoNewline} from './region'; import FilePatch from './file-patch'; import MultiFilePatch from './multi-file-patch'; -export function buildFilePatch(diffs) { +// TODO: fixme +const DEFAULT_LARGE_DIFF_THRESHOLD = 500; + +export function buildFilePatch(diffs, options) { + const opts = { + largeDiffThreshold: DEFAULT_LARGE_DIFF_THRESHOLD, + ...options, + }; + const layeredBuffer = initializeBuffer(); let filePatch; if (diffs.length === 0) { filePatch = emptyDiffFilePatch(); } else if (diffs.length === 1) { - filePatch = singleDiffFilePatch(diffs[0], layeredBuffer); + filePatch = singleDiffFilePatch(diffs[0], layeredBuffer, opts); } else if (diffs.length === 2) { - filePatch = dualDiffFilePatch(diffs[0], diffs[1], layeredBuffer); + filePatch = dualDiffFilePatch(diffs[0], diffs[1], layeredBuffer, opts); } else { throw new Error(`Unexpected number of diffs: ${diffs.length}`); } @@ -24,7 +32,12 @@ export function buildFilePatch(diffs) { return new MultiFilePatch({filePatches: [filePatch], ...layeredBuffer}); } -export function buildMultiFilePatch(diffs) { +export function buildMultiFilePatch(diffs, options) { + const opts = { + largeDiffThreshold: DEFAULT_LARGE_DIFF_THRESHOLD, + ...options, + }; + const layeredBuffer = initializeBuffer(); const byPath = new Map(); const actions = []; @@ -40,7 +53,7 @@ export function buildMultiFilePatch(diffs) { if (otherHalf) { // The second half. Complete the paired diff, or fail if they have unexpected statuses or modes. const [otherDiff, otherIndex] = otherHalf; - actions[otherIndex] = () => dualDiffFilePatch(diff, otherDiff, layeredBuffer); + actions[otherIndex] = () => dualDiffFilePatch(diff, otherDiff, layeredBuffer, opts); byPath.delete(thePath); } else { // The first half we've seen. @@ -48,7 +61,7 @@ export function buildMultiFilePatch(diffs) { index++; } } else { - actions[index] = () => singleDiffFilePatch(diff, layeredBuffer); + actions[index] = () => singleDiffFilePatch(diff, layeredBuffer, opts); index++; } } @@ -76,7 +89,7 @@ function emptyDiffFilePatch() { return FilePatch.createNull(); } -function singleDiffFilePatch(diff, layeredBuffer) { +function singleDiffFilePatch(diff, layeredBuffer, opts) { const wasSymlink = diff.oldMode === File.modes.SYMLINK; const isSymlink = diff.newMode === File.modes.SYMLINK; @@ -98,22 +111,27 @@ function singleDiffFilePatch(diff, layeredBuffer) { ? new File({path: diff.newPath, mode: diff.newMode, symlink: newSymlink}) : nullFile; - if (isDiffLarge([diff])) { + if (isDiffLarge([diff], opts)) { + const insertPoint = new Point(layeredBuffer.buffer.getLastRow(), 0); const delayed = FilePatch.createDelayedFilePatch( - oldFile, newFile, diff, - new Point(layeredBuffer.buffer.getLastRow(), 0), + oldFile, newFile, insertPoint, + TOO_LARGE, + () => { + const [hunks, patchMarker] = buildHunks(diff, layeredBuffer, insertPoint.row); + return new Patch({status: diff.status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); + }, ); console.log(delayed.getPatch()); return delayed; } - const [hunks, patchMarker] = buildHunks(diff, layeredBuffer); + const [hunks, patchMarker] = buildHunks(diff, layeredBuffer, layeredBuffer.buffer.getLastRow()); const patch = new Patch({status: diff.status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); return new FilePatch(oldFile, newFile, patch); } -function dualDiffFilePatch(diff1, diff2, layeredBuffer) { +function dualDiffFilePatch(diff1, diff2, layeredBuffer, opts) { let modeChangeDiff, contentChangeDiff; if (diff1.oldMode === File.modes.SYMLINK || diff1.newMode === File.modes.SYMLINK) { modeChangeDiff = diff1; @@ -153,7 +171,7 @@ function dualDiffFilePatch(diff1, diff2, layeredBuffer) { // TODO: do something with large diff too } - const [hunks, patchMarker] = buildHunks(contentChangeDiff, layeredBuffer); + const [hunks, patchMarker] = buildHunks(contentChangeDiff, layeredBuffer, layeredBuffer.buffer.getLastRow()); const patch = new Patch({status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); return new FilePatch(oldFile, newFile, patch); @@ -178,7 +196,7 @@ function initializeBuffer() { return {buffer, layers}; } -function buildHunks(diff, {buffer, layers}) { +function buildHunks(diff, {buffer, layers}, insertRow) { const layersByKind = new Map([ [Unchanged, layers.unchanged], [Addition, layers.addition], @@ -187,7 +205,7 @@ function buildHunks(diff, {buffer, layers}) { ]); const hunks = []; - const patchStartRow = buffer.getLastRow(); + const patchStartRow = insertRow; let bufferRow = patchStartRow; let nextLineLength = 0; @@ -228,7 +246,7 @@ function buildHunks(diff, {buffer, layers}) { for (const lineText of hunkData.lines) { const bufferLine = lineText.slice(1) + '\n'; nextLineLength = lineText.length - 1; - buffer.append(bufferLine); + buffer.insert([bufferRow, 0], bufferLine); const ChangeKind = CHANGEKIND[lineText[0]]; if (ChangeKind === undefined) { @@ -267,18 +285,13 @@ function buildHunks(diff, {buffer, layers}) { return [hunks, patchMarker]; } -function isDiffLarge(diffs) { - // TODO: fixme - const DIFF_BYTE_THRESHOLD = 500; - +function isDiffLarge(diffs, opts) { const size = diffs.reduce((diffSizeCounter, diff) => { return diffSizeCounter + diff.hunks.reduce((hunkSizeCounter, hunk) => { - return hunkSizeCounter + hunk.lines.reduce((lineSizeCounter, line) => { - return lineSizeCounter + Buffer.byteLength(line, 'utf8'); - }, 0); + return hunkSizeCounter + hunk.lines.length; }, 0); }, 0); console.log(diffs, `size: ${size}`); - return size > DIFF_BYTE_THRESHOLD; + return size > opts.largeDiffThreshold; } diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index 4882c2760f..868ce03753 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -7,8 +7,8 @@ export default class FilePatch { return new this(nullFile, nullFile, Patch.createNull()); } - static createDelayedFilePatch(oldFile, newFile, diff, insertPoint) { - return new this(oldFile, newFile, Patch.createDelayedPatch(diff, insertPoint)); + static createDelayedFilePatch(oldFile, newFile, position, renderStatus, parseFn) { + return new this(oldFile, newFile, Patch.createDelayedPatch(position, renderStatus, parseFn)); } constructor(oldFile, newFile, patch) { @@ -21,9 +21,8 @@ export default class FilePatch { return this.oldFile.isPresent() || this.newFile.isPresent() || this.patch.isPresent(); } - isLarge() { - // TODO: fix this - return (this.oldFile.isPresent() || this.newFile.isPresent()) && !this.patch.isPresent(); + getRenderStatus() { + return this.patch.getRenderStatus(); } getOldFile() { @@ -116,6 +115,10 @@ export default class FilePatch { return this.getPatch().getHunks(); } + triggerDelayedRender() { + this.patch = this.patch.parseFn(); + } + clone(opts = {}) { return new this.constructor( opts.oldFile !== undefined ? opts.oldFile : this.oldFile, diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index 57bd975dad..bfe2a69778 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -3,13 +3,19 @@ import {TextBuffer, Range} from 'atom'; import Hunk from './hunk'; import {Unchanged, Addition, Deletion, NoNewline} from './region'; +export const TOO_LARGE = Symbol('too large'); + +export const EXPANDED = Symbol('expanded'); + +export const COLLAPSED = Symbol('collapsed'); + export default class Patch { static createNull() { return new NullPatch(); } - static createDelayedPatch(diff, insertPoint) { - return new DelayedPatch(diff, insertPoint); + static createDelayedPatch(position, renderStatus, parseFn) { + return new DelayedPatch(position, renderStatus, parseFn); } constructor({status, hunks, marker}) { @@ -269,6 +275,14 @@ export default class Patch { isPresent() { return true; } + + getRenderStatus() { + return EXPANDED; + } + + parseFn() { + return this; + } } class NullPatch { @@ -348,6 +362,14 @@ class NullPatch { isPresent() { return false; } + + renderStatus() { + return EXPANDED; + } + + parseFn() { + return this; + } } // TODO: it prob shouldn't extend NullPatch @@ -356,16 +378,20 @@ class DelayedPatch extends NullPatch { // where to insert // what the diff is // reason it's delayed (???) - constructor(diff, insertPoint) { + constructor(position, renderStatus, parseFn) { super(); - this.insertPoint = insertPoint; - this.diff = diff; + this.position = position; + this.renderStatus = renderStatus; + this.parseFn = parseFn; } getStartRange() { - return new Range(this.insertPoint, this.insertPoint); + return new Range(this.position, this.position); } + getRenderStatus() { + return this.renderStatus; + } } class BufferBuilder { diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 8e64488f05..9e759c2ebe 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -1,4 +1,5 @@ import {buildFilePatch, buildMultiFilePatch} from '../../../lib/models/patch'; +import {TOO_LARGE, EXPANDED} from '../../../lib/models/patch/patch'; import {assertInPatch, assertInFilePatch} from '../../helpers'; describe('buildFilePatch', function() { @@ -800,6 +801,91 @@ describe('buildFilePatch', function() { }); }); + describe('with a large diff', function() { + it('creates a DelayedPatch when the diff is "too large"', function() { + const mfp = buildMultiFilePatch([ + { + oldPath: 'first', oldMode: '100644', newPath: 'first', newMode: '100755', status: 'modified', + hunks: [ + { + oldStartLine: 1, oldLineCount: 3, newStartLine: 1, newLineCount: 3, + lines: [' line-0', '+line-1', '-line-2', ' line-3'], + }, + ], + }, + { + oldPath: 'second', oldMode: '100644', newPath: 'second', newMode: '100755', status: 'modified', + hunks: [ + { + oldStartLine: 1, oldLineCount: 1, newStartLine: 1, newLineCount: 2, + lines: [' line-4', '+line-5'], + }, + ], + }, + ], {largeDiffThreshold: 3}); + + assert.lengthOf(mfp.getFilePatches(), 2); + const [fp0, fp1] = mfp.getFilePatches(); + + assert.strictEqual(fp0.getRenderStatus(), TOO_LARGE); + assert.strictEqual(fp0.getOldPath(), 'first'); + assert.strictEqual(fp0.getNewPath(), 'first'); + assert.deepEqual(fp0.getStartRange().serialize(), [[0, 0], [0, 0]]); + assertInFilePatch(fp0).hunks(); + + assert.strictEqual(fp1.getRenderStatus(), EXPANDED); + assert.strictEqual(fp1.getOldPath(), 'second'); + assert.strictEqual(fp1.getNewPath(), 'second'); + assert.deepEqual(fp1.getMarker().getRange().serialize(), [[0, 0], [1, 6]]); + assertInFilePatch(fp1, mfp.getBuffer()).hunks( + { + startRow: 0, endRow: 1, header: '@@ -1,1 +1,2 @@', regions: [ + {kind: 'unchanged', string: ' line-4\n', range: [[0, 0], [0, 6]]}, + {kind: 'addition', string: '+line-5\n', range: [[1, 0], [1, 6]]}, + ], + }, + ); + }); + + it('re-parse a DelayedPatch as a Patch', function() { + const mfp = buildMultiFilePatch([ + { + oldPath: 'first', oldMode: '100644', newPath: 'first', newMode: '100644', status: 'modified', + hunks: [ + { + oldStartLine: 1, oldLineCount: 3, newStartLine: 1, newLineCount: 3, + lines: [' line-0', '+line-1', '-line-2', ' line-3'], + }, + ], + }, + ], {largeDiffThreshold: 3}); + + assert.lengthOf(mfp.getFilePatches(), 1); + const [fp] = mfp.getFilePatches(); + + assert.strictEqual(fp.getRenderStatus(), TOO_LARGE); + assert.strictEqual(fp.getOldPath(), 'first'); + assert.strictEqual(fp.getNewPath(), 'first'); + assert.deepEqual(fp.getStartRange().serialize(), [[0, 0], [0, 0]]); + assertInFilePatch(fp).hunks(); + + fp.triggerDelayedRender(); + + assert.strictEqual(fp.getRenderStatus(), EXPANDED); + assert.deepEqual(fp.getMarker().getRange().serialize(), [[0, 0], [3, 6]]); + assertInFilePatch(fp, mfp.getBuffer()).hunks( + { + startRow: 0, endRow: 3, header: '@@ -1,3 +1,3 @@', regions: [ + {kind: 'unchanged', string: ' line-0\n', range: [[0, 0], [0, 6]]}, + {kind: 'addition', string: '+line-1\n', range: [[1, 0], [1, 6]]}, + {kind: 'deletion', string: '-line-2\n', range: [[2, 0], [2, 6]]}, + {kind: 'unchanged', string: ' line-3\n', range: [[3, 0], [3, 6]]}, + ], + }, + ); + }); + }); + it('throws an error with an unexpected number of diffs', function() { assert.throws(() => buildFilePatch([1, 2, 3]), /Unexpected number of diffs: 3/); }); From a729493cdfbbb70faf728bb3ab1b1b32754807b2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 10:55:34 -0500 Subject: [PATCH 2602/4847] Correct pre-existing markers after building patch hunks --- lib/models/patch/builder.js | 11 ++++ test/models/patch/builder.test.js | 99 +++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 30adefe7f2..9a52850237 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -205,6 +205,12 @@ function buildHunks(diff, {buffer, layers}, insertRow) { ]); const hunks = []; + const afterMarkers = []; + for (const layerName in layers) { + const layer = layers[layerName]; + afterMarkers.push(...layer.findMarkers({startPosition: [insertRow, 0]})); + } + const patchStartRow = insertRow; let bufferRow = patchStartRow; let nextLineLength = 0; @@ -282,6 +288,11 @@ function buildHunks(diff, {buffer, layers}, insertRow) { {invalidate: 'never', exclusive: false}, ); + // Correct any markers that used to start at the insertion point. + for (const marker of afterMarkers) { + marker.setTailPosition([bufferRow, 0]); + } + return [hunks, patchMarker]; } diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 9e759c2ebe..550b17d506 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -884,6 +884,105 @@ describe('buildFilePatch', function() { }, ); }); + + it('does not interfere with markers from surrounding patches when expanded', function() { + const mfp = buildMultiFilePatch([ + { + oldPath: 'first', oldMode: '100644', newPath: 'first', newMode: '100644', status: 'modified', + hunks: [ + { + oldStartLine: 1, oldLineCount: 3, newStartLine: 1, newLineCount: 3, + lines: [' line-0', '+line-1', '-line-2', ' line-3'], + }, + ], + }, + { + oldPath: 'big', oldMode: '100644', newPath: 'big', newMode: '100644', status: 'modified', + hunks: [ + { + oldStartLine: 1, oldLineCount: 3, newStartLine: 1, newLineCount: 4, + lines: [' line-0', '+line-1', '+line-2', '-line-3', ' line-4'], + }, + ], + }, + { + oldPath: 'last', oldMode: '100644', newPath: 'last', newMode: '100644', status: 'modified', + hunks: [ + { + oldStartLine: 1, oldLineCount: 3, newStartLine: 1, newLineCount: 3, + lines: [' line-0', '+line-1', '-line-2', ' line-3'], + }, + ], + } + ], {largeDiffThreshold: 4}); + + assert.lengthOf(mfp.getFilePatches(), 3); + const [fp0, fp1, fp2] = mfp.getFilePatches(); + assert.strictEqual(fp0.getRenderStatus(), EXPANDED); + assertInFilePatch(fp0, mfp.getBuffer()).hunks( + { + startRow: 0, endRow: 3, header: '@@ -1,3 +1,3 @@', regions: [ + {kind: 'unchanged', string: ' line-0\n', range: [[0, 0], [0, 6]]}, + {kind: 'addition', string: '+line-1\n', range: [[1, 0], [1, 6]]}, + {kind: 'deletion', string: '-line-2\n', range: [[2, 0], [2, 6]]}, + {kind: 'unchanged', string: ' line-3\n', range: [[3, 0], [3, 6]]}, + ], + }, + ); + + assert.strictEqual(fp1.getRenderStatus(), TOO_LARGE); + assertInFilePatch(fp1, mfp.getBuffer()).hunks(); + + assert.strictEqual(fp2.getRenderStatus(), EXPANDED); + assertInFilePatch(fp2, mfp.getBuffer()).hunks( + { + startRow: 4, endRow: 7, header: '@@ -1,3 +1,3 @@', regions: [ + {kind: 'unchanged', string: ' line-0\n', range: [[4, 0], [4, 6]]}, + {kind: 'addition', string: '+line-1\n', range: [[5, 0], [5, 6]]}, + {kind: 'deletion', string: '-line-2\n', range: [[6, 0], [6, 6]]}, + {kind: 'unchanged', string: ' line-3\n', range: [[7, 0], [7, 6]]}, + ], + }, + ); + + fp1.triggerDelayedRender(); + + assert.strictEqual(fp0.getRenderStatus(), EXPANDED); + assertInFilePatch(fp0, mfp.getBuffer()).hunks( + { + startRow: 0, endRow: 3, header: '@@ -1,3 +1,3 @@', regions: [ + {kind: 'unchanged', string: ' line-0\n', range: [[0, 0], [0, 6]]}, + {kind: 'addition', string: '+line-1\n', range: [[1, 0], [1, 6]]}, + {kind: 'deletion', string: '-line-2\n', range: [[2, 0], [2, 6]]}, + {kind: 'unchanged', string: ' line-3\n', range: [[3, 0], [3, 6]]}, + ], + }, + ); + + assert.strictEqual(fp1.getRenderStatus(), EXPANDED); + assertInFilePatch(fp1, mfp.getBuffer()).hunks( + { + startRow: 4, endRow: 8, header: '@@ -1,3 +1,4 @@', regions: [ + {kind: 'unchanged', string: ' line-0\n', range: [[4, 0], [4, 6]]}, + {kind: 'addition', string: '+line-1\n+line-2\n', range: [[5, 0], [6, 6]]}, + {kind: 'deletion', string: '-line-3\n', range: [[7, 0], [7, 6]]}, + {kind: 'unchanged', string: ' line-4\n', range: [[8, 0], [8, 6]]}, + ], + }, + ); + + assert.strictEqual(fp2.getRenderStatus(), EXPANDED); + assertInFilePatch(fp2, mfp.getBuffer()).hunks( + { + startRow: 9, endRow: 12, header: '@@ -1,3 +1,3 @@', regions: [ + {kind: 'unchanged', string: ' line-0\n', range: [[9, 0], [9, 6]]}, + {kind: 'addition', string: '+line-1\n', range: [[10, 0], [10, 6]]}, + {kind: 'deletion', string: '-line-2\n', range: [[11, 0], [11, 6]]}, + {kind: 'unchanged', string: ' line-3\n', range: [[12, 0], [12, 6]]}, + ], + }, + ); + }); }); it('throws an error with an unexpected number of diffs', function() { From 68926e5d4ffe41548b5117605f8767d3a4888be1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 11:03:36 -0500 Subject: [PATCH 2603/4847] :shirt: --- test/models/patch/builder.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 550b17d506..5ee54e42d3 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -913,7 +913,7 @@ describe('buildFilePatch', function() { lines: [' line-0', '+line-1', '-line-2', ' line-3'], }, ], - } + }, ], {largeDiffThreshold: 4}); assert.lengthOf(mfp.getFilePatches(), 3); From 4686cfcda3224df682830ed69150e73dc742e0c0 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 16 Jan 2019 18:14:10 +0100 Subject: [PATCH 2604/4847] get things to render properly first --- lib/models/patch/builder.js | 8 +++----- lib/views/multi-file-patch-view.js | 4 +++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 9a52850237..67c8140e31 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -8,7 +8,7 @@ import FilePatch from './file-patch'; import MultiFilePatch from './multi-file-patch'; // TODO: fixme -const DEFAULT_LARGE_DIFF_THRESHOLD = 500; +const DEFAULT_LARGE_DIFF_THRESHOLD = 10; export function buildFilePatch(diffs, options) { const opts = { @@ -68,7 +68,7 @@ export function buildMultiFilePatch(diffs, options) { // Populate unpaired diffs that looked like they could be part of a pair, but weren't. for (const [unpairedDiff, originalIndex] of byPath.values()) { - actions[originalIndex] = () => singleDiffFilePatch(unpairedDiff, layeredBuffer); + actions[originalIndex] = () => singleDiffFilePatch(unpairedDiff, layeredBuffer, opts); } const filePatches = actions.map(action => action()); @@ -121,7 +121,6 @@ function singleDiffFilePatch(diff, layeredBuffer, opts) { return new Patch({status: diff.status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); }, ); - console.log(delayed.getPatch()); return delayed; } @@ -167,7 +166,7 @@ function dualDiffFilePatch(diff1, diff2, layeredBuffer, opts) { const oldFile = new File({path: filePath, mode: oldMode, symlink: oldSymlink}); const newFile = new File({path: filePath, mode: newMode, symlink: newSymlink}); - if (isDiffLarge([diff1, diff2])) { + if (isDiffLarge([diff1, diff2]), opts) { // TODO: do something with large diff too } @@ -303,6 +302,5 @@ function isDiffLarge(diffs, opts) { }, 0); }, 0); - console.log(diffs, `size: ${size}`); return size > opts.largeDiffThreshold; } diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index a8c50824ec..bf2b7daa3e 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -22,6 +22,8 @@ import CommitDetailItem from '../items/commit-detail-item'; import IssueishDetailItem from '../items/issueish-detail-item'; import File from '../models/patch/file'; +import {TOO_LARGE} from '../models/patch/patch'; + const executableText = { [File.modes.NORMAL]: 'non executable', [File.modes.EXECUTABLE]: 'executable', @@ -353,7 +355,7 @@ export default class MultiFilePatchView extends React.Component { - {filePatch.isLarge() && this.renderDiffGate(filePatch)} + {filePatch.getPatch().getRenderStatus() === TOO_LARGE && this.renderDiffGate(filePatch)} {this.renderHunkHeaders(filePatch)} From 0c3a2a6457690458e831c9da7f6629a242149a4f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 12:25:33 -0500 Subject: [PATCH 2605/4847] Accept renderStatusOverrides in ye MultiFilePatch builder --- lib/models/patch/builder.js | 50 ++++++++++++++++++------------- test/models/patch/builder.test.js | 32 ++++++++++++++++++++ 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 67c8140e31..6c75fc5b0d 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -2,19 +2,22 @@ import {TextBuffer, Point} from 'atom'; import Hunk from './hunk'; import File, {nullFile} from './file'; -import Patch, {TOO_LARGE} from './patch'; +import Patch, {TOO_LARGE, EXPANDED} from './patch'; import {Unchanged, Addition, Deletion, NoNewline} from './region'; import FilePatch from './file-patch'; import MultiFilePatch from './multi-file-patch'; -// TODO: fixme -const DEFAULT_LARGE_DIFF_THRESHOLD = 10; +const DEFAULT_OPTIONS = { + // Number of lines after which we consider the diff "large" + // TODO: Set this based on performance measurements + largeDiffThreshold: 10, + + // Map of file path (relative to repository root) to Patch render status (EXPANDED, COLLAPSED, TOO_LARGE) + renderStatusOverrides: {}, +}; export function buildFilePatch(diffs, options) { - const opts = { - largeDiffThreshold: DEFAULT_LARGE_DIFF_THRESHOLD, - ...options, - }; + const opts = {...DEFAULT_OPTIONS, ...options}; const layeredBuffer = initializeBuffer(); @@ -33,10 +36,7 @@ export function buildFilePatch(diffs, options) { } export function buildMultiFilePatch(diffs, options) { - const opts = { - largeDiffThreshold: DEFAULT_LARGE_DIFF_THRESHOLD, - ...options, - }; + const opts = {...DEFAULT_OPTIONS, ...options}; const layeredBuffer = initializeBuffer(); const byPath = new Map(); @@ -111,23 +111,31 @@ function singleDiffFilePatch(diff, layeredBuffer, opts) { ? new File({path: diff.newPath, mode: diff.newMode, symlink: newSymlink}) : nullFile; - if (isDiffLarge([diff], opts)) { + const renderStatusOverride = + (oldFile.isPresent() && opts.renderStatusOverrides[oldFile.getPath()]) || + (newFile.isPresent() && opts.renderStatusOverrides[newFile.getPath()]) || + undefined; + + const renderStatus = renderStatusOverride || + (isDiffLarge([diff], opts) && TOO_LARGE) || + EXPANDED; + + if (renderStatus === TOO_LARGE) { const insertPoint = new Point(layeredBuffer.buffer.getLastRow(), 0); - const delayed = FilePatch.createDelayedFilePatch( - oldFile, newFile, insertPoint, - TOO_LARGE, + + return FilePatch.createDelayedFilePatch( + oldFile, newFile, insertPoint, TOO_LARGE, () => { const [hunks, patchMarker] = buildHunks(diff, layeredBuffer, insertPoint.row); return new Patch({status: diff.status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); }, ); - return delayed; - } - - const [hunks, patchMarker] = buildHunks(diff, layeredBuffer, layeredBuffer.buffer.getLastRow()); - const patch = new Patch({status: diff.status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); + } else { + const [hunks, patchMarker] = buildHunks(diff, layeredBuffer, layeredBuffer.buffer.getLastRow()); + const patch = new Patch({status: diff.status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); - return new FilePatch(oldFile, newFile, patch); + return new FilePatch(oldFile, newFile, patch); + } } function dualDiffFilePatch(diff1, diff2, layeredBuffer, opts) { diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 5ee54e42d3..59951c2f63 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -983,6 +983,38 @@ describe('buildFilePatch', function() { }, ); }); + + it('does not create a DelayedPatch when the patch has been explicitly expanded', function() { + const mfp = buildMultiFilePatch([ + { + oldPath: 'big/file.txt', oldMode: '100644', newPath: 'big/file.txt', newMode: '100755', status: 'modified', + hunks: [ + { + oldStartLine: 1, oldLineCount: 3, newStartLine: 1, newLineCount: 3, + lines: [' line-0', '+line-1', '-line-2', ' line-3'], + }, + ], + }, + ], {largeDiffThreshold: 3, renderStatusOverrides: {'big/file.txt': EXPANDED}}); + + assert.lengthOf(mfp.getFilePatches(), 1); + const [fp] = mfp.getFilePatches(); + + assert.strictEqual(fp.getRenderStatus(), EXPANDED); + assert.strictEqual(fp.getOldPath(), 'big/file.txt'); + assert.strictEqual(fp.getNewPath(), 'big/file.txt'); + assert.deepEqual(fp.getMarker().getRange().serialize(), [[0, 0], [3, 6]]); + assertInFilePatch(fp, mfp.getBuffer()).hunks( + { + startRow: 0, endRow: 3, header: '@@ -1,1 +1,2 @@', regions: [ + {kind: 'unchanged', string: ' line-0\n', range: [[0, 0], [0, 6]]}, + {kind: 'addition', string: '+line-1\n', range: [[1, 0], [1, 6]]}, + {kind: 'deletion', string: '-line-2\n', range: [[2, 0], [2, 6]]}, + {kind: 'unchanged', string: ' line-3\n', range: [[3, 0], [3, 6]]}, + ], + }, + ); + }); }); it('throws an error with an unexpected number of diffs', function() { From 7db6fb04fb41d057581d3d58edf0eac7bff85884 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 12:31:53 -0500 Subject: [PATCH 2606/4847] Pass builder options to getFilePatchForPath and getStagedChangesPatch --- lib/models/repository-states/present.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index 830c18280e..4604efed66 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -698,16 +698,27 @@ export default class Present extends State { return {stagedFiles, unstagedFiles, mergeConflictFiles}; } - getFilePatchForPath(filePath, {staged} = {staged: false}) { - return this.cache.getOrSet(Keys.filePatch.oneWith(filePath, {staged}), async () => { - const diffs = await this.git().getDiffsForFilePath(filePath, {staged}); - return buildFilePatch(diffs); + getFilePatchForPath(filePath, options) { + const opts = { + staged: false, + builder: {}, + ...options, + }; + + return this.cache.getOrSet(Keys.filePatch.oneWith(filePath, {staged: opts.staged}), async () => { + const diffs = await this.git().getDiffsForFilePath(filePath, {staged: opts.staged}); + return buildFilePatch(diffs, opts.builder); }); } - getStagedChangesPatch() { + getStagedChangesPatch(options) { + const opts = { + builder: {}, + ...options, + }; + return this.cache.getOrSet(Keys.stagedChanges, () => { - return this.git().getStagedChangesPatch().then(buildMultiFilePatch); + return this.git().getStagedChangesPatch().then(diffs => buildMultiFilePatch(diffs, opts.builder)); }); } From 9de0eae26de12dd6aed388fac0a1ec2d986fbc86 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 16 Jan 2019 18:17:36 +0100 Subject: [PATCH 2607/4847] some clean up --- lib/models/patch/patch.js | 4 ---- lib/views/multi-file-patch-view.js | 1 - 2 files changed, 5 deletions(-) diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index bfe2a69778..dd389a59c1 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -374,10 +374,6 @@ class NullPatch { // TODO: it prob shouldn't extend NullPatch class DelayedPatch extends NullPatch { - // should know: - // where to insert - // what the diff is - // reason it's delayed (???) constructor(position, renderStatus, parseFn) { super(); this.position = position; diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index bf2b7daa3e..d36af915bd 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -363,7 +363,6 @@ export default class MultiFilePatchView extends React.Component { } renderDiffGate(filePatch) { - // TODO: startRange is incorrect here return ( From e8f372ad3b6f5e143ea6d6a4420a8956d87a91ba Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 16 Jan 2019 19:02:56 +0100 Subject: [PATCH 2608/4847] click to show diff??? --- lib/views/multi-file-patch-view.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index d36af915bd..54956b1bcc 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -363,10 +363,14 @@ export default class MultiFilePatchView extends React.Component { } renderDiffGate(filePatch) { + const showDiff = () => filePatch.triggerDelayedRender(); return ( -

    Diff is too large to be displayed.

    +

    + Large diffs are collapsed by default for performance reasons. + Show diff anyway? +

    ); From dc04f498a99bb1fd9e55b2b70d6fad919e887e1d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 13:52:52 -0500 Subject: [PATCH 2609/4847] Add a renderStatus to Patch --- lib/models/patch/patch.js | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index dd389a59c1..db4801bd45 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -18,10 +18,11 @@ export default class Patch { return new DelayedPatch(position, renderStatus, parseFn); } - constructor({status, hunks, marker}) { + constructor({status, hunks, marker, renderStatus}) { this.status = status; this.hunks = hunks; this.marker = marker; + this.renderStatus = renderStatus || EXPANDED; this.changedLineCount = this.getHunks().reduce((acc, hunk) => acc + hunk.changedLineCount(), 0); } @@ -69,9 +70,26 @@ export default class Patch { status: opts.status !== undefined ? opts.status : this.getStatus(), hunks: opts.hunks !== undefined ? opts.hunks : this.getHunks(), marker: opts.marker !== undefined ? opts.marker : this.getMarker(), + renderStatus: opts.renderStatus !== undefined ? opts.renderStatus : this.getRenderStatus(), }); } + collapsed() { + if (this.getRenderStatus() === COLLAPSED) { + return this; + } + + return this.clone({renderStatus: COLLAPSED}); + } + + expanded() { + if (this.getRenderStatus() === EXPANDED) { + return this; + } + + return this.clone({renderStatus: EXPANDED}); + } + buildStagePatchForLines(originalBuffer, nextLayeredBuffer, rowSet) { const originalBaseOffset = this.getMarker().getRange().start.row; const builder = new BufferBuilder(originalBuffer, originalBaseOffset, nextLayeredBuffer); @@ -277,7 +295,7 @@ export default class Patch { } getRenderStatus() { - return EXPANDED; + return this.renderStatus; } parseFn() { @@ -331,7 +349,8 @@ class NullPatch { if ( opts.status === undefined && opts.hunks === undefined && - opts.marker === undefined + opts.marker === undefined && + opts.renderStatus === undefined ) { return this; } else { @@ -339,6 +358,7 @@ class NullPatch { status: opts.status !== undefined ? opts.status : this.getStatus(), hunks: opts.hunks !== undefined ? opts.hunks : this.getHunks(), marker: opts.marker !== undefined ? opts.marker : this.getMarker(), + renderStatus: opts.renderStatus !== undefined ? opts.renderStatus : this.getRenderStatus(), }); } } @@ -363,7 +383,7 @@ class NullPatch { return false; } - renderStatus() { + getRenderStatus() { return EXPANDED; } From f0b8371ee74ab75b6f56a07c804543626873a323 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 13:53:10 -0500 Subject: [PATCH 2610/4847] Emit events from a FilePatch when its render status changes --- lib/models/patch/file-patch.js | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index 868ce03753..230928226a 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -1,3 +1,5 @@ +import {Emitter} from 'event-kit'; + import {nullFile} from './file'; import Patch from './patch'; import {toGitPathSep} from '../../helpers'; @@ -15,6 +17,8 @@ export default class FilePatch { this.oldFile = oldFile; this.newFile = newFile; this.patch = patch; + + this.emitter = new Emitter(); } isPresent() { @@ -116,7 +120,35 @@ export default class FilePatch { } triggerDelayedRender() { - this.patch = this.patch.parseFn(); + const nextPatch = this.patch.parseFn(); + if (nextPatch !== this.patch) { + this.patch = nextPatch; + this.didChangeRenderStatus(); + } + } + + triggerCollapse() { + const nextPatch = this.patch.collapsed(); + if (nextPatch !== this.patch) { + this.patch = nextPatch; + this.didChangeRenderStatus(); + } + } + + triggerExpand() { + const nextPatch = this.patch.expanded(); + if (nextPatch !== this.patch) { + this.patch = nextPatch; + this.didChangeRenderStatus(); + } + } + + didChangeRenderStatus() { + return this.emitter.emit('change-render-status', this); + } + + onDidChangeRenderStatus(callback) { + return this.emitter.on('change-render-status', callback); } clone(opts = {}) { From 9dad4f7942c0d27ee668e6946ec4b5605d8ba76f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 13:53:36 -0500 Subject: [PATCH 2611/4847] Unit tests for FilePatch render status events --- test/builder/patch.js | 13 ++++- test/models/patch/file-patch.test.js | 75 +++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/test/builder/patch.js b/test/builder/patch.js index 18ff5067b5..c2e0e830ab 100644 --- a/test/builder/patch.js +++ b/test/builder/patch.js @@ -122,6 +122,11 @@ class FilePatchBuilder { return this; } + renderStatus(...args) { + this.patchBuilder.renderStatus(...args); + return this; + } + empty() { this.patchBuilder.empty(); return this; @@ -175,6 +180,7 @@ class PatchBuilder { constructor(layeredBuffer = null) { this.layeredBuffer = layeredBuffer; + this._renderStatus = undefined; this._status = 'modified'; this.hunks = []; @@ -183,6 +189,11 @@ class PatchBuilder { this.explicitlyEmpty = false; } + renderStatus(status) { + this._renderStatus = status; + return this; + } + status(st) { if (['modified', 'added', 'deleted'].indexOf(st) === -1) { throw new Error(`Unrecognized status: ${st} (must be 'modified', 'added' or 'deleted')`); @@ -221,7 +232,7 @@ class PatchBuilder { const marker = this.layeredBuffer.markFrom('patch', this.patchStart); return this.layeredBuffer.wrapReturn({ - patch: new Patch({status: this._status, hunks: this.hunks, marker}), + patch: new Patch({status: this._status, hunks: this.hunks, marker, renderStatus: this._renderStatus}), }); } } diff --git a/test/models/patch/file-patch.test.js b/test/models/patch/file-patch.test.js index abc0b5551d..34bc44dbfb 100644 --- a/test/models/patch/file-patch.test.js +++ b/test/models/patch/file-patch.test.js @@ -1,11 +1,12 @@ -import {TextBuffer} from 'atom'; +import {TextBuffer, Point} from 'atom'; import FilePatch from '../../../lib/models/patch/file-patch'; import File, {nullFile} from '../../../lib/models/patch/file'; -import Patch from '../../../lib/models/patch/patch'; +import Patch, {TOO_LARGE, COLLAPSED, EXPANDED} from '../../../lib/models/patch/patch'; import Hunk from '../../../lib/models/patch/hunk'; import {Unchanged, Addition, Deletion, NoNewline} from '../../../lib/models/patch/region'; import {assertInFilePatch} from '../../helpers'; +import {filePatchBuilder, patchBuilder} from '../../builder/patch'; describe('FilePatch', function() { it('delegates methods to its files and patch', function() { @@ -669,6 +670,76 @@ describe('FilePatch', function() { assert.isFalse(nullFilePatch.buildUnstagePatchForLines(new Set([0])).isPresent()); assert.strictEqual(nullFilePatch.toStringIn(new TextBuffer()), ''); }); + + describe('render status changes', function() { + let sub; + + afterEach(function() { + sub && sub.dispose(); + }); + + it('announces a delayed render to subscribers', function() { + const {patch: expandedPatch} = patchBuilder().build(); + + const filePatch = FilePatch.createDelayedFilePatch( + new File({path: 'file-0.txt', mode: '100644'}), + new File({path: 'file-1.txt', mode: '100644'}), + new Point(0, 0), + TOO_LARGE, + () => expandedPatch, + ); + + const callback = sinon.spy(); + sub = filePatch.onDidChangeRenderStatus(callback); + + assert.strictEqual(TOO_LARGE, filePatch.getRenderStatus()); + assert.notStrictEqual(filePatch.getPatch(), expandedPatch); + filePatch.triggerDelayedRender(); + + assert.strictEqual(EXPANDED, filePatch.getRenderStatus()); + assert.strictEqual(filePatch.getPatch(), expandedPatch); + assert.isTrue(callback.calledWith(filePatch)); + }); + + it('announces the collapse of an expanded patch', function() { + const {filePatch} = filePatchBuilder().build(); + + const callback = sinon.spy(); + sub = filePatch.onDidChangeRenderStatus(callback); + + assert.strictEqual(EXPANDED, filePatch.getRenderStatus()); + filePatch.triggerCollapse(); + + assert.strictEqual(COLLAPSED, filePatch.getRenderStatus()); + assert.isTrue(callback.calledWith(filePatch)); + }); + + it('announces the expansion of a collapsed patch', function() { + const {filePatch} = filePatchBuilder().renderStatus(COLLAPSED).build(); + + const callback = sinon.spy(); + sub = filePatch.onDidChangeRenderStatus(callback); + + assert.strictEqual(COLLAPSED, filePatch.getRenderStatus()); + filePatch.triggerExpand(); + + assert.strictEqual(EXPANDED, filePatch.getRenderStatus()); + assert.isTrue(callback.calledWith(filePatch)); + }); + + it('does not announce non-changes', function() { + const {filePatch} = filePatchBuilder().build(); + + const callback = sinon.spy(); + sub = filePatch.onDidChangeRenderStatus(callback); + + filePatch.triggerDelayedRender(); + assert.isFalse(callback.called); + + filePatch.triggerExpand(); + assert.isFalse(callback.called); + }); + }); }); function buildLayers(buffer) { From cd5cc2899040950363f7f0018c363f75fa2d076e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 14:27:04 -0500 Subject: [PATCH 2612/4847] Remember changed renderStatus --- lib/containers/changed-file-container.js | 35 ++++++++++++++++++- .../containers/changed-file-container.test.js | 21 ++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/lib/containers/changed-file-container.js b/lib/containers/changed-file-container.js index fc9a83ee4c..221ac0c7fe 100644 --- a/lib/containers/changed-file-container.js +++ b/lib/containers/changed-file-container.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import yubikiri from 'yubikiri'; +import {CompositeDisposable} from 'event-kit'; import {autobind} from '../helpers'; import ObserveModel from '../views/observe-model'; @@ -12,6 +13,7 @@ export default class ChangedFileContainer extends React.Component { repository: PropTypes.object.isRequired, stagingStatus: PropTypes.oneOf(['staged', 'unstaged']), relPath: PropTypes.string.isRequired, + largeDiffThreshold: PropTypes.number, workspace: PropTypes.object.isRequired, commands: PropTypes.object.isRequired, @@ -27,13 +29,26 @@ export default class ChangedFileContainer extends React.Component { constructor(props) { super(props); autobind(this, 'fetchData', 'renderWithData'); + + this.lastMultiFilePatch = null; + this.sub = new CompositeDisposable(); + + this.state = {renderStatusOverride: null}; } fetchData(repository) { const staged = this.props.stagingStatus === 'staged'; + const builder = {}; + if (this.state.renderStatusOverride !== null) { + builder.renderStatusOverrides = {[this.props.relPath]: this.state.renderStatusOverride}; + } + if (this.props.largeDiffThreshold !== undefined) { + builder.largeDiffThreshold = this.props.largeDiffThreshold; + } + return yubikiri({ - multiFilePatch: repository.getFilePatchForPath(this.props.relPath, {staged}), + multiFilePatch: repository.getFilePatchForPath(this.props.relPath, {staged, builder}), isPartiallyStaged: repository.isPartiallyStaged(this.props.relPath), hasUndoHistory: repository.hasDiscardHistory(this.props.relPath), }); @@ -48,6 +63,20 @@ export default class ChangedFileContainer extends React.Component { } renderWithData(data) { + const currentMultiFilePatch = data && data.multiFilePatch; + if (currentMultiFilePatch !== this.lastMultiFilePatch) { + this.sub.dispose(); + if (currentMultiFilePatch) { + // Keep this component's renderStatusOverride synchronized with the FilePatch we're rendering + this.sub = new CompositeDisposable( + ...currentMultiFilePatch.getFilePatches().map(fp => fp.onDidChangeRenderStatus(() => { + this.setState({renderStatusOverride: fp.getRenderStatus()}); + })), + ); + } + this.lastMultiFilePatch = currentMultiFilePatch; + } + if (this.props.repository.isLoading() || data === null) { return ; } @@ -59,4 +88,8 @@ export default class ChangedFileContainer extends React.Component { /> ); } + + componentWillUnmount() { + this.sub.dispose(); + } } diff --git a/test/containers/changed-file-container.test.js b/test/containers/changed-file-container.test.js index dd8fbf01f7..80573cbdad 100644 --- a/test/containers/changed-file-container.test.js +++ b/test/containers/changed-file-container.test.js @@ -5,6 +5,7 @@ import {mount} from 'enzyme'; import ChangedFileContainer from '../../lib/containers/changed-file-container'; import ChangedFileItem from '../../lib/items/changed-file-item'; +import {TOO_LARGE, EXPANDED} from '../../lib/models/patch/patch'; import {cloneRepository, buildRepository} from '../helpers'; describe('ChangedFileContainer', function() { @@ -17,7 +18,7 @@ describe('ChangedFileContainer', function() { repository = await buildRepository(workdirPath); // a.txt: unstaged changes - await fs.writeFile(path.join(workdirPath, 'a.txt'), 'changed\n'); + await fs.writeFile(path.join(workdirPath, 'a.txt'), '0\n1\n2\n3\n4\n5\n'); // b.txt: staged changes await fs.writeFile(path.join(workdirPath, 'b.txt'), 'changed\n'); @@ -100,4 +101,22 @@ describe('ChangedFileContainer', function() { const wrapper = mount(buildApp({relPath: 'a.txt', stagingStatus: 'unstaged', extra})); await assert.async.strictEqual(wrapper.update().find('MultiFilePatchView').prop('extra'), extra); }); + + it('remembers previously expanded large FilePatches', async function() { + const wrapper = mount(buildApp({relPath: 'a.txt', stagingStatus: 'unstaged', largeDiffThreshold: 2})); + + await assert.async.isTrue(wrapper.update().exists('ChangedFileController')); + const before = wrapper.find('ChangedFileController').prop('multiFilePatch'); + assert.strictEqual(before.getFilePatches()[0].getRenderStatus(), TOO_LARGE); + + before.getFilePatches()[0].triggerDelayedRender(); + assert.strictEqual(before.getFilePatches()[0].getRenderStatus(), EXPANDED); + + repository.refresh(); + await assert.async.notStrictEqual(wrapper.update().find('ChangedFileController').prop('multiFilePatch'), before); + + const after = wrapper.find('ChangedFileController').prop('multiFilePatch'); + assert.notStrictEqual(after, before); + assert.strictEqual(after.getFilePatches()[0].getRenderStatus(), EXPANDED); + }); }); From 7eab1197df074d1066698e543e5fa053075f8aad Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Fri, 21 Dec 2018 12:42:51 -0800 Subject: [PATCH 2613/4847] add collapse button to file patch header --- lib/views/file-patch-header-view.js | 15 +++++++++++++++ styles/file-patch-view.less | 11 +++++++++++ 2 files changed, 26 insertions(+) diff --git a/lib/views/file-patch-header-view.js b/lib/views/file-patch-header-view.js index 1425221120..a78b931750 100644 --- a/lib/views/file-patch-header-view.js +++ b/lib/views/file-patch-header-view.js @@ -4,6 +4,7 @@ import React, {Fragment} from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; +import Octicon from '../atom/octicon'; import RefHolder from '../models/ref-holder'; import IssueishDetailItem from '../items/issueish-detail-item'; import ChangedFileItem from '../items/changed-file-item'; @@ -25,7 +26,10 @@ export default class FilePatchHeaderView extends React.Component { undoLastDiscard: PropTypes.func.isRequired, diveIntoMirrorPatch: PropTypes.func.isRequired, openFile: PropTypes.func.isRequired, + // should probably change 'toggleFile' to 'toggleFileStagingStatus' + // because the addition of another toggling function makes the old name confusing. toggleFile: PropTypes.func.isRequired, + toggleFileCollapse: PropTypes.func, itemType: ItemTypePropType.isRequired, }; @@ -42,12 +46,23 @@ export default class FilePatchHeaderView extends React.Component {
    {this.renderTitle()} + {this.renderCollapseButton()} {this.renderButtonGroup()}
    ); } + renderCollapseButton() { + return ( + + ); + } + renderTitle() { if (this.props.itemType === ChangedFileItem) { const status = this.props.stagingStatus; diff --git a/styles/file-patch-view.less b/styles/file-patch-view.less index a51fd5d820..cc9af4ed6e 100644 --- a/styles/file-patch-view.less +++ b/styles/file-patch-view.less @@ -64,6 +64,17 @@ margin-right: @component-padding; } + &-collapseButton { + background: transparent; + border: none; + // dont' judge me. flexbox seemed like overkill, ok? + float: right; + } + + &-collapseButtonIcon { + position: absolute; + } + &-container { flex: 1; display: flex; From b2512645f062256ea04361935b41c77c94de12a2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 15:03:17 -0500 Subject: [PATCH 2614/4847] Use a Marker instead of a Point to track delayed patch location --- lib/models/patch/builder.js | 10 +++++++--- lib/models/patch/file-patch.js | 6 +++--- lib/models/patch/patch.js | 29 ++++++++--------------------- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 6c75fc5b0d..75e1f4d11f 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -121,12 +121,16 @@ function singleDiffFilePatch(diff, layeredBuffer, opts) { EXPANDED; if (renderStatus === TOO_LARGE) { - const insertPoint = new Point(layeredBuffer.buffer.getLastRow(), 0); + const insertRow = layeredBuffer.buffer.getLastRow(); + const patchMarker = layeredBuffer.layers.patch.markPosition( + [insertRow, 0], + {invalidate: 'never', exclusive: false}, + ); return FilePatch.createDelayedFilePatch( - oldFile, newFile, insertPoint, TOO_LARGE, + oldFile, newFile, patchMarker, TOO_LARGE, () => { - const [hunks, patchMarker] = buildHunks(diff, layeredBuffer, insertPoint.row); + const [hunks] = buildHunks(diff, layeredBuffer, insertRow, patchMarker); return new Patch({status: diff.status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); }, ); diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index 230928226a..362f630ae2 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -9,8 +9,8 @@ export default class FilePatch { return new this(nullFile, nullFile, Patch.createNull()); } - static createDelayedFilePatch(oldFile, newFile, position, renderStatus, parseFn) { - return new this(oldFile, newFile, Patch.createDelayedPatch(position, renderStatus, parseFn)); + static createDelayedFilePatch(oldFile, newFile, marker, renderStatus, parseFn) { + return new this(oldFile, newFile, Patch.createDelayedPatch(marker, renderStatus, parseFn)); } constructor(oldFile, newFile, patch) { @@ -120,7 +120,7 @@ export default class FilePatch { } triggerDelayedRender() { - const nextPatch = this.patch.parseFn(); + const nextPatch = this.patch.parseFn(this.patch); if (nextPatch !== this.patch) { this.patch = nextPatch; this.didChangeRenderStatus(); diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index db4801bd45..99741312ca 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -14,17 +14,22 @@ export default class Patch { return new NullPatch(); } - static createDelayedPatch(position, renderStatus, parseFn) { - return new DelayedPatch(position, renderStatus, parseFn); + static createDelayedPatch(marker, renderStatus, parseFn) { + return new this({status: null, hunks: [], marker, renderStatus, parseFn}); } - constructor({status, hunks, marker, renderStatus}) { + constructor({status, hunks, marker, renderStatus, parseFn}) { this.status = status; this.hunks = hunks; this.marker = marker; this.renderStatus = renderStatus || EXPANDED; this.changedLineCount = this.getHunks().reduce((acc, hunk) => acc + hunk.changedLineCount(), 0); + + if (parseFn) { + // Override the prototype's method + this.parseFn = parseFn; + } } getStatus() { @@ -392,24 +397,6 @@ class NullPatch { } } -// TODO: it prob shouldn't extend NullPatch -class DelayedPatch extends NullPatch { - constructor(position, renderStatus, parseFn) { - super(); - this.position = position; - this.renderStatus = renderStatus; - this.parseFn = parseFn; - } - - getStartRange() { - return new Range(this.position, this.position); - } - - getRenderStatus() { - return this.renderStatus; - } -} - class BufferBuilder { constructor(original, originalBaseOffset, nextLayeredBuffer) { this.originalBuffer = original; From 0bfacb6bbf77398e4ef71ccc73531f4644e1aa1a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 15:25:34 -0500 Subject: [PATCH 2615/4847] Track changed renderStatus in CommitPreviewContainer --- lib/containers/commit-preview-container.js | 39 ++++++++++++++++++- .../commit-preview-container.test.js | 30 ++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/lib/containers/commit-preview-container.js b/lib/containers/commit-preview-container.js index ef77f354fe..9b6cf49240 100644 --- a/lib/containers/commit-preview-container.js +++ b/lib/containers/commit-preview-container.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import yubikiri from 'yubikiri'; +import {CompositeDisposable} from 'event-kit'; import ObserveModel from '../views/observe-model'; import LoadingView from '../views/loading-view'; @@ -9,11 +10,27 @@ import CommitPreviewController from '../controllers/commit-preview-controller'; export default class CommitPreviewContainer extends React.Component { static propTypes = { repository: PropTypes.object.isRequired, + largeDiffThreshold: PropTypes.number, + } + + constructor(props) { + super(props); + + this.lastMultiFilePatch = null; + this.sub = new CompositeDisposable(); + + this.state = {renderStatusOverrides: {}}; } fetchData = repository => { + const builder = {renderStatusOverrides: this.state.renderStatusOverrides}; + + if (this.props.largeDiffThreshold !== undefined) { + builder.largeDiffThreshold = this.props.largeDiffThreshold; + } + return yubikiri({ - multiFilePatch: repository.getStagedChangesPatch(), + multiFilePatch: repository.getStagedChangesPatch({builder}), }); } @@ -26,6 +43,26 @@ export default class CommitPreviewContainer extends React.Component { } renderResult = data => { + const currentMultiFilePatch = data && data.multiFilePatch; + if (currentMultiFilePatch !== this.lastMultiFilePatch) { + this.sub.dispose(); + if (currentMultiFilePatch) { + this.sub = new CompositeDisposable( + ...currentMultiFilePatch.getFilePatches().map(fp => fp.onDidChangeRenderStatus(() => { + this.setState(prevState => { + return { + renderStatusOverrides: { + ...prevState.renderStatusOverrides, + [fp.getPath()]: fp.getRenderStatus(), + }, + }; + }); + })), + ); + } + this.lastMultiFilePatch = currentMultiFilePatch; + } + if (this.props.repository.isLoading() || data === null) { return ; } diff --git a/test/containers/commit-preview-container.test.js b/test/containers/commit-preview-container.test.js index c11a5a9164..c24002d0ae 100644 --- a/test/containers/commit-preview-container.test.js +++ b/test/containers/commit-preview-container.test.js @@ -1,8 +1,11 @@ import React from 'react'; import {mount} from 'enzyme'; +import fs from 'fs-extra'; +import path from 'path'; import CommitPreviewContainer from '../../lib/containers/commit-preview-container'; import CommitPreviewItem from '../../lib/items/commit-preview-item'; +import {TOO_LARGE, EXPANDED} from '../../lib/models/patch/patch'; import {cloneRepository, buildRepository} from '../helpers'; describe('CommitPreviewContainer', function() { @@ -71,4 +74,31 @@ describe('CommitPreviewContainer', function() { await assert.async.isTrue(wrapper.update().find('CommitPreviewController').exists()); assert.strictEqual(wrapper.find('CommitPreviewController').prop('multiFilePatch'), patch); }); + + it('remembers previously expanded large patches', async function() { + const wd = repository.getWorkingDirectoryPath(); + await repository.getLoadPromise(); + + await fs.writeFile(path.join(wd, 'file-0.txt'), '0\n1\n2\n3\n4\n5\n', {encoding: 'utf8'}); + await fs.writeFile(path.join(wd, 'file-1.txt'), '0\n1\n2\n', {encoding: 'utf8'}); + await repository.stageFiles(['file-0.txt', 'file-1.txt']); + + repository.refresh(); + + const wrapper = mount(buildApp({largeDiffThreshold: 3})); + await assert.async.isTrue(wrapper.update().exists('CommitPreviewController')); + + const before = wrapper.find('CommitPreviewController').prop('multiFilePatch'); + assert.strictEqual(before.getFilePatches()[0].getRenderStatus(), TOO_LARGE); + assert.strictEqual(before.getFilePatches()[1].getRenderStatus(), EXPANDED); + + before.getFilePatches()[0].triggerDelayedRender(); + repository.refresh(); + + await assert.async.notStrictEqual(wrapper.update().find('CommitPreviewController').prop('multiFilePatch'), before); + const after = wrapper.find('CommitPreviewController').prop('multiFilePatch'); + + assert.strictEqual(after.getFilePatches()[0].getRenderStatus(), EXPANDED); + assert.strictEqual(after.getFilePatches()[1].getRenderStatus(), EXPANDED); + }); }); From 40cde30b343b0e8b490ba4ce4e42447f06f68ebc Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 16 Jan 2019 15:40:21 -0500 Subject: [PATCH 2616/4847] Ditto for CommitDetailContainer --- lib/containers/commit-detail-container.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/containers/commit-detail-container.js b/lib/containers/commit-detail-container.js index c624d127f7..eedf3370be 100644 --- a/lib/containers/commit-detail-container.js +++ b/lib/containers/commit-detail-container.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import yubikiri from 'yubikiri'; +import {CompositeDisposable} from 'event-kit'; import ObserveModel from '../views/observe-model'; import LoadingView from '../views/loading-view'; @@ -13,6 +14,13 @@ export default class CommitDetailContainer extends React.Component { itemType: PropTypes.func.isRequired, } + constructor(props) { + super(props); + + this.lastCommit = null; + this.sub = new CompositeDisposable(); + } + fetchData = repository => { return yubikiri({ commit: repository.getCommit(this.props.sha), @@ -31,6 +39,19 @@ export default class CommitDetailContainer extends React.Component { } renderResult = data => { + const currentCommit = data && data.commit; + if (currentCommit !== this.lastCommit) { + this.sub.dispose(); + if (currentCommit && currentCommit.isPresent()) { + this.sub = new CompositeDisposable( + ...currentCommit.getMultiFileDiff().getFilePatches().map(fp => fp.onDidChangeRenderStatus(() => { + this.forceUpdate(); + })), + ); + } + this.lastCommit = currentCommit; + } + if (this.props.repository.isLoading() || data === null || !data.commit.isPresent()) { return ; } From be2ab8f5deb6d9ca7d78965ab7bafda69ad51776 Mon Sep 17 00:00:00 2001 From: annthurium Date: Wed, 16 Jan 2019 13:50:05 -0800 Subject: [PATCH 2617/4847] fix bad parens in mfp builder --- lib/models/patch/builder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 75e1f4d11f..45bbcdc9c2 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -178,7 +178,7 @@ function dualDiffFilePatch(diff1, diff2, layeredBuffer, opts) { const oldFile = new File({path: filePath, mode: oldMode, symlink: oldSymlink}); const newFile = new File({path: filePath, mode: newMode, symlink: newSymlink}); - if (isDiffLarge([diff1, diff2]), opts) { + if (isDiffLarge([diff1, diff2], opts)) { // TODO: do something with large diff too } From e28522ededfa992f89fab4032f9963f0469eff19 Mon Sep 17 00:00:00 2001 From: annthurium Date: Wed, 16 Jan 2019 15:10:17 -0800 Subject: [PATCH 2618/4847] don't render pull request comments if patch exceeds large diff threshold --- lib/models/patch/multi-file-patch.js | 15 +++++++++++++++ lib/views/multi-file-patch-view.js | 1 + lib/views/pr-review-comments-view.js | 3 +++ 3 files changed, 19 insertions(+) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index e21ae6158f..bf88e1fa32 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -1,6 +1,8 @@ import {TextBuffer, Range} from 'atom'; import {RBTree} from 'bintrees'; +import {TOO_LARGE} from './patch'; + export default class MultiFilePatch { constructor({buffer, layers, filePatches}) { this.buffer = buffer || null; @@ -339,6 +341,19 @@ export default class MultiFilePatch { return false; } + doesPatchExceedLargeDiffThreshold = filePatchPath => { + + const patches = this.getFilePatches(); + // can avoid iterating through all patches by adding a map + const patch = patches.filter(p => p.getPath() === filePatchPath)[0]; + // do I need to handle case where patch is null or something? + if (patch.getRenderStatus() === TOO_LARGE) { + return true; + } else { + return false; + } + } + getBufferRowForDiffPosition = (fileName, diffRow) => { const {startBufferRow, index} = this.diffRowOffsetIndices.get(fileName); const {offset} = index.lowerBound({diffRow}).data(); diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 54956b1bcc..05bcd3635f 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -321,6 +321,7 @@ export default class MultiFilePatchView extends React.Component { ); } else { diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index 80e89af272..af5feaece9 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -33,6 +33,9 @@ export default class PullRequestCommentsView extends React.Component { } const nativePath = toNativePathSep(rootComment.path); + if (this.props.doesPatchExceedLargeDiffThreshold(rootComment.path)) { + return null; + } const row = this.props.getBufferRowForDiffPosition(nativePath, rootComment.position); const point = new Point(row, 0); const range = new Range(point, point); From b66c88c3c5a33be85a2c97aab143d540dfc0c814 Mon Sep 17 00:00:00 2001 From: annthurium Date: Wed, 16 Jan 2019 15:16:47 -0800 Subject: [PATCH 2619/4847] use a Map to avoid iterating through patches --- lib/models/patch/multi-file-patch.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index bf88e1fa32..193b4cd803 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -17,6 +17,7 @@ export default class MultiFilePatch { this.filePatches = filePatches || []; this.filePatchesByMarker = new Map(); + this.filePatchesByPath = new Map(); this.hunksByMarker = new Map(); // Store a map of {diffRow, offset} for each FilePatch where offset is the number of Hunk headers within the current @@ -24,6 +25,7 @@ export default class MultiFilePatch { this.diffRowOffsetIndices = new Map(); for (const filePatch of this.filePatches) { + this.filePatchesByPath.set(filePatch.getPath(), filePatch); this.filePatchesByMarker.set(filePatch.getMarker(), filePatch); let diffRow = 1; @@ -342,16 +344,9 @@ export default class MultiFilePatch { } doesPatchExceedLargeDiffThreshold = filePatchPath => { - - const patches = this.getFilePatches(); - // can avoid iterating through all patches by adding a map - const patch = patches.filter(p => p.getPath() === filePatchPath)[0]; + const patch = this.filePatchesByPath.get(filePatchPath); + return patch.getRenderStatus() === TOO_LARGE; // do I need to handle case where patch is null or something? - if (patch.getRenderStatus() === TOO_LARGE) { - return true; - } else { - return false; - } } getBufferRowForDiffPosition = (fileName, diffRow) => { From 98fbfc910e76cccc6359558c5370bfe28566686d Mon Sep 17 00:00:00 2001 From: annthurium Date: Wed, 16 Jan 2019 15:22:07 -0800 Subject: [PATCH 2620/4847] deal with null patches ...not sure how we would get into this situation, but it seems like an important case to cover. --- lib/models/patch/multi-file-patch.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 193b4cd803..be4f516e1b 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -345,8 +345,10 @@ export default class MultiFilePatch { doesPatchExceedLargeDiffThreshold = filePatchPath => { const patch = this.filePatchesByPath.get(filePatchPath); + if (!patch) { + return null; + } return patch.getRenderStatus() === TOO_LARGE; - // do I need to handle case where patch is null or something? } getBufferRowForDiffPosition = (fileName, diffRow) => { From ccf2a99fc04e917f0a112f8a56fc96e12f2c00c5 Mon Sep 17 00:00:00 2001 From: annthurium Date: Wed, 16 Jan 2019 15:26:08 -0800 Subject: [PATCH 2621/4847] :shirt: --- lib/models/patch/builder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 45bbcdc9c2..29fc3f6156 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -1,4 +1,4 @@ -import {TextBuffer, Point} from 'atom'; +import {TextBuffer} from 'atom'; import Hunk from './hunk'; import File, {nullFile} from './file'; From 26ee209b4a37d03d1f56a57d136751fbb56dc2da Mon Sep 17 00:00:00 2001 From: annthurium Date: Wed, 16 Jan 2019 15:27:36 -0800 Subject: [PATCH 2622/4847] danananana PROP TYPES --- lib/controllers/pr-reviews-controller.js | 1 + lib/views/pr-review-comments-view.js | 1 + test/controllers/pr-reviews-controller.test.js | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index d10839eb69..9c72522333 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -19,6 +19,7 @@ export default class PullRequestReviewsController extends React.Component { ), }), getBufferRowForDiffPosition: PropTypes.func.isRequired, + doesPatchExceedLargeDiffThreshold: PropTypes.func.isRequired, } constructor(props) { diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index af5feaece9..9268728284 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -23,6 +23,7 @@ export default class PullRequestCommentsView extends React.Component { })), getBufferRowForDiffPosition: PropTypes.func.isRequired, switchToIssueish: PropTypes.func.isRequired, + doesPatchExceedLargeDiffThreshold: PropTypes.func.isRequired, } render() { diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index 83cfa8eadd..b6080d5b3c 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -43,6 +43,7 @@ describe('PullRequestReviewsController', function() { switchToIssueish: () => {}, getBufferRowForDiffPosition: () => {}, + doesPatchExceedLargeDiffThreshold: () => {}, pullRequest: {reviews}, ...overrideProps, }; From 010cd56374443aeb7b95199af9c4e04b45a09e5c Mon Sep 17 00:00:00 2001 From: annthurium Date: Wed, 16 Jan 2019 16:31:34 -0800 Subject: [PATCH 2623/4847] also check for COLLAPSED patch state --- lib/controllers/pr-reviews-controller.js | 2 +- lib/models/patch/multi-file-patch.js | 7 ++++--- lib/views/multi-file-patch-view.js | 2 +- lib/views/pr-review-comments-view.js | 7 ++++--- test/controllers/pr-reviews-controller.test.js | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 9c72522333..f2a836fc32 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -19,7 +19,7 @@ export default class PullRequestReviewsController extends React.Component { ), }), getBufferRowForDiffPosition: PropTypes.func.isRequired, - doesPatchExceedLargeDiffThreshold: PropTypes.func.isRequired, + isPatchTooLargeOrCollapsed: PropTypes.func.isRequired, } constructor(props) { diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index be4f516e1b..0490c5fd12 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -1,7 +1,7 @@ import {TextBuffer, Range} from 'atom'; import {RBTree} from 'bintrees'; -import {TOO_LARGE} from './patch'; +import {TOO_LARGE, COLLAPSED} from './patch'; export default class MultiFilePatch { constructor({buffer, layers, filePatches}) { @@ -343,12 +343,13 @@ export default class MultiFilePatch { return false; } - doesPatchExceedLargeDiffThreshold = filePatchPath => { + isPatchTooLargeOrCollapsed = filePatchPath => { const patch = this.filePatchesByPath.get(filePatchPath); if (!patch) { return null; } - return patch.getRenderStatus() === TOO_LARGE; + const renderStatus = patch.getRenderStatus(); + return renderStatus === TOO_LARGE || renderStatus === COLLAPSED; } getBufferRowForDiffPosition = (fileName, diffRow) => { diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 05bcd3635f..5554ac910c 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -321,7 +321,7 @@ export default class MultiFilePatchView extends React.Component { ); } else { diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index 9268728284..ca597f066e 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -23,7 +23,7 @@ export default class PullRequestCommentsView extends React.Component { })), getBufferRowForDiffPosition: PropTypes.func.isRequired, switchToIssueish: PropTypes.func.isRequired, - doesPatchExceedLargeDiffThreshold: PropTypes.func.isRequired, + isPatchTooLargeOrCollapsed: PropTypes.func.isRequired, } render() { @@ -33,10 +33,11 @@ export default class PullRequestCommentsView extends React.Component { return null; } - const nativePath = toNativePathSep(rootComment.path); - if (this.props.doesPatchExceedLargeDiffThreshold(rootComment.path)) { + // if file patch is collapsed or too large, do not render the comments + if (this.props.isPatchTooLargeOrCollapsed(rootComment.path)) { return null; } + const nativePath = toNativePathSep(rootComment.path); const row = this.props.getBufferRowForDiffPosition(nativePath, rootComment.position); const point = new Point(row, 0); const range = new Range(point, point); diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index b6080d5b3c..fcd44eacc8 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -43,7 +43,7 @@ describe('PullRequestReviewsController', function() { switchToIssueish: () => {}, getBufferRowForDiffPosition: () => {}, - doesPatchExceedLargeDiffThreshold: () => {}, + isPatchTooLargeOrCollapsed: () => {}, pullRequest: {reviews}, ...overrideProps, }; From cd2b7f982c119abf53066e67621404915f086b36 Mon Sep 17 00:00:00 2001 From: annthurium Date: Wed, 16 Jan 2019 16:56:09 -0800 Subject: [PATCH 2624/4847] honk if you like test helpers --- lib/views/pr-review-comments-view.js | 1 + test/views/pr-comments-view.test.js | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index ca597f066e..f31a9fe36b 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -11,6 +11,7 @@ import GithubDotcomMarkdown from './github-dotcom-markdown'; import Timeago from './timeago'; export default class PullRequestCommentsView extends React.Component { + // do we even need the relay props here? does not look like they are used static propTypes = { relay: PropTypes.shape({ hasMore: PropTypes.func.isRequired, diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index 15e2562626..7e32b755da 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -6,6 +6,23 @@ import {pullRequestBuilder} from '../builder/pr'; import PullRequestCommentsView, {PullRequestCommentView} from '../../lib/views/pr-review-comments-view'; describe('PullRequestCommentsView', function() { + function buildApp(multiFilePatch, pullRequest, overrideProps) { + const relay = { + hasMore: () => {}, + loadMore: () => {}, + isLoading: () => {}, + }; + return shallow( + {}} + {...overrideProps} + />, + ); + } it('adjusts the position for comments after hunk headers', function() { const {multiFilePatch} = multiFilePatchBuilder() .addFilePatch(fp => { @@ -31,7 +48,7 @@ describe('PullRequestCommentsView', function() { }) .build(); - const wrapper = shallow(); + const wrapper = buildApp(multiFilePatch, pr, {}); assert.deepEqual(wrapper.find('Marker').at(0).prop('bufferRange').serialize(), [[1, 0], [1, 0]]); assert.deepEqual(wrapper.find('Marker').at(1).prop('bufferRange').serialize(), [[12, 0], [12, 0]]); @@ -57,7 +74,7 @@ describe('PullRequestCommentsView', function() { }) .build(); - const wrapper = shallow(); + const wrapper = buildApp(multiFilePatch, pr, {}); const comments = wrapper.find('PullRequestCommentView'); assert.lengthOf(comments, 1); From 8324cb3080cd684a11bb1a7b23626c1380f408ab Mon Sep 17 00:00:00 2001 From: annthurium Date: Wed, 16 Jan 2019 17:00:15 -0800 Subject: [PATCH 2625/4847] clean up pr comments builder unnecessary console output during tests is a bummer. --- test/builder/pr.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/builder/pr.js b/test/builder/pr.js index 3616872b77..52c72a95dc 100644 --- a/test/builder/pr.js +++ b/test/builder/pr.js @@ -6,9 +6,10 @@ class CommentBuilder { this._authorLogin = 'someone'; this._authorAvatarUrl = 'https://avatars3.githubusercontent.com/u/17565?s=32&v=4'; this._url = 'https://github.com/atom/github/pull/1829/files#r242224689'; - this._createdAt = 0; + this._createdAt = '2018-12-27T17:51:17Z'; this._body = 'Lorem ipsum dolor sit amet, te urbanitas appellantur est.'; this._replyTo = null; + this._isMinimized = false; } id(i) { @@ -16,6 +17,11 @@ class CommentBuilder { return this; } + minmized(m) { + this._isMinimized = m; + return this; + } + path(p) { this._path = p; return this; @@ -69,6 +75,7 @@ class CommentBuilder { createdAt: this._createdAt, url: this._url, replyTo: this._replyTo, + isMinimized: this._isMinimized, }; } } From ee6c9c22f2204df05cdb988ed64d99d79649a5fa Mon Sep 17 00:00:00 2001 From: annthurium Date: Wed, 16 Jan 2019 17:10:30 -0800 Subject: [PATCH 2626/4847] [wip] add tests for `isPatchTooLargeOrCollapsed` --- test/models/patch/multi-file-patch.test.js | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index cad02eaffa..61fa236f7a 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -2,9 +2,12 @@ import dedent from 'dedent-js'; import {multiFilePatchBuilder, filePatchBuilder} from '../../builder/patch'; +import {TOO_LARGE} from '../../../lib/models/patch/patch'; import MultiFilePatch from '../../../lib/models/patch/multi-file-patch'; + import {assertInFilePatch} from '../../helpers'; + describe('MultiFilePatch', function() { it('creates an empty patch when constructed with no arguments', function() { const empty = new MultiFilePatch({}); @@ -704,6 +707,41 @@ describe('MultiFilePatch', function() { }); }); + describe('isPatchTooLargeOrCollapsed', function() { + let multiFilePatch; + beforeEach(function() { + multiFilePatch = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('file-0')); + // do we even give a shit about the hunks here? + fp.addHunk(h => h.unchanged('0').added('1').deleted('2', '3').unchanged('4')); + fp.addHunk(h => h.unchanged('5').added('6').unchanged('7')); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('file-1')); + fp.addHunk(h => h.unchanged('8').deleted('9', '10').unchanged('11')); + }) + .build() + .multiFilePatch; + }); + it('returns true if patch exceeds large diff threshold', function() { + // todo: what is the best way to use the patch builder to build at patch that + // exceeds the large diff threshold? + }); + + it('returns true if patch is collapsed', function() { + }); + + it('returns false if patch does not exceed large diff threshold and is not collapsed', function() { + assert.isFalse(multiFilePatch.isPatchTooLargeOrCollapsed('file-1')); + }); + + it('returns null if patch does not exist', function() { + assert.isNull(multiFilePatch.isPatchTooLargeOrCollapsed('invalid-file-path')); + }); + }); + + describe('diff position translation', function() { it('offsets rows in the first hunk by the first hunk header', function() { const {multiFilePatch} = multiFilePatchBuilder() From 49d12128b36ddf3bd0ea36be9db7bc2f8efe5cf1 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 17 Jan 2019 17:21:59 +0900 Subject: [PATCH 2627/4847] Replace PR list with progress bars --- docs/feature-requests/003-pull-request-review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 2fc225648d..4d30fdd02b 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -18,7 +18,7 @@ Peer review is also a critical part of the path to acceptance for pull requests ### Pull Request list -![image](https://user-images.githubusercontent.com/378023/46524357-89bf6580-c8c3-11e8-8e2d-ea02d5a1f278.png) +![image](https://user-images.githubusercontent.com/378023/51304737-4658c380-1a7c-11e9-8edb-7ceafeedabe5.png) * Review progress is indicated for open pull requests listed in the GitHub panel. * The pull request corresponding to the checked out branch gets special treatment in its own section at the top of the list. From 6c6a5b6050856bd0df91e329f3efda3e3801c1aa Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 17 Jan 2019 17:31:08 +0900 Subject: [PATCH 2628/4847] Replace PR list actions --- docs/feature-requests/003-pull-request-review.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 4d30fdd02b..6cc1655e77 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -23,10 +23,10 @@ Peer review is also a critical part of the path to acceptance for pull requests * Review progress is indicated for open pull requests listed in the GitHub panel. * The pull request corresponding to the checked out branch gets special treatment in its own section at the top of the list. -![center pane](https://user-images.githubusercontent.com/378023/46985265-75c9fe00-d124-11e8-9b34-572cd1aaf701.png) +![center pane](https://user-images.githubusercontent.com/378023/51305096-45746180-1a7d-11e9-801b-37b3ab0c862a.png) * Clicking a pull request in the list opens a `PullRequestDetailItem` in the workspace center. -* Clicking the "Reviews" label or progress bar opens a `PullRequestReviewsItem` in the right dock. +* Clicking the progress bar opens a `PullRequestReviewsItem` in the left dock. ### PullRequestDetailItem From b72a00655442b3026d78d8e77bf4299849df2e10 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 17 Jan 2019 17:35:29 +0900 Subject: [PATCH 2629/4847] Replace header and footer Plus remove outdated mockups --- docs/feature-requests/003-pull-request-review.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 6cc1655e77..a99d9e2a4a 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -32,7 +32,7 @@ Peer review is also a critical part of the path to acceptance for pull requests #### Header -![header](https://user-images.githubusercontent.com/378023/46536358-3829d180-c8e9-11e8-9167-3d1003ab566b.png) +![header](https://user-images.githubusercontent.com/378023/51305325-e400c280-1a7d-11e9-9b4e-b9cf2d326dd5.png) At the top of each `PullRequestDetailItem` is a summary about the pull request, followed by the tabs to switch between different sub-views. @@ -45,15 +45,9 @@ Below the tabs is a "tools bar" with controls to toggle review comments or colla #### Footer -> TODO: Add "open" button +![reviews panel](https://user-images.githubusercontent.com/378023/51305353-f2e77500-1a7d-11e9-96f0-da879d49da3a.png) -![reviews panel](https://user-images.githubusercontent.com/378023/46536010-17ad4780-c8e8-11e8-8338-338bb592efc5.png) - -A panel at the bottom of the pane shows the progress for resolved review comments. It also has a "Review Changes" button to create a new review. This panel is persistent throughout all sub-views. It allows creating new reviews no matter where you are. Below examples with the existing sub-views: - -Overview | Commits | Build Status ---- | --- | --- -![overview](https://user-images.githubusercontent.com/378023/46535907-ca30da80-c8e7-11e8-9401-2b8660d56c25.png) | ![commits](https://user-images.githubusercontent.com/378023/46535908-ca30da80-c8e7-11e8-87ca-01637f2554b6.png) | ![build status](https://user-images.githubusercontent.com/378023/46535909-cac97100-c8e7-11e8-8813-47fdaa3ece57.png) +A panel at the bottom of the pane shows the progress for resolved review comments. It also has a "Review Changes" button to create a new review. This panel is persistent throughout all sub-views. It allows creating new reviews no matter where you are. When the pull request is checked out, an "open" button is shown in the review footer. Clicking "open" opens a `PullRequestReviewsItem` for this pull request's review comments as an item in the right workspace dock. From 5ca37fb4196e0489d6137fed740099823badac97 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 17 Jan 2019 17:54:33 +0900 Subject: [PATCH 2630/4847] Update "Files" mockups --- docs/feature-requests/003-pull-request-review.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index a99d9e2a4a..2b22be338d 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -55,15 +55,15 @@ When the pull request is checked out, an "open" button is shown in the review fo Clicking on the "Files Changed" tab displays the full, multi-file diff associated with the pull request. This is akin to the "Files changed" tab on dotcom. -> TODO: Change "Show review comments" checkbox to an expand/collapse review summaries control - -![files](https://user-images.githubusercontent.com/378023/46536560-d3bb4200-c8e9-11e8-9764-dca0b84245cf.png) +![files](https://user-images.githubusercontent.com/378023/51305826-43ab9d80-1a7f-11e9-8b41-42bc4812d214.png) Clicking on the "Expand review summaries" control in the filter bar reveals an inline panel that displays the summary of each review created on this pull request, including the review's author, the review's current state, its summary comment, and a progress bar showing how many of the review comments associated with this review have been marked as resolved. -![review summary list panel](https://user-images.githubusercontent.com/17565/50930369-e172ed00-142d-11e9-8ae4-00106dde80f5.png) +![review summary list panel](https://user-images.githubusercontent.com/378023/51305827-43ab9d80-1a7f-11e9-90be-902e541b805f.png) + +Clicking on "Comments" within each review summary block hides or reveals the review summary comments associated with that review in diff on this tab. Clicking the "Collapse review summaries" control conceals the review summary panel again. -Clicking the checkbox within each review summary block hides or reveals the review summary comments associated with that review in diff on this tab. Clicking the "Collapse review summaries" control conceals the review summary panel again. +![review summary list panel with comments](https://user-images.githubusercontent.com/378023/51306485-ca14af00-1a80-11e9-8e52-bb4d55928736.png) Beneath the review summary panel is the pull request's combined diff. Diffs are editable, but _only_ if the pull request branch is checked out and the local branch history has not diverged incompatibly from the remote branch history. From dccb70a740d932fa658524d885c238839e8be907 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 17 Jan 2019 17:58:30 +0900 Subject: [PATCH 2631/4847] Replace pull request reviews item --- docs/feature-requests/003-pull-request-review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 2b22be338d..eb03b8e8e2 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -124,7 +124,7 @@ This item is opened in the workspace's right dock when the user: It shows a scrollable view of all of the reviews and comments associated with a specific pull request, -![pull request reviews item](https://user-images.githubusercontent.com/17565/50931285-213ad400-1430-11e9-8dd2-bd0cc98216fa.png) +![pull request reviews item](https://user-images.githubusercontent.com/378023/51306720-6939a680-1a81-11e9-8eaa-ffd480e3d47f.png) Reviews are sorted by "urgency," showing reviews that still need to be addressed at the top. Within each group, sorting is done by "newest first". From 07336769f5acd64b799c1cb05da33906253cd1fa Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 17 Jan 2019 08:35:54 -0500 Subject: [PATCH 2632/4847] Test case for Patch Marker movement --- test/models/patch/builder.test.js | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 59951c2f63..d917d8af36 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -984,6 +984,50 @@ describe('buildFilePatch', function() { ); }); + it('preserves patch markers when a delayed patch is expanded', function() { + const mfp = buildMultiFilePatch([ + { + oldPath: 'first', oldMode: '100644', newPath: 'first', newMode: '100644', status: 'modified', + hunks: [ + { + oldStartLine: 1, oldLineCount: 3, newStartLine: 1, newLineCount: 3, + lines: [' line-0', '+line-1', '-line-2', ' line-3'], + }, + ], + }, + { + oldPath: 'second', oldMode: '100644', newPath: 'second', newMode: '100644', status: 'modified', + hunks: [ + { + oldStartLine: 1, oldLineCount: 3, newStartLine: 1, newLineCount: 3, + lines: [' line-0', '+line-1', '-line-2', ' line-3'], + }, + ], + }, + { + oldPath: 'third', oldMode: '100644', newPath: 'third', newMode: '100644', status: 'modified', + hunks: [ + { + oldStartLine: 1, oldLineCount: 3, newStartLine: 1, newLineCount: 3, + lines: [' line-0', '+line-1', '-line-2', ' line-3'], + }, + ], + }, + ], {largeDiffThreshold: 3}); + + assert.lengthOf(mfp.getFilePatches(), 3); + const [fp0, fp1, fp2] = mfp.getFilePatches(); + assert.deepEqual(fp0.getMarker().getRange().serialize(), [[0, 0], [0, 0]]); + assert.deepEqual(fp1.getMarker().getRange().serialize(), [[0, 0], [0, 0]]); + assert.deepEqual(fp2.getMarker().getRange().serialize(), [[0, 0], [0, 0]]); + + fp1.triggerDelayedRender(); + + assert.deepEqual(fp0.getMarker().getRange().serialize(), [[0, 0], [0, 0]]); + assert.deepEqual(fp1.getMarker().getRange().serialize(), [[0, 0], [3, 6]]); + assert.deepEqual(fp2.getMarker().getRange().serialize(), [[4, 0], [4, 0]]); + }); + it('does not create a DelayedPatch when the patch has been explicitly expanded', function() { const mfp = buildMultiFilePatch([ { From 1237458dec35cc4ee510bf3933a65374c9e981bf Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 17 Jan 2019 10:23:21 -0500 Subject: [PATCH 2633/4847] Extract LayeredBuffer class and use it consistently in Patch logic --- lib/models/patch/builder.js | 84 ++++++++------------ lib/models/patch/hunk.js | 2 + lib/models/patch/layered-buffer.js | 43 ++++++++++ lib/models/patch/multi-file-patch.js | 112 +++++++++------------------ lib/models/patch/patch.js | 76 +++++++++--------- lib/models/patch/region.js | 8 ++ test/builder/patch.js | 85 ++++++++------------ test/models/patch/builder.test.js | 4 +- 8 files changed, 193 insertions(+), 221 deletions(-) create mode 100644 lib/models/patch/layered-buffer.js diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 29fc3f6156..6a308b2f7d 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -1,5 +1,4 @@ -import {TextBuffer} from 'atom'; - +import LayeredBuffer from './layered-buffer'; import Hunk from './hunk'; import File, {nullFile} from './file'; import Patch, {TOO_LARGE, EXPANDED} from './patch'; @@ -10,7 +9,7 @@ import MultiFilePatch from './multi-file-patch'; const DEFAULT_OPTIONS = { // Number of lines after which we consider the diff "large" // TODO: Set this based on performance measurements - largeDiffThreshold: 10, + largeDiffThreshold: 100, // Map of file path (relative to repository root) to Patch render status (EXPANDED, COLLAPSED, TOO_LARGE) renderStatusOverrides: {}, @@ -19,7 +18,7 @@ const DEFAULT_OPTIONS = { export function buildFilePatch(diffs, options) { const opts = {...DEFAULT_OPTIONS, ...options}; - const layeredBuffer = initializeBuffer(); + const layeredBuffer = new LayeredBuffer(); let filePatch; if (diffs.length === 0) { @@ -32,13 +31,13 @@ export function buildFilePatch(diffs, options) { throw new Error(`Unexpected number of diffs: ${diffs.length}`); } - return new MultiFilePatch({filePatches: [filePatch], ...layeredBuffer}); + return new MultiFilePatch({layeredBuffer, filePatches: [filePatch]}); } export function buildMultiFilePatch(diffs, options) { const opts = {...DEFAULT_OPTIONS, ...options}; - const layeredBuffer = initializeBuffer(); + const layeredBuffer = new LayeredBuffer(); const byPath = new Map(); const actions = []; @@ -82,7 +81,7 @@ export function buildMultiFilePatch(diffs, options) { } }); - return new MultiFilePatch({filePatches, ...layeredBuffer}); + return new MultiFilePatch({layeredBuffer, filePatches}); } function emptyDiffFilePatch() { @@ -121,8 +120,9 @@ function singleDiffFilePatch(diff, layeredBuffer, opts) { EXPANDED; if (renderStatus === TOO_LARGE) { - const insertRow = layeredBuffer.buffer.getLastRow(); - const patchMarker = layeredBuffer.layers.patch.markPosition( + const insertRow = layeredBuffer.getBuffer().getLastRow(); + const patchMarker = layeredBuffer.markPosition( + Patch.layerName, [insertRow, 0], {invalidate: 'never', exclusive: false}, ); @@ -131,12 +131,12 @@ function singleDiffFilePatch(diff, layeredBuffer, opts) { oldFile, newFile, patchMarker, TOO_LARGE, () => { const [hunks] = buildHunks(diff, layeredBuffer, insertRow, patchMarker); - return new Patch({status: diff.status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); + return new Patch({status: diff.status, hunks, marker: patchMarker}); }, ); } else { - const [hunks, patchMarker] = buildHunks(diff, layeredBuffer, layeredBuffer.buffer.getLastRow()); - const patch = new Patch({status: diff.status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); + const [hunks, patchMarker] = buildHunks(diff, layeredBuffer, layeredBuffer.getBuffer().getLastRow()); + const patch = new Patch({status: diff.status, hunks, marker: patchMarker}); return new FilePatch(oldFile, newFile, patch); } @@ -182,8 +182,8 @@ function dualDiffFilePatch(diff1, diff2, layeredBuffer, opts) { // TODO: do something with large diff too } - const [hunks, patchMarker] = buildHunks(contentChangeDiff, layeredBuffer, layeredBuffer.buffer.getLastRow()); - const patch = new Patch({status, hunks, marker: patchMarker, buffer: layeredBuffer.buffer}); + const [hunks, patchMarker] = buildHunks(contentChangeDiff, layeredBuffer, layeredBuffer.getBuffer().getLastRow()); + const patch = new Patch({status, hunks, marker: patchMarker}); return new FilePatch(oldFile, newFile, patch); } @@ -195,41 +195,18 @@ const CHANGEKIND = { '\\': NoNewline, }; -function initializeBuffer() { - const buffer = new TextBuffer(); - buffer.retain(); - - const layers = ['patch', 'hunk', 'unchanged', 'addition', 'deletion', 'noNewline'].reduce((obj, key) => { - obj[key] = buffer.addMarkerLayer(); - return obj; - }, {}); - - return {buffer, layers}; -} - -function buildHunks(diff, {buffer, layers}, insertRow) { - const layersByKind = new Map([ - [Unchanged, layers.unchanged], - [Addition, layers.addition], - [Deletion, layers.deletion], - [NoNewline, layers.noNewline], - ]); +function buildHunks(diff, layeredBuffer, insertRow, existingMarker = null) { const hunks = []; - const afterMarkers = []; - for (const layerName in layers) { - const layer = layers[layerName]; - afterMarkers.push(...layer.findMarkers({startPosition: [insertRow, 0]})); - } - const patchStartRow = insertRow; let bufferRow = patchStartRow; let nextLineLength = 0; if (diff.hunks.length === 0) { - const patchMarker = layers.patch.markPosition( + const patchMarker = layeredBuffer.markPosition( + Patch.layerName, [patchStartRow, 0], - {invalidate: 'never', exclusive: false}, + {invalidate: 'never', exclusive: true}, ); return [hunks, patchMarker]; @@ -251,7 +228,8 @@ function buildHunks(diff, {buffer, layers}, insertRow) { regions.push( new LastChangeKind( - layersByKind.get(LastChangeKind).markRange( + layeredBuffer.markRange( + LastChangeKind.layerName, [[currentRangeStart, 0], [bufferRow - 1, lastLineLength]], {invalidate: 'never', exclusive: false}, ), @@ -263,7 +241,7 @@ function buildHunks(diff, {buffer, layers}, insertRow) { for (const lineText of hunkData.lines) { const bufferLine = lineText.slice(1) + '\n'; nextLineLength = lineText.length - 1; - buffer.insert([bufferRow, 0], bufferLine); + layeredBuffer.getBuffer().insert([bufferRow, 0], bufferLine); const ChangeKind = CHANGEKIND[lineText[0]]; if (ChangeKind === undefined) { @@ -286,7 +264,8 @@ function buildHunks(diff, {buffer, layers}, insertRow) { oldRowCount: hunkData.oldLineCount, newRowCount: hunkData.newLineCount, sectionHeading: hunkData.heading, - marker: layers.hunk.markRange( + marker: layeredBuffer.markRange( + Hunk.layerName, [[bufferStartRow, 0], [bufferRow - 1, nextLineLength]], {invalidate: 'never', exclusive: false}, ), @@ -294,14 +273,15 @@ function buildHunks(diff, {buffer, layers}, insertRow) { })); } - const patchMarker = layers.patch.markRange( - [[patchStartRow, 0], [bufferRow - 1, nextLineLength]], - {invalidate: 'never', exclusive: false}, - ); - - // Correct any markers that used to start at the insertion point. - for (const marker of afterMarkers) { - marker.setTailPosition([bufferRow, 0]); + let patchMarker = existingMarker; + if (patchMarker) { + patchMarker.setRange([[patchStartRow, 0], [bufferRow - 1, nextLineLength]], {exclusive: false}); + } else { + patchMarker = layeredBuffer.markRange( + Patch.layerName, + [[patchStartRow, 0], [bufferRow - 1, nextLineLength]], + {invalidate: 'never', exclusive: false}, + ); } return [hunks, patchMarker]; diff --git a/lib/models/patch/hunk.js b/lib/models/patch/hunk.js index 84cab39002..074f86f7f3 100644 --- a/lib/models/patch/hunk.js +++ b/lib/models/patch/hunk.js @@ -1,4 +1,6 @@ export default class Hunk { + static layerName = 'hunk'; + constructor({ oldStartRow, newStartRow, diff --git a/lib/models/patch/layered-buffer.js b/lib/models/patch/layered-buffer.js new file mode 100644 index 0000000000..2265ae7899 --- /dev/null +++ b/lib/models/patch/layered-buffer.js @@ -0,0 +1,43 @@ +import {TextBuffer} from 'atom'; + +const LAYER_NAMES = ['unchanged', 'addition', 'deletion', 'nonewline', 'hunk', 'patch']; + +export default class LayeredBuffer { + constructor() { + this.buffer = new TextBuffer(); + this.layers = LAYER_NAMES.reduce((map, layerName) => { + map[layerName] = this.buffer.addMarkerLayer(); + return map; + }, {}); + } + + getBuffer() { + return this.buffer; + } + + getInsertionPoint() { + return this.buffer.getEndPosition(); + } + + getLayer(layerName) { + return this.layers[layerName]; + } + + findMarkers(layerName, ...args) { + return this.layers[layerName].findMarkers(...args); + } + + markPosition(layerName, ...args) { + return this.layers[layerName].markPosition(...args); + } + + markRange(layerName, ...args) { + return this.layers[layerName].markRange(...args); + } + + clearAllLayers() { + for (const layerName of LAYER_NAMES) { + this.layers[layerName].clear(); + } + } +} diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 0490c5fd12..3e5a85c602 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -1,20 +1,17 @@ -import {TextBuffer, Range} from 'atom'; +import {Range} from 'atom'; import {RBTree} from 'bintrees'; +import LayeredBuffer from './layered-buffer'; import {TOO_LARGE, COLLAPSED} from './patch'; export default class MultiFilePatch { - constructor({buffer, layers, filePatches}) { - this.buffer = buffer || null; - - this.patchLayer = layers && layers.patch; - this.hunkLayer = layers && layers.hunk; - this.unchangedLayer = layers && layers.unchanged; - this.additionLayer = layers && layers.addition; - this.deletionLayer = layers && layers.deletion; - this.noNewlineLayer = layers && layers.noNewline; + static createNull() { + return new this({layeredBuffer: new LayeredBuffer(), filePatches: []}); + } - this.filePatches = filePatches || []; + constructor({layeredBuffer, filePatches}) { + this.layeredBuffer = layeredBuffer; + this.filePatches = filePatches; this.filePatchesByMarker = new Map(); this.filePatchesByPath = new Map(); @@ -48,45 +45,41 @@ export default class MultiFilePatch { clone(opts = {}) { return new this.constructor({ - buffer: opts.buffer !== undefined ? opts.buffer : this.getBuffer(), - layers: opts.layers !== undefined ? opts.layers : { - patch: this.getPatchLayer(), - hunk: this.getHunkLayer(), - unchanged: this.getUnchangedLayer(), - addition: this.getAdditionLayer(), - deletion: this.getDeletionLayer(), - noNewline: this.getNoNewlineLayer(), - }, + layeredBuffer: opts.layeredBuffer !== undefined ? opts.layeredBuffer : this.getLayeredBuffer(), filePatches: opts.filePatches !== undefined ? opts.filePatches : this.getFilePatches(), }); } + getLayeredBuffer() { + return this.layeredBuffer; + } + getBuffer() { - return this.buffer; + return this.getLayeredBuffer().getBuffer(); } getPatchLayer() { - return this.patchLayer; + return this.getLayeredBuffer().getLayer('patch'); } getHunkLayer() { - return this.hunkLayer; + return this.getLayeredBuffer().getLayer('hunk'); } getUnchangedLayer() { - return this.unchangedLayer; + return this.getLayeredBuffer().getLayer('unchanged'); } getAdditionLayer() { - return this.additionLayer; + return this.getLayeredBuffer().getLayer('addition'); } getDeletionLayer() { - return this.deletionLayer; + return this.getLayeredBuffer().getLayer('deletion'); } getNoNewlineLayer() { - return this.noNewlineLayer; + return this.getLayeredBuffer().getLayer('nonewline'); } getFilePatches() { @@ -108,7 +101,7 @@ export default class MultiFilePatch { if (bufferRow < 0) { return undefined; } - const [marker] = this.patchLayer.findMarkers({intersectsRow: bufferRow}); + const [marker] = this.layeredBuffer.findMarkers('patch', {intersectsRow: bufferRow}); return this.filePatchesByMarker.get(marker); } @@ -116,16 +109,16 @@ export default class MultiFilePatch { if (bufferRow < 0) { return undefined; } - const [marker] = this.hunkLayer.findMarkers({intersectsRow: bufferRow}); + const [marker] = this.layeredBuffer.findMarkers('hunk', {intersectsRow: bufferRow}); return this.hunksByMarker.get(marker); } getStagePatchForLines(selectedLineSet) { - const nextLayeredBuffer = this.buildLayeredBuffer(); + const nextLayeredBuffer = new LayeredBuffer(); const nextFilePatches = this.getFilePatchesContaining(selectedLineSet).map(fp => { return fp.buildStagePatchForLines(this.getBuffer(), nextLayeredBuffer, selectedLineSet); }); - return this.clone({...nextLayeredBuffer, filePatches: nextFilePatches}); + return this.clone({layeredBuffer: nextLayeredBuffer, filePatches: nextFilePatches}); } getStagePatchForHunk(hunk) { @@ -133,11 +126,11 @@ export default class MultiFilePatch { } getUnstagePatchForLines(selectedLineSet) { - const nextLayeredBuffer = this.buildLayeredBuffer(); + const nextLayeredBuffer = new LayeredBuffer(); const nextFilePatches = this.getFilePatchesContaining(selectedLineSet).map(fp => { return fp.buildUnstagePatchForLines(this.getBuffer(), nextLayeredBuffer, selectedLineSet); }); - return this.clone({...nextLayeredBuffer, filePatches: nextFilePatches}); + return this.clone({layeredBuffer: nextLayeredBuffer, filePatches: nextFilePatches}); } getUnstagePatchForHunk(hunk) { @@ -220,64 +213,29 @@ export default class MultiFilePatch { } adoptBufferFrom(lastMultiFilePatch) { - lastMultiFilePatch.getPatchLayer().clear(); - lastMultiFilePatch.getHunkLayer().clear(); - lastMultiFilePatch.getUnchangedLayer().clear(); - lastMultiFilePatch.getAdditionLayer().clear(); - lastMultiFilePatch.getDeletionLayer().clear(); - lastMultiFilePatch.getNoNewlineLayer().clear(); + const nextLayeredBuffer = lastMultiFilePatch.getLayeredBuffer(); + nextLayeredBuffer.clearAllLayers(); this.filePatchesByMarker.clear(); this.hunksByMarker.clear(); - const nextBuffer = lastMultiFilePatch.getBuffer(); - nextBuffer.setText(this.getBuffer().getText()); + nextLayeredBuffer.getBuffer().setText(this.getBuffer().getText()); for (const filePatch of this.getFilePatches()) { - filePatch.getPatch().reMarkOn(lastMultiFilePatch.getPatchLayer()); + filePatch.getPatch().reMarkOn(nextLayeredBuffer); this.filePatchesByMarker.set(filePatch.getMarker(), filePatch); for (const hunk of filePatch.getHunks()) { - hunk.reMarkOn(lastMultiFilePatch.getHunkLayer()); + hunk.reMarkOn(nextLayeredBuffer); this.hunksByMarker.set(hunk.getMarker(), hunk); for (const region of hunk.getRegions()) { - const target = region.when({ - unchanged: () => lastMultiFilePatch.getUnchangedLayer(), - addition: () => lastMultiFilePatch.getAdditionLayer(), - deletion: () => lastMultiFilePatch.getDeletionLayer(), - nonewline: () => lastMultiFilePatch.getNoNewlineLayer(), - }); - region.reMarkOn(target); + region.reMarkOn(nextLayeredBuffer); } } } - this.patchLayer = lastMultiFilePatch.getPatchLayer(); - this.hunkLayer = lastMultiFilePatch.getHunkLayer(); - this.unchangedLayer = lastMultiFilePatch.getUnchangedLayer(); - this.additionLayer = lastMultiFilePatch.getAdditionLayer(); - this.deletionLayer = lastMultiFilePatch.getDeletionLayer(); - this.noNewlineLayer = lastMultiFilePatch.getNoNewlineLayer(); - - this.buffer = nextBuffer; - } - - buildLayeredBuffer() { - const buffer = new TextBuffer(); - buffer.retain(); - - return { - buffer, - layers: { - patch: buffer.addMarkerLayer(), - hunk: buffer.addMarkerLayer(), - unchanged: buffer.addMarkerLayer(), - addition: buffer.addMarkerLayer(), - deletion: buffer.addMarkerLayer(), - noNewline: buffer.addMarkerLayer(), - }, - }; + this.layeredBuffer = nextLayeredBuffer; } /* @@ -304,7 +262,7 @@ export default class MultiFilePatch { } anyPresent() { - return this.buffer !== null && this.filePatches.some(fp => fp.isPresent()); + return this.layeredBuffer !== null && this.filePatches.some(fp => fp.isPresent()); } didAnyChangeExecutableMode() { @@ -362,7 +320,7 @@ export default class MultiFilePatch { * Construct an apply-able patch String. */ toString() { - return this.filePatches.map(fp => fp.toStringIn(this.buffer)).join(''); + return this.filePatches.map(fp => fp.toStringIn(this.getBuffer())).join(''); } isEqual(other) { diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index 99741312ca..b5fc8209e5 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -3,13 +3,27 @@ import {TextBuffer, Range} from 'atom'; import Hunk from './hunk'; import {Unchanged, Addition, Deletion, NoNewline} from './region'; -export const TOO_LARGE = Symbol('too large'); +export const EXPANDED = { + toString() { return 'RenderStatus(expanded)'; }, -export const EXPANDED = Symbol('expanded'); + isVisible() { return true; }, +}; -export const COLLAPSED = Symbol('collapsed'); +export const COLLAPSED = { + toString() { return 'RenderStatus(collapsed)'; }, + + isVisible() { return false; }, +}; + +export const TOO_LARGE = { + toString() { return 'RenderStatus(too-large)'; }, + + isVisible() { return false; }, +}; export default class Patch { + static layerName = 'patch'; + static createNull() { return new NullPatch(); } @@ -61,8 +75,12 @@ export default class Patch { return this.marker.getRange().intersectsRow(row); } - reMarkOn(markable) { - this.marker = markable.markRange(this.getRange(), {invalidate: 'never', exclusive: false}); + reMarkOn(layeredBuffer) { + this.marker = layeredBuffer.markRange( + this.constructor.layerName, + this.getRange(), + {invalidate: 'never', exclusive: false}, + ); } getMaxLineNumberWidth() { @@ -174,9 +192,11 @@ export default class Patch { } } - const buffer = builder.getBuffer(); - const layers = builder.getLayers(); - const marker = layers.patch.markRange([[0, 0], [buffer.getLastRow() - 1, Infinity]]); + const marker = nextLayeredBuffer.markRange( + this.constructor.layerName, + [[0, 0], [nextLayeredBuffer.getBuffer().getLastRow() - 1, Infinity]], + {invalidate: 'never', exclusive: false}, + ); const wholeFile = rowSet.size === this.changedLineCount; const status = this.getStatus() === 'deleted' && !wholeFile ? 'modified' : this.getStatus(); @@ -269,9 +289,11 @@ export default class Patch { status = 'added'; } - const buffer = builder.getBuffer(); - const layers = builder.getLayers(); - const marker = layers.patch.markRange([[0, 0], [buffer.getLastRow(), Infinity]]); + const marker = nextLayeredBuffer.markRange( + this.constructor.layerName, + [[0, 0], [nextLayeredBuffer.getBuffer().getLastRow(), Infinity]], + {invalidate: 'never', exclusive: false}, + ); return this.clone({hunks, status, marker}); } @@ -400,16 +422,7 @@ class NullPatch { class BufferBuilder { constructor(original, originalBaseOffset, nextLayeredBuffer) { this.originalBuffer = original; - - this.buffer = nextLayeredBuffer.buffer; - this.layers = new Map([ - [Unchanged, nextLayeredBuffer.layers.unchanged], - [Addition, nextLayeredBuffer.layers.addition], - [Deletion, nextLayeredBuffer.layers.deletion], - [NoNewline, nextLayeredBuffer.layers.noNewline], - ['hunk', nextLayeredBuffer.layers.hunk], - ['patch', nextLayeredBuffer.layers.patch], - ]); + this.nextLayeredBuffer = nextLayeredBuffer; // The ranges provided to builder methods are expected to be valid within the original buffer. Account for // the position of the Patch within its original TextBuffer, and any existing content already on the next @@ -457,15 +470,15 @@ class BufferBuilder { } latestHunkWasIncluded() { - this.buffer.append(this.hunkBufferText, {normalizeLineEndings: false}); + this.nextLayeredBuffer.getBuffer().append(this.hunkBufferText, {normalizeLineEndings: false}); const regions = this.hunkRegions.map(({RegionKind, range}) => { return new RegionKind( - this.layers.get(RegionKind).markRange(range, {invalidate: 'never', exclusive: false}), + this.nextLayeredBuffer.getLayer(RegionKind.layerName, range, {invalidate: 'never', exclusive: false}), ); }); - const marker = this.layers.get('hunk').markRange(this.hunkRange, {invalidate: 'never', exclusive: false}); + const marker = this.nextLayeredBuffer.markRange('hunk', this.hunkRange, {invalidate: 'never', exclusive: false}); this.hunkBufferText = ''; this.hunkRowCount = 0; @@ -488,18 +501,7 @@ class BufferBuilder { return {regions: [], marker: null}; } - getBuffer() { - return this.buffer; - } - - getLayers() { - return { - patch: this.layers.get('patch'), - hunk: this.layers.get('hunk'), - unchanged: this.layers.get(Unchanged), - addition: this.layers.get(Addition), - deletion: this.layers.get(Deletion), - noNewline: this.layers.get(NoNewline), - }; + getLayeredBuffer() { + return this.nextLayeredBuffer; } } diff --git a/lib/models/patch/region.js b/lib/models/patch/region.js index 3afaef844d..d246b911bc 100644 --- a/lib/models/patch/region.js +++ b/lib/models/patch/region.js @@ -125,6 +125,8 @@ class Region { export class Addition extends Region { static origin = '+'; + static layerName = 'addition'; + isAddition() { return true; } @@ -137,6 +139,8 @@ export class Addition extends Region { export class Deletion extends Region { static origin = '-'; + static layerName = 'deletion'; + isDeletion() { return true; } @@ -149,6 +153,8 @@ export class Deletion extends Region { export class Unchanged extends Region { static origin = ' '; + static layerName = 'unchanged'; + isUnchanged() { return true; } @@ -165,6 +171,8 @@ export class Unchanged extends Region { export class NoNewline extends Region { static origin = '\\'; + static layerName = 'nonewline'; + isNoNewline() { return true; } diff --git a/test/builder/patch.js b/test/builder/patch.js index c2e0e830ab..6da24e5f29 100644 --- a/test/builder/patch.js +++ b/test/builder/patch.js @@ -1,6 +1,6 @@ // Builders for classes related to MultiFilePatches. -import {TextBuffer} from 'atom'; +import LayeredBuffer from '../../lib/models/patch/layered-buffer'; import MultiFilePatch from '../../lib/models/patch/multi-file-patch'; import FilePatch from '../../lib/models/patch/file-patch'; import File, {nullFile} from '../../lib/models/patch/file'; @@ -8,49 +8,29 @@ import Patch from '../../lib/models/patch/patch'; import Hunk from '../../lib/models/patch/hunk'; import {Unchanged, Addition, Deletion, NoNewline} from '../../lib/models/patch/region'; -class LayeredBuffer { - constructor() { - this.buffer = new TextBuffer(); - this.layers = ['patch', 'hunk', 'unchanged', 'addition', 'deletion', 'noNewline'].reduce((layers, name) => { - layers[name] = this.buffer.addMarkerLayer(); - return layers; - }, {}); - } - - getInsertionPoint() { - return this.buffer.getEndPosition(); - } - - getLayer(markerLayerName) { - const layer = this.layers[markerLayerName]; - if (!layer) { - throw new Error(`invalid marker layer name: ${markerLayerName}`); - } - return layer; - } - - appendMarked(markerLayerName, lines) { - const startPosition = this.buffer.getEndPosition(); - const layer = this.getLayer(markerLayerName); - this.buffer.append(lines.join('\n')); - const marker = layer.markRange([startPosition, this.buffer.getEndPosition()], {exclusive: true}); - this.buffer.append('\n'); - return marker; - } +function appendMarked(layeredBuffer, layerName, lines) { + const startPosition = layeredBuffer.getInsertionPoint(); + layeredBuffer.getBuffer().append(lines.join('\n')); + const marker = layeredBuffer.markRange( + layerName, + [startPosition, layeredBuffer.getInsertionPoint()], + {invalidate: 'never', exclusive: false}, + ); + layeredBuffer.getBuffer().append('\n'); + return marker; +} - markFrom(markerLayerName, startPosition) { - const endPosition = this.buffer.getEndPosition().translate([-1, Infinity]); - const layer = this.getLayer(markerLayerName); - return layer.markRange([startPosition, endPosition], {exclusive: true}); - } +function markFrom(layeredBuffer, layerName, startPosition) { + const endPosition = layeredBuffer.getInsertionPoint().translate([-1, Infinity]); + return layeredBuffer.markRange( + layerName, + [startPosition, endPosition], + {invalidate: 'never', exclusive: false}, + ); +} - wrapReturn(object) { - return { - buffer: this.buffer, - layers: this.layers, - ...object, - }; - } +function wrapReturn(layeredBuffer, object) { + return {buffer: layeredBuffer.getBuffer(), layers: layeredBuffer.getLayers(), ...object}; } class MultiFilePatchBuilder { @@ -68,10 +48,9 @@ class MultiFilePatchBuilder { } build() { - return this.layeredBuffer.wrapReturn({ + return wrapReturn(this.layeredBuffer, { multiFilePatch: new MultiFilePatch({ - buffer: this.layeredBuffer.buffer, - layers: this.layeredBuffer.layers, + layeredBuffer: this.layeredBuffer, filePatches: this.filePatches, }), }); @@ -229,9 +208,9 @@ class PatchBuilder { } } - const marker = this.layeredBuffer.markFrom('patch', this.patchStart); + const marker = markFrom(this.layeredBuffer, 'patch', this.patchStart); - return this.layeredBuffer.wrapReturn({ + return wrapReturn(this.layeredBuffer, { patch: new Patch({status: this._status, hunks: this.hunks, marker, renderStatus: this._renderStatus}), }); } @@ -259,22 +238,22 @@ class HunkBuilder { } unchanged(...lines) { - this.regions.push(new Unchanged(this.layeredBuffer.appendMarked('unchanged', lines))); + this.regions.push(new Unchanged(appendMarked(this.layeredBuffer, 'unchanged', lines))); return this; } added(...lines) { - this.regions.push(new Addition(this.layeredBuffer.appendMarked('addition', lines))); + this.regions.push(new Addition(appendMarked(this.layeredBuffer, 'addition', lines))); return this; } deleted(...lines) { - this.regions.push(new Deletion(this.layeredBuffer.appendMarked('deletion', lines))); + this.regions.push(new Deletion(appendMarked(this.layeredBuffer, 'deletion', lines))); return this; } noNewline() { - this.regions.push(new NoNewline(this.layeredBuffer.appendMarked('noNewline', [' No newline at end of file']))); + this.regions.push(new NoNewline(appendMarked(this.layeredBuffer, 'nonewline', [' No newline at end of file']))); return this; } @@ -303,9 +282,9 @@ class HunkBuilder { }), 0); } - const marker = this.layeredBuffer.markFrom('hunk', this.hunkStartPoint); + const marker = markFrom(this.layeredBuffer, 'hunk', this.hunkStartPoint); - return this.layeredBuffer.wrapReturn({ + return wrapReturn(this.layeredBuffer, { hunk: new Hunk({ oldStartRow: this.oldStartRow, oldRowCount: this.oldRowCount, diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index d917d8af36..75949de05e 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -885,7 +885,7 @@ describe('buildFilePatch', function() { ); }); - it('does not interfere with markers from surrounding patches when expanded', function() { + it('does not interfere with markers from surrounding visible patches when expanded', function() { const mfp = buildMultiFilePatch([ { oldPath: 'first', oldMode: '100644', newPath: 'first', newMode: '100644', status: 'modified', @@ -984,7 +984,7 @@ describe('buildFilePatch', function() { ); }); - it('preserves patch markers when a delayed patch is expanded', function() { + it('does not interfere with markers from surrounding non-visible patches when expanded', function() { const mfp = buildMultiFilePatch([ { oldPath: 'first', oldMode: '100644', newPath: 'first', newMode: '100644', status: 'modified', From f963e7510a14f6bf7015ad9e7694f852efa23246 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 17 Jan 2019 14:01:46 -0500 Subject: [PATCH 2634/4847] Rename LayeredBuffer to PatchBuffer --- lib/models/patch/builder.js | 46 +++++------ lib/models/patch/multi-file-patch.js | 28 +++---- .../{layered-buffer.js => patch-buffer.js} | 2 +- lib/models/patch/patch.js | 4 +- test/builder/patch.js | 80 +++++++++---------- 5 files changed, 80 insertions(+), 80 deletions(-) rename lib/models/patch/{layered-buffer.js => patch-buffer.js} (96%) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 6a308b2f7d..ab8c81109c 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -1,4 +1,4 @@ -import LayeredBuffer from './layered-buffer'; +import PatchBuffer from './patch-buffer'; import Hunk from './hunk'; import File, {nullFile} from './file'; import Patch, {TOO_LARGE, EXPANDED} from './patch'; @@ -18,26 +18,26 @@ const DEFAULT_OPTIONS = { export function buildFilePatch(diffs, options) { const opts = {...DEFAULT_OPTIONS, ...options}; - const layeredBuffer = new LayeredBuffer(); + const patchBuffer = new PatchBuffer(); let filePatch; if (diffs.length === 0) { filePatch = emptyDiffFilePatch(); } else if (diffs.length === 1) { - filePatch = singleDiffFilePatch(diffs[0], layeredBuffer, opts); + filePatch = singleDiffFilePatch(diffs[0], patchBuffer, opts); } else if (diffs.length === 2) { - filePatch = dualDiffFilePatch(diffs[0], diffs[1], layeredBuffer, opts); + filePatch = dualDiffFilePatch(diffs[0], diffs[1], patchBuffer, opts); } else { throw new Error(`Unexpected number of diffs: ${diffs.length}`); } - return new MultiFilePatch({layeredBuffer, filePatches: [filePatch]}); + return new MultiFilePatch({patchBuffer, filePatches: [filePatch]}); } export function buildMultiFilePatch(diffs, options) { const opts = {...DEFAULT_OPTIONS, ...options}; - const layeredBuffer = new LayeredBuffer(); + const patchBuffer = new PatchBuffer(); const byPath = new Map(); const actions = []; @@ -52,7 +52,7 @@ export function buildMultiFilePatch(diffs, options) { if (otherHalf) { // The second half. Complete the paired diff, or fail if they have unexpected statuses or modes. const [otherDiff, otherIndex] = otherHalf; - actions[otherIndex] = () => dualDiffFilePatch(diff, otherDiff, layeredBuffer, opts); + actions[otherIndex] = () => dualDiffFilePatch(diff, otherDiff, patchBuffer, opts); byPath.delete(thePath); } else { // The first half we've seen. @@ -60,14 +60,14 @@ export function buildMultiFilePatch(diffs, options) { index++; } } else { - actions[index] = () => singleDiffFilePatch(diff, layeredBuffer, opts); + actions[index] = () => singleDiffFilePatch(diff, patchBuffer, opts); index++; } } // Populate unpaired diffs that looked like they could be part of a pair, but weren't. for (const [unpairedDiff, originalIndex] of byPath.values()) { - actions[originalIndex] = () => singleDiffFilePatch(unpairedDiff, layeredBuffer, opts); + actions[originalIndex] = () => singleDiffFilePatch(unpairedDiff, patchBuffer, opts); } const filePatches = actions.map(action => action()); @@ -81,14 +81,14 @@ export function buildMultiFilePatch(diffs, options) { } }); - return new MultiFilePatch({layeredBuffer, filePatches}); + return new MultiFilePatch({patchBuffer, filePatches}); } function emptyDiffFilePatch() { return FilePatch.createNull(); } -function singleDiffFilePatch(diff, layeredBuffer, opts) { +function singleDiffFilePatch(diff, patchBuffer, opts) { const wasSymlink = diff.oldMode === File.modes.SYMLINK; const isSymlink = diff.newMode === File.modes.SYMLINK; @@ -120,8 +120,8 @@ function singleDiffFilePatch(diff, layeredBuffer, opts) { EXPANDED; if (renderStatus === TOO_LARGE) { - const insertRow = layeredBuffer.getBuffer().getLastRow(); - const patchMarker = layeredBuffer.markPosition( + const insertRow = patchBuffer.getBuffer().getLastRow(); + const patchMarker = patchBuffer.markPosition( Patch.layerName, [insertRow, 0], {invalidate: 'never', exclusive: false}, @@ -130,19 +130,19 @@ function singleDiffFilePatch(diff, layeredBuffer, opts) { return FilePatch.createDelayedFilePatch( oldFile, newFile, patchMarker, TOO_LARGE, () => { - const [hunks] = buildHunks(diff, layeredBuffer, insertRow, patchMarker); + const [hunks] = buildHunks(diff, patchBuffer, insertRow, patchMarker); return new Patch({status: diff.status, hunks, marker: patchMarker}); }, ); } else { - const [hunks, patchMarker] = buildHunks(diff, layeredBuffer, layeredBuffer.getBuffer().getLastRow()); + const [hunks, patchMarker] = buildHunks(diff, patchBuffer, patchBuffer.getBuffer().getLastRow()); const patch = new Patch({status: diff.status, hunks, marker: patchMarker}); return new FilePatch(oldFile, newFile, patch); } } -function dualDiffFilePatch(diff1, diff2, layeredBuffer, opts) { +function dualDiffFilePatch(diff1, diff2, patchBuffer, opts) { let modeChangeDiff, contentChangeDiff; if (diff1.oldMode === File.modes.SYMLINK || diff1.newMode === File.modes.SYMLINK) { modeChangeDiff = diff1; @@ -182,7 +182,7 @@ function dualDiffFilePatch(diff1, diff2, layeredBuffer, opts) { // TODO: do something with large diff too } - const [hunks, patchMarker] = buildHunks(contentChangeDiff, layeredBuffer, layeredBuffer.getBuffer().getLastRow()); + const [hunks, patchMarker] = buildHunks(contentChangeDiff, patchBuffer, patchBuffer.getBuffer().getLastRow()); const patch = new Patch({status, hunks, marker: patchMarker}); return new FilePatch(oldFile, newFile, patch); @@ -195,7 +195,7 @@ const CHANGEKIND = { '\\': NoNewline, }; -function buildHunks(diff, layeredBuffer, insertRow, existingMarker = null) { +function buildHunks(diff, patchBuffer, insertRow, existingMarker = null) { const hunks = []; const patchStartRow = insertRow; @@ -203,7 +203,7 @@ function buildHunks(diff, layeredBuffer, insertRow, existingMarker = null) { let nextLineLength = 0; if (diff.hunks.length === 0) { - const patchMarker = layeredBuffer.markPosition( + const patchMarker = patchBuffer.markPosition( Patch.layerName, [patchStartRow, 0], {invalidate: 'never', exclusive: true}, @@ -228,7 +228,7 @@ function buildHunks(diff, layeredBuffer, insertRow, existingMarker = null) { regions.push( new LastChangeKind( - layeredBuffer.markRange( + patchBuffer.markRange( LastChangeKind.layerName, [[currentRangeStart, 0], [bufferRow - 1, lastLineLength]], {invalidate: 'never', exclusive: false}, @@ -241,7 +241,7 @@ function buildHunks(diff, layeredBuffer, insertRow, existingMarker = null) { for (const lineText of hunkData.lines) { const bufferLine = lineText.slice(1) + '\n'; nextLineLength = lineText.length - 1; - layeredBuffer.getBuffer().insert([bufferRow, 0], bufferLine); + patchBuffer.getBuffer().insert([bufferRow, 0], bufferLine); const ChangeKind = CHANGEKIND[lineText[0]]; if (ChangeKind === undefined) { @@ -264,7 +264,7 @@ function buildHunks(diff, layeredBuffer, insertRow, existingMarker = null) { oldRowCount: hunkData.oldLineCount, newRowCount: hunkData.newLineCount, sectionHeading: hunkData.heading, - marker: layeredBuffer.markRange( + marker: patchBuffer.markRange( Hunk.layerName, [[bufferStartRow, 0], [bufferRow - 1, nextLineLength]], {invalidate: 'never', exclusive: false}, @@ -277,7 +277,7 @@ function buildHunks(diff, layeredBuffer, insertRow, existingMarker = null) { if (patchMarker) { patchMarker.setRange([[patchStartRow, 0], [bufferRow - 1, nextLineLength]], {exclusive: false}); } else { - patchMarker = layeredBuffer.markRange( + patchMarker = patchBuffer.markRange( Patch.layerName, [[patchStartRow, 0], [bufferRow - 1, nextLineLength]], {invalidate: 'never', exclusive: false}, diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 3e5a85c602..7d0a9ae8d4 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -1,16 +1,16 @@ import {Range} from 'atom'; import {RBTree} from 'bintrees'; -import LayeredBuffer from './layered-buffer'; +import PatchBuffer from './patch-buffer'; import {TOO_LARGE, COLLAPSED} from './patch'; export default class MultiFilePatch { static createNull() { - return new this({layeredBuffer: new LayeredBuffer(), filePatches: []}); + return new this({patchBuffer: new PatchBuffer(), filePatches: []}); } - constructor({layeredBuffer, filePatches}) { - this.layeredBuffer = layeredBuffer; + constructor({patchBuffer, filePatches}) { + this.patchBuffer = patchBuffer; this.filePatches = filePatches; this.filePatchesByMarker = new Map(); @@ -45,13 +45,13 @@ export default class MultiFilePatch { clone(opts = {}) { return new this.constructor({ - layeredBuffer: opts.layeredBuffer !== undefined ? opts.layeredBuffer : this.getLayeredBuffer(), + patchBuffer: opts.patchBuffer !== undefined ? opts.patchBuffer : this.getLayeredBuffer(), filePatches: opts.filePatches !== undefined ? opts.filePatches : this.getFilePatches(), }); } getLayeredBuffer() { - return this.layeredBuffer; + return this.patchBuffer; } getBuffer() { @@ -101,7 +101,7 @@ export default class MultiFilePatch { if (bufferRow < 0) { return undefined; } - const [marker] = this.layeredBuffer.findMarkers('patch', {intersectsRow: bufferRow}); + const [marker] = this.patchBuffer.findMarkers('patch', {intersectsRow: bufferRow}); return this.filePatchesByMarker.get(marker); } @@ -109,16 +109,16 @@ export default class MultiFilePatch { if (bufferRow < 0) { return undefined; } - const [marker] = this.layeredBuffer.findMarkers('hunk', {intersectsRow: bufferRow}); + const [marker] = this.patchBuffer.findMarkers('hunk', {intersectsRow: bufferRow}); return this.hunksByMarker.get(marker); } getStagePatchForLines(selectedLineSet) { - const nextLayeredBuffer = new LayeredBuffer(); + const nextLayeredBuffer = new PatchBuffer(); const nextFilePatches = this.getFilePatchesContaining(selectedLineSet).map(fp => { return fp.buildStagePatchForLines(this.getBuffer(), nextLayeredBuffer, selectedLineSet); }); - return this.clone({layeredBuffer: nextLayeredBuffer, filePatches: nextFilePatches}); + return this.clone({patchBuffer: nextLayeredBuffer, filePatches: nextFilePatches}); } getStagePatchForHunk(hunk) { @@ -126,11 +126,11 @@ export default class MultiFilePatch { } getUnstagePatchForLines(selectedLineSet) { - const nextLayeredBuffer = new LayeredBuffer(); + const nextLayeredBuffer = new PatchBuffer(); const nextFilePatches = this.getFilePatchesContaining(selectedLineSet).map(fp => { return fp.buildUnstagePatchForLines(this.getBuffer(), nextLayeredBuffer, selectedLineSet); }); - return this.clone({layeredBuffer: nextLayeredBuffer, filePatches: nextFilePatches}); + return this.clone({patchBuffer: nextLayeredBuffer, filePatches: nextFilePatches}); } getUnstagePatchForHunk(hunk) { @@ -235,7 +235,7 @@ export default class MultiFilePatch { } } - this.layeredBuffer = nextLayeredBuffer; + this.patchBuffer = nextLayeredBuffer; } /* @@ -262,7 +262,7 @@ export default class MultiFilePatch { } anyPresent() { - return this.layeredBuffer !== null && this.filePatches.some(fp => fp.isPresent()); + return this.patchBuffer !== null && this.filePatches.some(fp => fp.isPresent()); } didAnyChangeExecutableMode() { diff --git a/lib/models/patch/layered-buffer.js b/lib/models/patch/patch-buffer.js similarity index 96% rename from lib/models/patch/layered-buffer.js rename to lib/models/patch/patch-buffer.js index 2265ae7899..a6f1d0666f 100644 --- a/lib/models/patch/layered-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -2,7 +2,7 @@ import {TextBuffer} from 'atom'; const LAYER_NAMES = ['unchanged', 'addition', 'deletion', 'nonewline', 'hunk', 'patch']; -export default class LayeredBuffer { +export default class PatchBuffer { constructor() { this.buffer = new TextBuffer(); this.layers = LAYER_NAMES.reduce((map, layerName) => { diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index b5fc8209e5..129e23cfd3 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -75,8 +75,8 @@ export default class Patch { return this.marker.getRange().intersectsRow(row); } - reMarkOn(layeredBuffer) { - this.marker = layeredBuffer.markRange( + reMarkOn(patchBuffer) { + this.marker = patchBuffer.markRange( this.constructor.layerName, this.getRange(), {invalidate: 'never', exclusive: false}, diff --git a/test/builder/patch.js b/test/builder/patch.js index 6da24e5f29..cd8f45a79f 100644 --- a/test/builder/patch.js +++ b/test/builder/patch.js @@ -1,6 +1,6 @@ // Builders for classes related to MultiFilePatches. -import LayeredBuffer from '../../lib/models/patch/layered-buffer'; +import PatchBuffer from '../../lib/models/patch/patch-buffer'; import MultiFilePatch from '../../lib/models/patch/multi-file-patch'; import FilePatch from '../../lib/models/patch/file-patch'; import File, {nullFile} from '../../lib/models/patch/file'; @@ -8,49 +8,49 @@ import Patch from '../../lib/models/patch/patch'; import Hunk from '../../lib/models/patch/hunk'; import {Unchanged, Addition, Deletion, NoNewline} from '../../lib/models/patch/region'; -function appendMarked(layeredBuffer, layerName, lines) { - const startPosition = layeredBuffer.getInsertionPoint(); - layeredBuffer.getBuffer().append(lines.join('\n')); - const marker = layeredBuffer.markRange( +function appendMarked(patchBuffer, layerName, lines) { + const startPosition = patchBuffer.getInsertionPoint(); + patchBuffer.getBuffer().append(lines.join('\n')); + const marker = patchBuffer.markRange( layerName, - [startPosition, layeredBuffer.getInsertionPoint()], + [startPosition, patchBuffer.getInsertionPoint()], {invalidate: 'never', exclusive: false}, ); - layeredBuffer.getBuffer().append('\n'); + patchBuffer.getBuffer().append('\n'); return marker; } -function markFrom(layeredBuffer, layerName, startPosition) { - const endPosition = layeredBuffer.getInsertionPoint().translate([-1, Infinity]); - return layeredBuffer.markRange( +function markFrom(patchBuffer, layerName, startPosition) { + const endPosition = patchBuffer.getInsertionPoint().translate([-1, Infinity]); + return patchBuffer.markRange( layerName, [startPosition, endPosition], {invalidate: 'never', exclusive: false}, ); } -function wrapReturn(layeredBuffer, object) { - return {buffer: layeredBuffer.getBuffer(), layers: layeredBuffer.getLayers(), ...object}; +function wrapReturn(patchBuffer, object) { + return {buffer: patchBuffer.getBuffer(), layers: patchBuffer.getLayers(), ...object}; } class MultiFilePatchBuilder { - constructor(layeredBuffer = null) { - this.layeredBuffer = layeredBuffer; + constructor(patchBuffer = null) { + this.patchBuffer = patchBuffer; this.filePatches = []; } addFilePatch(block = () => {}) { - const filePatch = new FilePatchBuilder(this.layeredBuffer); + const filePatch = new FilePatchBuilder(this.patchBuffer); block(filePatch); this.filePatches.push(filePatch.build().filePatch); return this; } build() { - return wrapReturn(this.layeredBuffer, { + return wrapReturn(this.patchBuffer, { multiFilePatch: new MultiFilePatch({ - layeredBuffer: this.layeredBuffer, + patchBuffer: this.patchBuffer, filePatches: this.filePatches, }), }); @@ -58,13 +58,13 @@ class MultiFilePatchBuilder { } class FilePatchBuilder { - constructor(layeredBuffer = null) { - this.layeredBuffer = layeredBuffer; + constructor(patchBuffer = null) { + this.patchBuffer = patchBuffer; this.oldFile = new File({path: 'file', mode: File.modes.NORMAL}); this.newFile = null; - this.patchBuilder = new PatchBuilder(this.layeredBuffer); + this.patchBuilder = new PatchBuilder(this.patchBuffer); } setOldFile(block) { @@ -118,7 +118,7 @@ class FilePatchBuilder { this.newFile = this.oldFile.clone(); } - return this.layeredBuffer.wrapReturn({ + return this.patchBuffer.wrapReturn({ filePatch: new FilePatch(this.oldFile, this.newFile, patch), }); } @@ -156,14 +156,14 @@ class FileBuilder { } class PatchBuilder { - constructor(layeredBuffer = null) { - this.layeredBuffer = layeredBuffer; + constructor(patchBuffer = null) { + this.patchBuffer = patchBuffer; this._renderStatus = undefined; this._status = 'modified'; this.hunks = []; - this.patchStart = this.layeredBuffer.getInsertionPoint(); + this.patchStart = this.patchBuffer.getInsertionPoint(); this.drift = 0; this.explicitlyEmpty = false; } @@ -183,7 +183,7 @@ class PatchBuilder { } addHunk(block = () => {}) { - const builder = new HunkBuilder(this.layeredBuffer, this.drift); + const builder = new HunkBuilder(this.patchBuffer, this.drift); block(builder); const {hunk, drift} = builder.build(); this.hunks.push(hunk); @@ -208,17 +208,17 @@ class PatchBuilder { } } - const marker = markFrom(this.layeredBuffer, 'patch', this.patchStart); + const marker = markFrom(this.patchBuffer, 'patch', this.patchStart); - return wrapReturn(this.layeredBuffer, { + return wrapReturn(this.patchBuffer, { patch: new Patch({status: this._status, hunks: this.hunks, marker, renderStatus: this._renderStatus}), }); } } class HunkBuilder { - constructor(layeredBuffer = null, drift = 0) { - this.layeredBuffer = layeredBuffer; + constructor(patchBuffer = null, drift = 0) { + this.patchBuffer = patchBuffer; this.drift = drift; this.oldStartRow = 0; @@ -228,7 +228,7 @@ class HunkBuilder { this.sectionHeading = "don't care"; - this.hunkStartPoint = this.layeredBuffer.getInsertionPoint(); + this.hunkStartPoint = this.patchBuffer.getInsertionPoint(); this.regions = []; } @@ -238,22 +238,22 @@ class HunkBuilder { } unchanged(...lines) { - this.regions.push(new Unchanged(appendMarked(this.layeredBuffer, 'unchanged', lines))); + this.regions.push(new Unchanged(appendMarked(this.patchBuffer, 'unchanged', lines))); return this; } added(...lines) { - this.regions.push(new Addition(appendMarked(this.layeredBuffer, 'addition', lines))); + this.regions.push(new Addition(appendMarked(this.patchBuffer, 'addition', lines))); return this; } deleted(...lines) { - this.regions.push(new Deletion(appendMarked(this.layeredBuffer, 'deletion', lines))); + this.regions.push(new Deletion(appendMarked(this.patchBuffer, 'deletion', lines))); return this; } noNewline() { - this.regions.push(new NoNewline(appendMarked(this.layeredBuffer, 'nonewline', [' No newline at end of file']))); + this.regions.push(new NoNewline(appendMarked(this.patchBuffer, 'nonewline', [' No newline at end of file']))); return this; } @@ -282,9 +282,9 @@ class HunkBuilder { }), 0); } - const marker = markFrom(this.layeredBuffer, 'hunk', this.hunkStartPoint); + const marker = markFrom(this.patchBuffer, 'hunk', this.hunkStartPoint); - return wrapReturn(this.layeredBuffer, { + return wrapReturn(this.patchBuffer, { hunk: new Hunk({ oldStartRow: this.oldStartRow, oldRowCount: this.oldRowCount, @@ -300,17 +300,17 @@ class HunkBuilder { } export function multiFilePatchBuilder() { - return new MultiFilePatchBuilder(new LayeredBuffer()); + return new MultiFilePatchBuilder(new PatchBuffer()); } export function filePatchBuilder() { - return new FilePatchBuilder(new LayeredBuffer()); + return new FilePatchBuilder(new PatchBuffer()); } export function patchBuilder() { - return new PatchBuilder(new LayeredBuffer()); + return new PatchBuilder(new PatchBuffer()); } export function hunkBuilder() { - return new HunkBuilder(new LayeredBuffer()); + return new HunkBuilder(new PatchBuffer()); } From 6df1380f609d9784c9348f1cb29ec36fc565f786 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 17 Jan 2019 14:15:07 -0500 Subject: [PATCH 2635/4847] Begin an "atomic" (with respect to markers) Modification API --- lib/models/patch/patch-buffer.js | 37 ++++++++++- test/models/patch/patch-buffer.test.js | 86 ++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 test/models/patch/patch-buffer.test.js diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index a6f1d0666f..1ff655824f 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -1,4 +1,4 @@ -import {TextBuffer} from 'atom'; +import {TextBuffer, Range} from 'atom'; const LAYER_NAMES = ['unchanged', 'addition', 'deletion', 'nonewline', 'hunk', 'patch']; @@ -40,4 +40,39 @@ export default class PatchBuffer { this.layers[layerName].clear(); } } + + createModifier() { + return new Modification(this); + } +} + +class Modification { + constructor(patchBuffer) { + this.patchBuffer = patchBuffer; + this.markerBlueprints = []; + } + + append(text) { + this.patchBuffer.getBuffer().append(text); + } + + appendMarked(text, layerName, markerOpts) { + const start = this.patchBuffer.getBuffer().getEndPosition(); + this.append(text); + const end = this.patchBuffer.getBuffer().getEndPosition(); + this.markerBlueprints.push({layerName, range: new Range(start, end), markerOpts}); + return this; + } + + apply() { + for (const {layerName, range, markerOpts} of this.markerBlueprints) { + const callback = markerOpts.callback; + delete markerOpts.callback; + + const marker = this.patchBuffer.markRange(layerName, range, markerOpts); + if (callback) { + callback(marker); + } + } + } } diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js new file mode 100644 index 0000000000..135f32ba30 --- /dev/null +++ b/test/models/patch/patch-buffer.test.js @@ -0,0 +1,86 @@ +import dedent from 'dedent-js'; + +import PatchBuffer from '../../../lib/models/patch/patch-buffer'; + +describe('PatchBuffer', function() { + let patchBuffer; + + beforeEach(function() { + patchBuffer = new PatchBuffer(); + patchBuffer.getBuffer().setText(TEXT); + }); + + it('has simple accessors', function() { + assert.strictEqual(patchBuffer.getBuffer().getText(), TEXT); + assert.deepEqual(patchBuffer.getInsertionPoint().serialize(), [9, 4]); + }); + + it('creates and finds markers on specified layers', function() { + const patchMarker = patchBuffer.markRange('patch', [[1, 0], [2, 4]]); + const hunkMarker = patchBuffer.markRange('hunk', [[2, 0], [3, 4]]); + + assert.deepEqual(patchBuffer.findMarkers('patch', {}), [patchMarker]); + assert.deepEqual(patchBuffer.findMarkers('hunk', {}), [hunkMarker]); + }); + + it('clears markers from all layers at once', function() { + patchBuffer.markRange('patch', [[0, 0], [0, 4]]); + patchBuffer.markPosition('hunk', [0, 1]); + + patchBuffer.clearAllLayers(); + + assert.lengthOf(patchBuffer.findMarkers('patch', {}), 0); + assert.lengthOf(patchBuffer.findMarkers('hunk', {}), 0); + }); + + describe('deferred-marking modifications', function() { + it('performs multiple modifications and only creates markers at the end', function() { + const modifier = patchBuffer.createModifier(); + const cb0 = sinon.spy(); + const cb1 = sinon.spy(); + + modifier.append('0010\n'); + modifier.appendMarked('0011\n', 'patch', {invalidate: 'never', callback: cb0}); + modifier.append('0012\n'); + modifier.appendMarked('0013\n0014\n', 'hunk', {invalidate: 'surround', callback: cb1}); + + assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` + ${TEXT}0010 + 0011 + 0012 + 0013 + 0014 + + `); + + assert.isFalse(cb0.called); + assert.isFalse(cb1.called); + assert.lengthOf(patchBuffer.findMarkers('patch', {}), 0); + assert.lengthOf(patchBuffer.findMarkers('hunk', {}), 0); + + modifier.apply(); + + assert.lengthOf(patchBuffer.findMarkers('patch', {}), 1); + const [marker0] = patchBuffer.findMarkers('patch', {}); + assert.isTrue(cb0.calledWith(marker0)); + + assert.lengthOf(patchBuffer.findMarkers('hunk', {}), 1); + const [marker1] = patchBuffer.findMarkers('hunk', {}); + assert.isTrue(cb1.calledWith(marker1)); + }); + }); +}); + +const TEXT = dedent` + 0000 + 0001 + 0002 + 0003 + 0004 + 0005 + 0006 + 0007 + 0008 + 0009 + +`; From 3b340999f60a0d7f2973d84cbbab2bc5fe73ab36 Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 17 Jan 2019 12:06:06 -0800 Subject: [PATCH 2636/4847] import LARGE_DIFF_THRESHOLD --- lib/models/patch/builder.js | 2 +- test/models/patch/multi-file-patch.test.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index ab8c81109c..af0814e94e 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -6,7 +6,7 @@ import {Unchanged, Addition, Deletion, NoNewline} from './region'; import FilePatch from './file-patch'; import MultiFilePatch from './multi-file-patch'; -const DEFAULT_OPTIONS = { +export const DEFAULT_OPTIONS = { // Number of lines after which we consider the diff "large" // TODO: Set this based on performance measurements largeDiffThreshold: 100, diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index 61fa236f7a..b5e665da38 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -3,6 +3,7 @@ import dedent from 'dedent-js'; import {multiFilePatchBuilder, filePatchBuilder} from '../../builder/patch'; import {TOO_LARGE} from '../../../lib/models/patch/patch'; +import {DEFAULT_OPTIONS} from '../../../lib/models/patch/builder.js'; import MultiFilePatch from '../../../lib/models/patch/multi-file-patch'; import {assertInFilePatch} from '../../helpers'; @@ -709,6 +710,7 @@ describe('MultiFilePatch', function() { describe('isPatchTooLargeOrCollapsed', function() { let multiFilePatch; + const {largeDiffThreshold} = DEFAULT_OPTIONS; beforeEach(function() { multiFilePatch = multiFilePatchBuilder() .addFilePatch(fp => { From 49b406d5000e2e63ce5f4bca30b6e2bbdb68eb1a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 17 Jan 2019 14:59:28 -0500 Subject: [PATCH 2637/4847] Preserve Markers that begin or end at a Modification's insertion point --- lib/models/patch/patch-buffer.js | 57 ++++++++++++++++++++--- test/models/patch/patch-buffer.test.js | 63 +++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 9 deletions(-) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 1ff655824f..aec6b2493d 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -1,4 +1,4 @@ -import {TextBuffer, Range} from 'atom'; +import {TextBuffer, Range, Point} from 'atom'; const LAYER_NAMES = ['unchanged', 'addition', 'deletion', 'nonewline', 'hunk', 'patch']; @@ -41,25 +41,52 @@ export default class PatchBuffer { } } - createModifier() { - return new Modification(this); + createModifierAt(insertionPoint) { + return new Modification(this, Point.fromObject(insertionPoint)); + } + + createModifierAtEnd() { + return this.createModifierAt(this.getInsertionPoint()); } } class Modification { - constructor(patchBuffer) { + constructor(patchBuffer, insertionPoint) { this.patchBuffer = patchBuffer; + this.startPoint = insertionPoint.copy(); + this.insertionPoint = insertionPoint; this.markerBlueprints = []; + + this.markersBefore = new Set(); + this.markersAfter = new Set(); + } + + keepBefore(markers) { + for (const marker of markers) { + if (marker.getRange().end.isEqual(this.startPoint)) { + this.markersBefore.add(marker); + } + } + } + + keepAfter(markers) { + for (const marker of markers) { + if (marker.getRange().end.isEqual(this.startPoint)) { + this.markersAfter.add(marker); + } + } } append(text) { - this.patchBuffer.getBuffer().append(text); + const insertedRange = this.patchBuffer.getBuffer().insert(this.insertionPoint, text); + this.insertionPoint = insertedRange.end; + return this; } appendMarked(text, layerName, markerOpts) { - const start = this.patchBuffer.getBuffer().getEndPosition(); + const start = this.insertionPoint.copy(); this.append(text); - const end = this.patchBuffer.getBuffer().getEndPosition(); + const end = this.insertionPoint.copy(); this.markerBlueprints.push({layerName, range: new Range(start, end), markerOpts}); return this; } @@ -74,5 +101,21 @@ class Modification { callback(marker); } } + + for (const beforeMarker of this.markersBefore) { + if (!beforeMarker.isReversed()) { + beforeMarker.setHeadPosition(this.startPoint); + } else { + beforeMarker.setTailPosition(this.startPoint); + } + } + + for (const afterMarker of this.markersAfter) { + if (!afterMarker.isReversed()) { + afterMarker.setTailPosition(this.insertionPoint); + } else { + afterMarker.setHeadPosition(this.insertionPoint); + } + } } } diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index 135f32ba30..102ed2d409 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -12,7 +12,7 @@ describe('PatchBuffer', function() { it('has simple accessors', function() { assert.strictEqual(patchBuffer.getBuffer().getText(), TEXT); - assert.deepEqual(patchBuffer.getInsertionPoint().serialize(), [9, 4]); + assert.deepEqual(patchBuffer.getInsertionPoint().serialize(), [10, 0]); }); it('creates and finds markers on specified layers', function() { @@ -35,7 +35,7 @@ describe('PatchBuffer', function() { describe('deferred-marking modifications', function() { it('performs multiple modifications and only creates markers at the end', function() { - const modifier = patchBuffer.createModifier(); + const modifier = patchBuffer.createModifierAtEnd(); const cb0 = sinon.spy(); const cb1 = sinon.spy(); @@ -68,6 +68,65 @@ describe('PatchBuffer', function() { const [marker1] = patchBuffer.findMarkers('hunk', {}); assert.isTrue(cb1.calledWith(marker1)); }); + + it('inserts into the middle of an existing buffer', function() { + const modifier = patchBuffer.createModifierAt([4, 2]); + const callback = sinon.spy(); + + modifier.append('aa\nbbbb\n'); + modifier.appendMarked('-patch-\n-patch-\n', 'patch', {callback}); + modifier.appendMarked('-hunk-\ndd', 'hunk', {}); + + assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` + 0000 + 0001 + 0002 + 0003 + 00aa + bbbb + -patch- + -patch- + -hunk- + dd04 + 0005 + 0006 + 0007 + 0008 + 0009 + + `); + + assert.lengthOf(patchBuffer.findMarkers('patch', {}), 0); + assert.lengthOf(patchBuffer.findMarkers('hunk', {}), 0); + assert.isFalse(callback.called); + + modifier.apply(); + + assert.lengthOf(patchBuffer.findMarkers('patch', {}), 1); + const [marker] = patchBuffer.findMarkers('patch', {}); + assert.isTrue(callback.calledWith(marker)); + }); + + it('preserves markers that should be before or after the modification region', function() { + const before0 = patchBuffer.markRange('patch', [[1, 0], [4, 0]]); + const before1 = patchBuffer.markPosition('hunk', [4, 0]); + const after0 = patchBuffer.markPosition('patch', [4, 0]); + + const modifier = patchBuffer.createModifierAt([4, 0]); + modifier.keepBefore([before0, before1]); + modifier.keepAfter([after0]); + + let marker = null; + const callback = m => { marker = m; }; + modifier.appendMarked('A\nB\nC\nD\nE\n', 'addition', {callback}); + + modifier.apply(); + + assert.deepEqual(before0.getRange().serialize(), [[1, 0], [4, 0]]); + assert.deepEqual(before1.getRange().serialize(), [[4, 0], [4, 0]]); + assert.deepEqual(marker.getRange().serialize(), [[4, 0], [9, 0]]); + assert.deepEqual(after0.getRange().serialize(), [[9, 0], [9, 0]]); + }); }); }); From a2d453c41b9742f385dc1a4e03d7c0ad6b4169ca Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 17 Jan 2019 16:12:11 -0500 Subject: [PATCH 2638/4847] PatchBuffer::extract() to slice a Range out and preserve its markers --- lib/models/patch/patch-buffer.js | 27 ++++++++++++++++ test/models/patch/patch-buffer.test.js | 45 ++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index aec6b2493d..d827c97974 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -48,6 +48,33 @@ export default class PatchBuffer { createModifierAtEnd() { return this.createModifierAt(this.getInsertionPoint()); } + + extract(rangeLike) { + const range = Range.fromObject(rangeLike); + const movedMarkersByLayer = LAYER_NAMES.reduce((map, layerName) => { + map[layerName] = this.layers[layerName].findMarkers({containedInRange: range}); + return map; + }, {}); + const markerMap = new Map(); + + const subBuffer = new PatchBuffer(); + subBuffer.getBuffer().setText(this.buffer.getTextInRange(range)); + + for (const layerName of LAYER_NAMES) { + for (const oldMarker of movedMarkersByLayer[layerName]) { + const newMarker = subBuffer.markRange( + layerName, + oldMarker.getRange().translate(range.start.negate()), + oldMarker.getProperties(), + ); + markerMap.set(oldMarker, newMarker); + oldMarker.destroy(); + } + } + + this.buffer.setTextInRange(range, ''); + return subBuffer; + } } class Modification { diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index 102ed2d409..c9759fc197 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -33,6 +33,51 @@ describe('PatchBuffer', function() { assert.lengthOf(patchBuffer.findMarkers('hunk', {}), 0); }); + it('extracts a subset of the buffer and layers as a new LayeredBuffer', function() { + patchBuffer.markRange('patch', [[1, 0], [3, 0]]); // before + patchBuffer.markRange('hunk', [[2, 0], [4, 0]]); // before, ending at the extraction point + patchBuffer.markRange('hunk', [[4, 0], [5, 0]]); // within + patchBuffer.markRange('patch', [[6, 0], [7, 0]]); // within + patchBuffer.markRange('hunk', [[7, 0], [9, 0]]); // after, starting at the extraction point + patchBuffer.markRange('patch', [[8, 0], [10, 0]]); // after + + const subPatchBuffer = patchBuffer.extract([[4, 0], [7, 0]]); + + assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` + 0000 + 0001 + 0002 + 0003 + 0007 + 0008 + 0009 + + `); + assert.deepEqual( + patchBuffer.findMarkers('patch', {}).map(m => m.getRange().serialize()), + [[[1, 0], [3, 0]], [[5, 0], [7, 0]]], + ); + assert.deepEqual( + patchBuffer.findMarkers('hunk', {}).map(m => m.getRange().serialize()), + [[[2, 0], [4, 0]], [[4, 0], [6, 0]]], + ); + + assert.strictEqual(subPatchBuffer.getBuffer().getText(), dedent` + 0004 + 0005 + 0006 + + `); + assert.deepEqual( + subPatchBuffer.findMarkers('hunk', {}).map(m => m.getRange().serialize()), + [[[0, 0], [1, 0]]], + ); + assert.deepEqual( + subPatchBuffer.findMarkers('patch', {}).map(m => m.getRange().serialize()), + [[[2, 0], [3, 0]]], + ); + }); + describe('deferred-marking modifications', function() { it('performs multiple modifications and only creates markers at the end', function() { const modifier = patchBuffer.createModifierAtEnd(); From 34e104af8af8e56bc644cf6eb5d5ac47c4999e7b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 17 Jan 2019 16:29:31 -0500 Subject: [PATCH 2639/4847] Unit test for inserting one PatchBuffer into another --- test/models/patch/patch-buffer.test.js | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index c9759fc197..5c9f697031 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -172,6 +172,61 @@ describe('PatchBuffer', function() { assert.deepEqual(marker.getRange().serialize(), [[4, 0], [9, 0]]); assert.deepEqual(after0.getRange().serialize(), [[9, 0], [9, 0]]); }); + + it('appends another PatchBuffer at its insertion point', function() { + const subPatchBuffer = new PatchBuffer(); + subPatchBuffer.getBuffer().setText(dedent` + aaaa + bbbb + cc + `); + + subPatchBuffer.markPosition('patch', [0, 0]); + subPatchBuffer.markRange('hunk', [[0, 0], [1, 4]]); + subPatchBuffer.markRange('addition', [[1, 2], [2, 2]]); + + const mBefore = patchBuffer.markRange('deletion', [[0, 0], [2, 0]]); + const mAfter = patchBuffer.markRange('deletion', [[7, 0], [7, 4]]); + + patchBuffer + .createModifierAt([3, 2]) + .appendPatchBuffer(subPatchBuffer) + .apply(); + + assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` + 0000 + 0001 + 0002 + 00aaaa + bbbb + cc03 + 0004 + 0005 + 0006 + 0007 + 0008 + 0009 + + `); + + assert.deepEqual(mBefore.getRange().serialize(), [[0, 0], [2, 0]]); + assert.deepEqual(mAfter.getRange().serialize(), [[9, 0], [9, 4]]); + + assert.deepEqual( + patchBuffer.findMarkers('patch', {}).map(m => m.getRange().serialize()), + [[[3, 2], [3, 2]]], + ); + + assert.deepEqual( + patchBuffer.findMarkers('hunk', {}).map(m => m.getRange().serialize()), + [[[3, 2], [4, 4]]], + ); + + assert.deepEqual( + patchBuffer.findMarkers('addition', {}).map(m => m.getRange().serialize()), + [[[4, 2], [5, 2]]], + ); + }); }); }); From dfc2fee53c5e4a10337a748297b6f9a96227050a Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 17 Jan 2019 16:08:03 -0800 Subject: [PATCH 2640/4847] actually trigger expanding and collapsing from `FilePatchHeaderView` --- lib/models/patch/file-patch.js | 4 ++-- lib/views/file-patch-header-view.js | 15 +++++++++++++-- lib/views/multi-file-patch-view.js | 6 +++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index 362f630ae2..7c76d6a0e9 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -127,7 +127,7 @@ export default class FilePatch { } } - triggerCollapse() { + triggerCollapse = () => { const nextPatch = this.patch.collapsed(); if (nextPatch !== this.patch) { this.patch = nextPatch; @@ -135,7 +135,7 @@ export default class FilePatch { } } - triggerExpand() { + triggerExpand = () => { const nextPatch = this.patch.expanded(); if (nextPatch !== this.patch) { this.patch = nextPatch; diff --git a/lib/views/file-patch-header-view.js b/lib/views/file-patch-header-view.js index a78b931750..ae10db1fde 100644 --- a/lib/views/file-patch-header-view.js +++ b/lib/views/file-patch-header-view.js @@ -29,9 +29,12 @@ export default class FilePatchHeaderView extends React.Component { // should probably change 'toggleFile' to 'toggleFileStagingStatus' // because the addition of another toggling function makes the old name confusing. toggleFile: PropTypes.func.isRequired, - toggleFileCollapse: PropTypes.func, itemType: ItemTypePropType.isRequired, + + isCollapsed: PropTypes.bool.isRequired, + triggerExpand: PropTypes.func.isRequired, + triggerCollapse: PropTypes.func.isRequired, }; constructor(props) { @@ -53,11 +56,19 @@ export default class FilePatchHeaderView extends React.Component { ); } + togglePatchCollapse = () => { + if (this.props.isCollapsed) { + this.props.triggerExpand(); + } else { + this.props.triggerCollapse(); + } + } + renderCollapseButton() { return ( ); diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 5554ac910c..5bb93e7c7b 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -22,7 +22,7 @@ import CommitDetailItem from '../items/commit-detail-item'; import IssueishDetailItem from '../items/issueish-detail-item'; import File from '../models/patch/file'; -import {TOO_LARGE} from '../models/patch/patch'; +import {TOO_LARGE, COLLAPSED} from '../models/patch/patch'; const executableText = { [File.modes.NORMAL]: 'non executable', @@ -350,6 +350,10 @@ export default class MultiFilePatchView extends React.Component { diveIntoMirrorPatch={() => this.props.diveIntoMirrorPatch(filePatch)} openFile={() => this.didOpenFile({selectedFilePatch: filePatch})} toggleFile={() => this.props.toggleFile(filePatch)} + + isCollapsed={filePatch.getRenderStatus === TOO_LARGE || filePatch.getRenderStatus === COLLAPSED} + triggerCollapse={filePatch.triggerCollapse} + triggerExpand={filePatch.triggerExpand} /> {this.renderSymlinkChangeMeta(filePatch)} {this.renderExecutableModeChangeMeta(filePatch)} From ebdec242ceaf3860f1ebae2c27387e5763f24c11 Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 17 Jan 2019 17:04:27 -0800 Subject: [PATCH 2641/4847] change the chevron icon direction depending on collapsed prop --- lib/views/file-patch-header-view.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/views/file-patch-header-view.js b/lib/views/file-patch-header-view.js index ae10db1fde..56ba16c466 100644 --- a/lib/views/file-patch-header-view.js +++ b/lib/views/file-patch-header-view.js @@ -65,11 +65,12 @@ export default class FilePatchHeaderView extends React.Component { } renderCollapseButton() { + const icon = this.props.isCollapsed ? 'chevron-up' : 'chevron-down'; return ( ); } From 7290720ff5c37440c1276a7fae6b2283d77ef585 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 18 Jan 2019 10:48:16 +0900 Subject: [PATCH 2642/4847] Add inline diff mockup --- docs/feature-requests/003-pull-request-review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index eb03b8e8e2..3802a51dbb 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -142,7 +142,7 @@ Clicking on a review comment opens a `TextEditor` on the corresponding position If an open `TextEditor` corresponds to a file that has one or more review comments in an open `PullRequestReviewsItem`, gutter and line decorations are added to the lines that match those review comment positions. The "current" one is styled differently to stand out. -> TODO: Illustrate the "review comment here" gutter and line decorations +![inline diff](https://user-images.githubusercontent.com/378023/51360052-68e6ed00-1b0d-11e9-852e-a51cff4d479e.png) Clicking on the gutter icon reveals the `PullRequestReviewsItem` and highlights that review comment as the "current" one, scrolling to it and expanding its review if necessary. From 01b82f0e23cd22fb4afb6c8571a2f789b3a8fd58 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 18 Jan 2019 13:19:32 -0500 Subject: [PATCH 2643/4847] Implement appendPatchBuffer() --- lib/models/patch/patch-buffer.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index d827c97974..7ec517a7a8 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -118,6 +118,28 @@ class Modification { return this; } + appendPatchBuffer(subPatchBuffer) { + const baseOffset = this.insertionPoint.copy(); + this.append(subPatchBuffer.getBuffer().getText()); + + const subMarkerMap = new Map(); + for (const layerName of LAYER_NAMES) { + for (const oldMarker of subPatchBuffer.findMarkers(layerName, {})) { + const startOffset = oldMarker.getRange().start.row === 0 ? baseOffset : [baseOffset.row, 0]; + const endOffset = oldMarker.getRange().end.row === 0 ? baseOffset : [baseOffset.row, 0]; + + const range = oldMarker.getRange().translate(startOffset, endOffset); + const markerOpts = { + ...oldMarker.getProperties(), + callback: newMarker => { subMarkerMap.set(oldMarker, newMarker); }, + }; + this.markerBlueprints.push({layerName, range, markerOpts}); + } + } + + return this; + } + apply() { for (const {layerName, range, markerOpts} of this.markerBlueprints) { const callback = markerOpts.callback; From 2d7c2f465733717e66c7fca9e7d62267f5a35876 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 18 Jan 2019 13:50:14 -0500 Subject: [PATCH 2644/4847] Translate Markers when extracting and appending PatchBuffers midline --- lib/models/patch/patch-buffer.js | 5 ++++- test/models/patch/patch-buffer.test.js | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 7ec517a7a8..d1ed781035 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -51,6 +51,7 @@ export default class PatchBuffer { extract(rangeLike) { const range = Range.fromObject(rangeLike); + const baseOffset = range.start.negate(); const movedMarkersByLayer = LAYER_NAMES.reduce((map, layerName) => { map[layerName] = this.layers[layerName].findMarkers({containedInRange: range}); return map; @@ -62,9 +63,11 @@ export default class PatchBuffer { for (const layerName of LAYER_NAMES) { for (const oldMarker of movedMarkersByLayer[layerName]) { + const startOffset = oldMarker.getRange().start.row === range.start.row ? baseOffset : [baseOffset.row, 0]; + const endOffset = oldMarker.getRange().end.row === range.start.row ? baseOffset : [baseOffset.row, 0]; const newMarker = subBuffer.markRange( layerName, - oldMarker.getRange().translate(range.start.negate()), + oldMarker.getRange().translate(startOffset, endOffset), oldMarker.getProperties(), ); markerMap.set(oldMarker, newMarker); diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index 5c9f697031..5256c1c6c6 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -35,20 +35,20 @@ describe('PatchBuffer', function() { it('extracts a subset of the buffer and layers as a new LayeredBuffer', function() { patchBuffer.markRange('patch', [[1, 0], [3, 0]]); // before - patchBuffer.markRange('hunk', [[2, 0], [4, 0]]); // before, ending at the extraction point - patchBuffer.markRange('hunk', [[4, 0], [5, 0]]); // within - patchBuffer.markRange('patch', [[6, 0], [7, 0]]); // within - patchBuffer.markRange('hunk', [[7, 0], [9, 0]]); // after, starting at the extraction point + patchBuffer.markRange('hunk', [[2, 0], [4, 2]]); // before, ending at the extraction point + patchBuffer.markRange('hunk', [[4, 2], [5, 0]]); // within + patchBuffer.markRange('patch', [[6, 0], [7, 1]]); // within + patchBuffer.markRange('hunk', [[7, 1], [9, 0]]); // after, starting at the extraction point patchBuffer.markRange('patch', [[8, 0], [10, 0]]); // after - const subPatchBuffer = patchBuffer.extract([[4, 0], [7, 0]]); + const subPatchBuffer = patchBuffer.extract([[4, 2], [7, 1]]); assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` 0000 0001 0002 0003 - 0007 + 00007 0008 0009 @@ -59,14 +59,14 @@ describe('PatchBuffer', function() { ); assert.deepEqual( patchBuffer.findMarkers('hunk', {}).map(m => m.getRange().serialize()), - [[[2, 0], [4, 0]], [[4, 0], [6, 0]]], + [[[2, 0], [4, 2]], [[4, 2], [6, 0]]], ); assert.strictEqual(subPatchBuffer.getBuffer().getText(), dedent` - 0004 + 04 0005 0006 - + 0 `); assert.deepEqual( subPatchBuffer.findMarkers('hunk', {}).map(m => m.getRange().serialize()), @@ -74,7 +74,7 @@ describe('PatchBuffer', function() { ); assert.deepEqual( subPatchBuffer.findMarkers('patch', {}).map(m => m.getRange().serialize()), - [[[2, 0], [3, 0]]], + [[[2, 0], [3, 1]]], ); }); From 03e03f342d58df1c664dab704e5ccd7d1026a7e6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 18 Jan 2019 13:55:26 -0500 Subject: [PATCH 2645/4847] Renamings --- lib/models/patch/patch-buffer.js | 12 ++++----- test/models/patch/patch-buffer.test.js | 36 +++++++++++++------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index d1ed781035..4177d33ef0 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -41,15 +41,15 @@ export default class PatchBuffer { } } - createModifierAt(insertionPoint) { - return new Modification(this, Point.fromObject(insertionPoint)); + createInserterAt(insertionPoint) { + return new Inserter(this, Point.fromObject(insertionPoint)); } - createModifierAtEnd() { - return this.createModifierAt(this.getInsertionPoint()); + createInserterAtEnd() { + return this.createInserterAt(this.getInsertionPoint()); } - extract(rangeLike) { + extractPatchBuffer(rangeLike) { const range = Range.fromObject(rangeLike); const baseOffset = range.start.negate(); const movedMarkersByLayer = LAYER_NAMES.reduce((map, layerName) => { @@ -80,7 +80,7 @@ export default class PatchBuffer { } } -class Modification { +class Inserter { constructor(patchBuffer, insertionPoint) { this.patchBuffer = patchBuffer; this.startPoint = insertionPoint.copy(); diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index 5256c1c6c6..3efc44a53c 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -41,7 +41,7 @@ describe('PatchBuffer', function() { patchBuffer.markRange('hunk', [[7, 1], [9, 0]]); // after, starting at the extraction point patchBuffer.markRange('patch', [[8, 0], [10, 0]]); // after - const subPatchBuffer = patchBuffer.extract([[4, 2], [7, 1]]); + const subPatchBuffer = patchBuffer.extractPatchBuffer([[4, 2], [7, 1]]); assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` 0000 @@ -80,14 +80,14 @@ describe('PatchBuffer', function() { describe('deferred-marking modifications', function() { it('performs multiple modifications and only creates markers at the end', function() { - const modifier = patchBuffer.createModifierAtEnd(); + const inserter = patchBuffer.createInserterAtEnd(); const cb0 = sinon.spy(); const cb1 = sinon.spy(); - modifier.append('0010\n'); - modifier.appendMarked('0011\n', 'patch', {invalidate: 'never', callback: cb0}); - modifier.append('0012\n'); - modifier.appendMarked('0013\n0014\n', 'hunk', {invalidate: 'surround', callback: cb1}); + inserter.append('0010\n'); + inserter.appendMarked('0011\n', 'patch', {invalidate: 'never', callback: cb0}); + inserter.append('0012\n'); + inserter.appendMarked('0013\n0014\n', 'hunk', {invalidate: 'surround', callback: cb1}); assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` ${TEXT}0010 @@ -103,7 +103,7 @@ describe('PatchBuffer', function() { assert.lengthOf(patchBuffer.findMarkers('patch', {}), 0); assert.lengthOf(patchBuffer.findMarkers('hunk', {}), 0); - modifier.apply(); + inserter.apply(); assert.lengthOf(patchBuffer.findMarkers('patch', {}), 1); const [marker0] = patchBuffer.findMarkers('patch', {}); @@ -115,12 +115,12 @@ describe('PatchBuffer', function() { }); it('inserts into the middle of an existing buffer', function() { - const modifier = patchBuffer.createModifierAt([4, 2]); + const inserter = patchBuffer.createInserterAt([4, 2]); const callback = sinon.spy(); - modifier.append('aa\nbbbb\n'); - modifier.appendMarked('-patch-\n-patch-\n', 'patch', {callback}); - modifier.appendMarked('-hunk-\ndd', 'hunk', {}); + inserter.append('aa\nbbbb\n'); + inserter.appendMarked('-patch-\n-patch-\n', 'patch', {callback}); + inserter.appendMarked('-hunk-\ndd', 'hunk', {}); assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` 0000 @@ -145,7 +145,7 @@ describe('PatchBuffer', function() { assert.lengthOf(patchBuffer.findMarkers('hunk', {}), 0); assert.isFalse(callback.called); - modifier.apply(); + inserter.apply(); assert.lengthOf(patchBuffer.findMarkers('patch', {}), 1); const [marker] = patchBuffer.findMarkers('patch', {}); @@ -157,15 +157,15 @@ describe('PatchBuffer', function() { const before1 = patchBuffer.markPosition('hunk', [4, 0]); const after0 = patchBuffer.markPosition('patch', [4, 0]); - const modifier = patchBuffer.createModifierAt([4, 0]); - modifier.keepBefore([before0, before1]); - modifier.keepAfter([after0]); + const inserter = patchBuffer.createInserterAt([4, 0]); + inserter.keepBefore([before0, before1]); + inserter.keepAfter([after0]); let marker = null; const callback = m => { marker = m; }; - modifier.appendMarked('A\nB\nC\nD\nE\n', 'addition', {callback}); + inserter.appendMarked('A\nB\nC\nD\nE\n', 'addition', {callback}); - modifier.apply(); + inserter.apply(); assert.deepEqual(before0.getRange().serialize(), [[1, 0], [4, 0]]); assert.deepEqual(before1.getRange().serialize(), [[4, 0], [4, 0]]); @@ -189,7 +189,7 @@ describe('PatchBuffer', function() { const mAfter = patchBuffer.markRange('deletion', [[7, 0], [7, 4]]); patchBuffer - .createModifierAt([3, 2]) + .createInserterAt([3, 2]) .appendPatchBuffer(subPatchBuffer) .apply(); From 400d1b821d94dc49fb844cbd9dd7c4bf9a9e49b2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 18 Jan 2019 13:57:30 -0500 Subject: [PATCH 2646/4847] Rename Inserter methods as "insert..." instead of "append..." --- lib/models/patch/patch-buffer.js | 10 +++++----- test/models/patch/patch-buffer.test.js | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 4177d33ef0..4852742825 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -107,23 +107,23 @@ class Inserter { } } - append(text) { + insert(text) { const insertedRange = this.patchBuffer.getBuffer().insert(this.insertionPoint, text); this.insertionPoint = insertedRange.end; return this; } - appendMarked(text, layerName, markerOpts) { + insertMarked(text, layerName, markerOpts) { const start = this.insertionPoint.copy(); - this.append(text); + this.insert(text); const end = this.insertionPoint.copy(); this.markerBlueprints.push({layerName, range: new Range(start, end), markerOpts}); return this; } - appendPatchBuffer(subPatchBuffer) { + insertPatchBuffer(subPatchBuffer) { const baseOffset = this.insertionPoint.copy(); - this.append(subPatchBuffer.getBuffer().getText()); + this.insert(subPatchBuffer.getBuffer().getText()); const subMarkerMap = new Map(); for (const layerName of LAYER_NAMES) { diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index 3efc44a53c..570143f87d 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -84,10 +84,10 @@ describe('PatchBuffer', function() { const cb0 = sinon.spy(); const cb1 = sinon.spy(); - inserter.append('0010\n'); - inserter.appendMarked('0011\n', 'patch', {invalidate: 'never', callback: cb0}); - inserter.append('0012\n'); - inserter.appendMarked('0013\n0014\n', 'hunk', {invalidate: 'surround', callback: cb1}); + inserter.insert('0010\n'); + inserter.insertMarked('0011\n', 'patch', {invalidate: 'never', callback: cb0}); + inserter.insert('0012\n'); + inserter.insertMarked('0013\n0014\n', 'hunk', {invalidate: 'surround', callback: cb1}); assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` ${TEXT}0010 @@ -118,9 +118,9 @@ describe('PatchBuffer', function() { const inserter = patchBuffer.createInserterAt([4, 2]); const callback = sinon.spy(); - inserter.append('aa\nbbbb\n'); - inserter.appendMarked('-patch-\n-patch-\n', 'patch', {callback}); - inserter.appendMarked('-hunk-\ndd', 'hunk', {}); + inserter.insert('aa\nbbbb\n'); + inserter.insertMarked('-patch-\n-patch-\n', 'patch', {callback}); + inserter.insertMarked('-hunk-\ndd', 'hunk', {}); assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` 0000 @@ -163,7 +163,7 @@ describe('PatchBuffer', function() { let marker = null; const callback = m => { marker = m; }; - inserter.appendMarked('A\nB\nC\nD\nE\n', 'addition', {callback}); + inserter.insertMarked('A\nB\nC\nD\nE\n', 'addition', {callback}); inserter.apply(); @@ -190,7 +190,7 @@ describe('PatchBuffer', function() { patchBuffer .createInserterAt([3, 2]) - .appendPatchBuffer(subPatchBuffer) + .insertPatchBuffer(subPatchBuffer) .apply(); assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` From 37f9ae6cb1f991f5119b7c4767b06ce1750e0783 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 18 Jan 2019 14:13:53 -0500 Subject: [PATCH 2647/4847] Produce Maps of equivalent Markers after extract/insert PatchBuffers --- lib/models/patch/patch-buffer.js | 8 +++-- test/models/patch/patch-buffer.test.js | 44 ++++++++++++++++++-------- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 4852742825..19c7979c7d 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -76,7 +76,7 @@ export default class PatchBuffer { } this.buffer.setTextInRange(range, ''); - return subBuffer; + return {patchBuffer: subBuffer, markerMap}; } } @@ -121,7 +121,7 @@ class Inserter { return this; } - insertPatchBuffer(subPatchBuffer) { + insertPatchBuffer(subPatchBuffer, opts) { const baseOffset = this.insertionPoint.copy(); this.insert(subPatchBuffer.getBuffer().getText()); @@ -140,6 +140,10 @@ class Inserter { } } + if (opts.callback) { + opts.callback(subMarkerMap); + } + return this; } diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index 570143f87d..75a7de3b2e 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -34,14 +34,14 @@ describe('PatchBuffer', function() { }); it('extracts a subset of the buffer and layers as a new LayeredBuffer', function() { - patchBuffer.markRange('patch', [[1, 0], [3, 0]]); // before - patchBuffer.markRange('hunk', [[2, 0], [4, 2]]); // before, ending at the extraction point - patchBuffer.markRange('hunk', [[4, 2], [5, 0]]); // within - patchBuffer.markRange('patch', [[6, 0], [7, 1]]); // within - patchBuffer.markRange('hunk', [[7, 1], [9, 0]]); // after, starting at the extraction point - patchBuffer.markRange('patch', [[8, 0], [10, 0]]); // after + const m0 = patchBuffer.markRange('patch', [[1, 0], [3, 0]]); // before + const m1 = patchBuffer.markRange('hunk', [[2, 0], [4, 2]]); // before, ending at the extraction point + const m2 = patchBuffer.markRange('hunk', [[4, 2], [5, 0]]); // within + const m3 = patchBuffer.markRange('patch', [[6, 0], [7, 1]]); // within + const m4 = patchBuffer.markRange('hunk', [[7, 1], [9, 0]]); // after, starting at the extraction point + const m5 = patchBuffer.markRange('patch', [[8, 0], [10, 0]]); // after - const subPatchBuffer = patchBuffer.extractPatchBuffer([[4, 2], [7, 1]]); + const {patchBuffer: subPatchBuffer, markerMap} = patchBuffer.extractPatchBuffer([[4, 2], [7, 1]]); assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` 0000 @@ -61,6 +61,17 @@ describe('PatchBuffer', function() { patchBuffer.findMarkers('hunk', {}).map(m => m.getRange().serialize()), [[[2, 0], [4, 2]], [[4, 2], [6, 0]]], ); + assert.deepEqual(m0.getRange().serialize(), [[1, 0], [3, 0]]); + assert.deepEqual(m1.getRange().serialize(), [[2, 0], [4, 2]]); + assert.isTrue(m2.isDestroyed()); + assert.isTrue(m3.isDestroyed()); + assert.deepEqual(m4.getRange().serialize(), [[4, 2], [6, 0]]); + assert.deepEqual(m5.getRange().serialize(), [[5, 0], [7, 0]]); + + assert.isFalse(markerMap.has(m0)); + assert.isFalse(markerMap.has(m1)); + assert.isFalse(markerMap.has(m4)); + assert.isFalse(markerMap.has(m5)); assert.strictEqual(subPatchBuffer.getBuffer().getText(), dedent` 04 @@ -76,6 +87,8 @@ describe('PatchBuffer', function() { subPatchBuffer.findMarkers('patch', {}).map(m => m.getRange().serialize()), [[[2, 0], [3, 1]]], ); + assert.deepEqual(markerMap.get(m2).getRange().serialize(), [[0, 0], [1, 0]]); + assert.deepEqual(markerMap.get(m3).getRange().serialize(), [[2, 0], [3, 1]]); }); describe('deferred-marking modifications', function() { @@ -181,16 +194,17 @@ describe('PatchBuffer', function() { cc `); - subPatchBuffer.markPosition('patch', [0, 0]); - subPatchBuffer.markRange('hunk', [[0, 0], [1, 4]]); - subPatchBuffer.markRange('addition', [[1, 2], [2, 2]]); + const m0 = subPatchBuffer.markPosition('patch', [0, 0]); + const m1 = subPatchBuffer.markRange('hunk', [[0, 0], [1, 4]]); + const m2 = subPatchBuffer.markRange('addition', [[1, 2], [2, 2]]); const mBefore = patchBuffer.markRange('deletion', [[0, 0], [2, 0]]); const mAfter = patchBuffer.markRange('deletion', [[7, 0], [7, 4]]); + let markerMap; patchBuffer .createInserterAt([3, 2]) - .insertPatchBuffer(subPatchBuffer) + .insertPatchBuffer(subPatchBuffer, {callback: m => { markerMap = m; }}) .apply(); assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` @@ -211,21 +225,25 @@ describe('PatchBuffer', function() { assert.deepEqual(mBefore.getRange().serialize(), [[0, 0], [2, 0]]); assert.deepEqual(mAfter.getRange().serialize(), [[9, 0], [9, 4]]); + assert.isFalse(markerMap.has(mBefore)); + assert.isFalse(markerMap.has(mAfter)); assert.deepEqual( patchBuffer.findMarkers('patch', {}).map(m => m.getRange().serialize()), [[[3, 2], [3, 2]]], ); - assert.deepEqual( patchBuffer.findMarkers('hunk', {}).map(m => m.getRange().serialize()), [[[3, 2], [4, 4]]], ); - assert.deepEqual( patchBuffer.findMarkers('addition', {}).map(m => m.getRange().serialize()), [[[4, 2], [5, 2]]], ); + + assert.deepEqual(markerMap.get(m0).getRange().serialize(), [[3, 2], [3, 2]]); + assert.deepEqual(markerMap.get(m1).getRange().serialize(), [[3, 2], [4, 4]]); + assert.deepEqual(markerMap.get(m2).getRange().serialize(), [[4, 2], [5, 2]]); }); }); }); From 498c7200566a5b5f013bb428b829d8819774a1bd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 18 Jan 2019 15:57:09 -0500 Subject: [PATCH 2648/4847] Inserter::markWhile() to mark all changes made in a block --- lib/models/patch/patch-buffer.js | 14 +++++++++----- test/models/patch/patch-buffer.test.js | 17 +++++++++++++---- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 19c7979c7d..18801b14a1 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -107,6 +107,14 @@ class Inserter { } } + markWhile(layerName, block, markerOpts) { + const start = this.insertionPoint.copy(); + block(); + const end = this.insertionPoint.copy(); + this.markerBlueprints.push({layerName, range: new Range(start, end), markerOpts}); + return this; + } + insert(text) { const insertedRange = this.patchBuffer.getBuffer().insert(this.insertionPoint, text); this.insertionPoint = insertedRange.end; @@ -114,11 +122,7 @@ class Inserter { } insertMarked(text, layerName, markerOpts) { - const start = this.insertionPoint.copy(); - this.insert(text); - const end = this.insertionPoint.copy(); - this.markerBlueprints.push({layerName, range: new Range(start, end), markerOpts}); - return this; + return this.markWhile(layerName, () => this.insert(text), markerOpts); } insertPatchBuffer(subPatchBuffer, opts) { diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index 75a7de3b2e..95c65fe364 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -96,11 +96,14 @@ describe('PatchBuffer', function() { const inserter = patchBuffer.createInserterAtEnd(); const cb0 = sinon.spy(); const cb1 = sinon.spy(); + const cb2 = sinon.spy(); - inserter.insert('0010\n'); - inserter.insertMarked('0011\n', 'patch', {invalidate: 'never', callback: cb0}); - inserter.insert('0012\n'); - inserter.insertMarked('0013\n0014\n', 'hunk', {invalidate: 'surround', callback: cb1}); + inserter.markWhile('addition', () => { + inserter.insert('0010\n'); + inserter.insertMarked('0011\n', 'patch', {invalidate: 'never', callback: cb0}); + inserter.insert('0012\n'); + inserter.insertMarked('0013\n0014\n', 'hunk', {invalidate: 'surround', callback: cb1}); + }, {invalidate: 'never', callback: cb2}); assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` ${TEXT}0010 @@ -113,6 +116,8 @@ describe('PatchBuffer', function() { assert.isFalse(cb0.called); assert.isFalse(cb1.called); + assert.isFalse(cb2.called); + assert.lengthOf(patchBuffer.findMarkers('addition', {}), 0); assert.lengthOf(patchBuffer.findMarkers('patch', {}), 0); assert.lengthOf(patchBuffer.findMarkers('hunk', {}), 0); @@ -125,6 +130,10 @@ describe('PatchBuffer', function() { assert.lengthOf(patchBuffer.findMarkers('hunk', {}), 1); const [marker1] = patchBuffer.findMarkers('hunk', {}); assert.isTrue(cb1.calledWith(marker1)); + + assert.lengthOf(patchBuffer.findMarkers('addition', {}), 1); + const [marker2] = patchBuffer.findMarkers('addition', {}); + assert.isTrue(cb2.calledWith(marker2)); }); it('inserts into the middle of an existing buffer', function() { From 5c8181e44c6f7eac977254b64bd9701c8906046f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 18 Jan 2019 16:45:16 -0500 Subject: [PATCH 2649/4847] Rewrite buildHunks() to use an Inserter --- lib/models/patch/builder.js | 149 +++++++++++++++--------------------- 1 file changed, 63 insertions(+), 86 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index af0814e94e..a2de6603b3 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -195,94 +195,71 @@ const CHANGEKIND = { '\\': NoNewline, }; -function buildHunks(diff, patchBuffer, insertRow, existingMarker = null) { - const hunks = []; - - const patchStartRow = insertRow; - let bufferRow = patchStartRow; - let nextLineLength = 0; - - if (diff.hunks.length === 0) { - const patchMarker = patchBuffer.markPosition( - Patch.layerName, - [patchStartRow, 0], - {invalidate: 'never', exclusive: true}, - ); - - return [hunks, patchMarker]; - } - - for (const hunkData of diff.hunks) { - const bufferStartRow = bufferRow; - - const regions = []; - - let LastChangeKind = null; - let currentRangeStart = bufferRow; - let lastLineLength = 0; - - const finishCurrentRange = () => { - if (currentRangeStart === bufferRow) { - return; - } +function buildHunks(diff, patchBuffer, insertRow) { + const inserter = patchBuffer.createInserterAt([insertRow, 0]); - regions.push( - new LastChangeKind( - patchBuffer.markRange( - LastChangeKind.layerName, - [[currentRangeStart, 0], [bufferRow - 1, lastLineLength]], - {invalidate: 'never', exclusive: false}, - ), - ), - ); - currentRangeStart = bufferRow; - }; - - for (const lineText of hunkData.lines) { - const bufferLine = lineText.slice(1) + '\n'; - nextLineLength = lineText.length - 1; - patchBuffer.getBuffer().insert([bufferRow, 0], bufferLine); - - const ChangeKind = CHANGEKIND[lineText[0]]; - if (ChangeKind === undefined) { - throw new Error(`Unknown diff status character: "${lineText[0]}"`); - } - - if (ChangeKind !== LastChangeKind) { - finishCurrentRange(); - } - - LastChangeKind = ChangeKind; - bufferRow++; - lastLineLength = nextLineLength; + let patchMarker = null; + const hunks = []; + inserter.markWhile(Patch.layerName, () => { + for (const rawHunk of diff.hunks) { + const regions = []; + + inserter.markWhile(Hunk.layerName, () => { + let currentRegionText = ''; + let CurrentRegionKind = null; + + function finishRegion() { + if (currentRegionText === '' || CurrentRegionKind === null) { + return; + } + + inserter.insertMarked(currentRegionText, CurrentRegionKind.layerName, { + invalidate: 'never', + exclusive: false, + callback: regionMarker => { regions.push(new CurrentRegionKind(regionMarker)); }, + }); + } + + for (const rawLine of rawHunk.lines) { + const NextRegionKind = CHANGEKIND[rawLine[0]]; + if (NextRegionKind === undefined) { + throw new Error(`Unknown diff status character: "${rawLine[0]}"`); + } + const nextLine = rawLine.slice(1) + '\n'; + + if (NextRegionKind === CurrentRegionKind) { + currentRegionText += nextLine; + continue; + } else { + finishRegion(); + + CurrentRegionKind = NextRegionKind; + currentRegionText = nextLine; + } + } + finishRegion(); + }, { + invalidate: 'never', + exclusive: false, + callback: hunkMarker => { + hunks.push(new Hunk({ + oldStartRow: rawHunk.oldStartLine, + newStartRow: rawHunk.newStartLine, + oldRowCount: rawHunk.oldLineCount, + newRowCount: rawHunk.newLineCount, + sectionHeading: rawHunk.heading, + marker: hunkMarker, + regions, + })); + }, + }); } - finishCurrentRange(); - - hunks.push(new Hunk({ - oldStartRow: hunkData.oldStartLine, - newStartRow: hunkData.newStartLine, - oldRowCount: hunkData.oldLineCount, - newRowCount: hunkData.newLineCount, - sectionHeading: hunkData.heading, - marker: patchBuffer.markRange( - Hunk.layerName, - [[bufferStartRow, 0], [bufferRow - 1, nextLineLength]], - {invalidate: 'never', exclusive: false}, - ), - regions, - })); - } - - let patchMarker = existingMarker; - if (patchMarker) { - patchMarker.setRange([[patchStartRow, 0], [bufferRow - 1, nextLineLength]], {exclusive: false}); - } else { - patchMarker = patchBuffer.markRange( - Patch.layerName, - [[patchStartRow, 0], [bufferRow - 1, nextLineLength]], - {invalidate: 'never', exclusive: false}, - ); - } + }, { + invalidate: 'never', + exclusive: false, + callback: marker => { patchMarker = marker; }, + }); + inserter.apply(); return [hunks, patchMarker]; } From 1a74e83b02712812ce1cd776d7ffa99860765d74 Mon Sep 17 00:00:00 2001 From: annthurium Date: Tue, 22 Jan 2019 11:45:55 -0800 Subject: [PATCH 2650/4847] [wip] make patch model use `nextLayeredBuffer` not sure why getBuffer() sometimes does not work, but nextLayeredBuffer.buffer does... --- lib/models/patch/patch.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index 129e23cfd3..d5c5982ccd 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -192,9 +192,9 @@ export default class Patch { } } - const marker = nextLayeredBuffer.markRange( + const marker = nextLayeredBuffer.buffer.markRange( this.constructor.layerName, - [[0, 0], [nextLayeredBuffer.getBuffer().getLastRow() - 1, Infinity]], + [[0, 0], [nextLayeredBuffer.buffer.getLastRow() - 1, Infinity]], {invalidate: 'never', exclusive: false}, ); @@ -427,7 +427,7 @@ class BufferBuilder { // The ranges provided to builder methods are expected to be valid within the original buffer. Account for // the position of the Patch within its original TextBuffer, and any existing content already on the next // TextBuffer. - this.offset = this.buffer.getLastRow() - originalBaseOffset; + this.offset = this.nextLayeredBuffer.buffer.getLastRow() - originalBaseOffset; this.hunkBufferText = ''; this.hunkRowCount = 0; @@ -470,15 +470,13 @@ class BufferBuilder { } latestHunkWasIncluded() { - this.nextLayeredBuffer.getBuffer().append(this.hunkBufferText, {normalizeLineEndings: false}); + this.nextLayeredBuffer.buffer.append(this.hunkBufferText, {normalizeLineEndings: false}); const regions = this.hunkRegions.map(({RegionKind, range}) => { - return new RegionKind( - this.nextLayeredBuffer.getLayer(RegionKind.layerName, range, {invalidate: 'never', exclusive: false}), - ); + return new RegionKind(this.nextLayeredBuffer.layers[RegionKind.layerName]); }); - const marker = this.nextLayeredBuffer.markRange('hunk', this.hunkRange, {invalidate: 'never', exclusive: false}); + const marker = this.nextLayeredBuffer.buffer.markRange('hunk', this.hunkRange, {invalidate: 'never', exclusive: false}); this.hunkBufferText = ''; this.hunkRowCount = 0; From 510c88766daaaa511f7e7e9f688b3ebfdbecc1ff Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 15:25:02 -0500 Subject: [PATCH 2651/4847] PatchBuffer::inspect() to debug marker placement --- lib/models/patch/patch-buffer.js | 44 ++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 18801b14a1..e5dca106e7 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -1,4 +1,5 @@ import {TextBuffer, Range, Point} from 'atom'; +import {inspect} from 'util'; const LAYER_NAMES = ['unchanged', 'addition', 'deletion', 'nonewline', 'hunk', 'patch']; @@ -78,6 +79,49 @@ export default class PatchBuffer { this.buffer.setTextInRange(range, ''); return {patchBuffer: subBuffer, markerMap}; } + + inspect() { + let inspectString = ''; + + const increasingMarkers = []; + for (const layerName of LAYER_NAMES) { + for (const marker of this.findMarkers(layerName, {})) { + increasingMarkers.push({layerName, point: marker.getRange().start, start: true, id: marker.id}); + increasingMarkers.push({layerName, point: marker.getRange().end, end: true, id: marker.id}); + } + } + increasingMarkers.sort((a, b) => { + const cmp = a.point.compare(b.point); + if (cmp !== 0) { + return cmp; + } else if (a.start && b.start) { + return 0; + } else if (a.start && !b.start) { + return -1; + } else if (!a.start && b.start) { + return 1; + } else { + return 0; + } + }); + + let inspectPoint = Point.fromObject([0, 0]); + for (const marker of increasingMarkers) { + if (!marker.point.isEqual(inspectPoint)) { + inspectString += inspect(this.buffer.getTextInRange([inspectPoint, marker.point])) + '\n'; + } + + if (marker.start) { + inspectString += ` start ${marker.layerName}@${marker.id}\n`; + } else if (marker.end) { + inspectString += ` end ${marker.layerName}@${marker.id}\n`; + } + + inspectPoint = marker.point; + } + + return inspectString; + } } class Inserter { From 18ff065dfbe6935499a8e531ff67065149078812 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 15:34:10 -0500 Subject: [PATCH 2652/4847] PatchBuffer::findAllMarkers() to query markers across all layers --- lib/models/patch/patch-buffer.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index e5dca106e7..834b3e785a 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -28,6 +28,13 @@ export default class PatchBuffer { return this.layers[layerName].findMarkers(...args); } + findAllMarkers(...args) { + return LAYER_NAMES.reduce((arr, layerName) => { + arr.push(...this.findMarkers(layerName, ...args)); + return arr; + }, []); + } + markPosition(layerName, ...args) { return this.layers[layerName].markPosition(...args); } From 5283be0ba884d4b628133b32d058c6c4fcbc2ef3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 15:34:24 -0500 Subject: [PATCH 2653/4847] Clip insertion point to valid buffer positions --- lib/models/patch/patch-buffer.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 834b3e785a..2ce96fe416 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -133,9 +133,11 @@ export default class PatchBuffer { class Inserter { constructor(patchBuffer, insertionPoint) { + const clipped = patchBuffer.getBuffer().clipPosition(insertionPoint); + this.patchBuffer = patchBuffer; - this.startPoint = insertionPoint.copy(); - this.insertionPoint = insertionPoint; + this.startPoint = clipped.copy(); + this.insertionPoint = clipped.copy(); this.markerBlueprints = []; this.markersBefore = new Set(); From c56becb6b1f56cc263a182fa45d441e04b7e37e3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 15:34:30 -0500 Subject: [PATCH 2654/4847] Fluent APIs --- lib/models/patch/patch-buffer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 2ce96fe416..936e9a7735 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -150,6 +150,7 @@ class Inserter { this.markersBefore.add(marker); } } + return this; } keepAfter(markers) { @@ -158,6 +159,7 @@ class Inserter { this.markersAfter.add(marker); } } + return this; } markWhile(layerName, block, markerOpts) { From d6e5947b5cf7e38f0556e7cee374806e279cd833 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 15:34:53 -0500 Subject: [PATCH 2655/4847] No need to manually touch up patch/hunk markers --- lib/models/patch/builder.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index a2de6603b3..bcf95bd6fb 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -71,16 +71,6 @@ export function buildMultiFilePatch(diffs, options) { } const filePatches = actions.map(action => action()); - - // Fix markers for patches with no hunks. - // Head position was moved everytime lines were appended. - filePatches.forEach(filePatch => { - if (filePatch.getHunks().length === 0) { - const marker = filePatch.getMarker(); - marker.setHeadPosition(marker.getTailPosition()); - } - }); - return new MultiFilePatch({patchBuffer, filePatches}); } From 4c39a4bb83e5f535a36bb69800702596bfc9c9c2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 15:36:12 -0500 Subject: [PATCH 2656/4847] Insert newlines *between* consecutive patches, hunks, regions --- lib/models/patch/builder.js | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index bcf95bd6fb..4caf56db52 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -189,11 +189,28 @@ function buildHunks(diff, patchBuffer, insertRow) { const inserter = patchBuffer.createInserterAt([insertRow, 0]); let patchMarker = null; + let firstHunk = true; const hunks = []; + + // Separate multiple patches on the same buffer with an unmarked newline + if (patchBuffer.getBuffer().getLength() > 0) { + console.log('inserting newline to separate Patches'); + inserter.insert('\n'); + } + inserter.markWhile(Patch.layerName, () => { for (const rawHunk of diff.hunks) { + let firstRegion = true; const regions = []; + // Separate hunks with an unmarked newline + if (firstHunk) { + firstHunk = false; + } else { + console.log('inserting newline to separate Hunks'); + inserter.insert('\n'); + } + inserter.markWhile(Hunk.layerName, () => { let currentRegionText = ''; let CurrentRegionKind = null; @@ -203,6 +220,14 @@ function buildHunks(diff, patchBuffer, insertRow) { return; } + // Separate regions with an unmarked newline + if (firstRegion) { + firstRegion = false; + } else { + console.log('inserting newline to separate Regions'); + inserter.insert('\n'); + } + inserter.insertMarked(currentRegionText, CurrentRegionKind.layerName, { invalidate: 'never', exclusive: false, @@ -215,9 +240,12 @@ function buildHunks(diff, patchBuffer, insertRow) { if (NextRegionKind === undefined) { throw new Error(`Unknown diff status character: "${rawLine[0]}"`); } - const nextLine = rawLine.slice(1) + '\n'; + const nextLine = rawLine.slice(1); if (NextRegionKind === CurrentRegionKind) { + if (currentRegionText !== '') { + currentRegionText += '\n'; + } currentRegionText += nextLine; continue; } else { From 62951be35ecd5f24a47dda299ad14ec887c17f8b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 15:36:41 -0500 Subject: [PATCH 2657/4847] Need IIFEs for callbacks created within loops --- lib/models/patch/builder.js | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 4caf56db52..5a57832296 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -231,7 +231,9 @@ function buildHunks(diff, patchBuffer, insertRow) { inserter.insertMarked(currentRegionText, CurrentRegionKind.layerName, { invalidate: 'never', exclusive: false, - callback: regionMarker => { regions.push(new CurrentRegionKind(regionMarker)); }, + callback: (function(_regions, _CurrentRegionKind) { + return regionMarker => { _regions.push(new _CurrentRegionKind(regionMarker)); }; + })(regions, CurrentRegionKind), }); } @@ -259,17 +261,19 @@ function buildHunks(diff, patchBuffer, insertRow) { }, { invalidate: 'never', exclusive: false, - callback: hunkMarker => { - hunks.push(new Hunk({ - oldStartRow: rawHunk.oldStartLine, - newStartRow: rawHunk.newStartLine, - oldRowCount: rawHunk.oldLineCount, - newRowCount: rawHunk.newLineCount, - sectionHeading: rawHunk.heading, - marker: hunkMarker, - regions, - })); - }, + callback: (function(_hunks, _rawHunk, _regions) { + return hunkMarker => { + _hunks.push(new Hunk({ + oldStartRow: _rawHunk.oldStartLine, + newStartRow: _rawHunk.newStartLine, + oldRowCount: _rawHunk.oldLineCount, + newRowCount: _rawHunk.newLineCount, + sectionHeading: _rawHunk.heading, + marker: hunkMarker, + regions: _regions, + })); + }; + })(hunks, rawHunk, regions), }); } }, { From 0187f4c2cec163430e34fea5a7b6a88a43ff8ac1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 15:37:04 -0500 Subject: [PATCH 2658/4847] buildHunks() always inserts at the end --- lib/models/patch/builder.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 5a57832296..555f54a173 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -120,12 +120,12 @@ function singleDiffFilePatch(diff, patchBuffer, opts) { return FilePatch.createDelayedFilePatch( oldFile, newFile, patchMarker, TOO_LARGE, () => { - const [hunks] = buildHunks(diff, patchBuffer, insertRow, patchMarker); + const [hunks] = buildHunks(diff, patchBuffer); return new Patch({status: diff.status, hunks, marker: patchMarker}); }, ); } else { - const [hunks, patchMarker] = buildHunks(diff, patchBuffer, patchBuffer.getBuffer().getLastRow()); + const [hunks, patchMarker] = buildHunks(diff, patchBuffer); const patch = new Patch({status: diff.status, hunks, marker: patchMarker}); return new FilePatch(oldFile, newFile, patch); @@ -172,7 +172,7 @@ function dualDiffFilePatch(diff1, diff2, patchBuffer, opts) { // TODO: do something with large diff too } - const [hunks, patchMarker] = buildHunks(contentChangeDiff, patchBuffer, patchBuffer.getBuffer().getLastRow()); + const [hunks, patchMarker] = buildHunks(contentChangeDiff, patchBuffer); const patch = new Patch({status, hunks, marker: patchMarker}); return new FilePatch(oldFile, newFile, patch); @@ -185,8 +185,9 @@ const CHANGEKIND = { '\\': NoNewline, }; -function buildHunks(diff, patchBuffer, insertRow) { - const inserter = patchBuffer.createInserterAt([insertRow, 0]); +function buildHunks(diff, patchBuffer) { + const inserter = patchBuffer.createInserterAtEnd() + .keepBefore(patchBuffer.findAllMarkers({endPosition: patchBuffer.getInsertionPoint()})); let patchMarker = null; let firstHunk = true; From 07f3c88a7d4de3873c6b61980801c4552eb35e4c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 15:37:52 -0500 Subject: [PATCH 2659/4847] :fire: trailing newline --- test/models/patch/builder.test.js | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 75949de05e..a8cd12b2db 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -79,7 +79,7 @@ describe('buildFilePatch', function() { const bufferText = 'line-0\nline-1\nline-2\nline-3\nline-4\nline-5\nline-6\nline-7\nline-8\nline-9\nline-10\n' + - 'line-11\nline-12\nline-13\nline-14\nline-15\nline-16\nline-17\nline-18\n'; + 'line-11\nline-12\nline-13\nline-14\nline-15\nline-16\nline-17\nline-18'; assert.strictEqual(buffer.getText(), bufferText); assertInPatch(p, buffer).hunks( @@ -113,7 +113,7 @@ describe('buildFilePatch', function() { {kind: 'unchanged', string: ' line-13\n', range: [[13, 0], [13, 7]]}, {kind: 'deletion', string: '-line-14\n-line-15\n', range: [[14, 0], [15, 7]]}, {kind: 'addition', string: '+line-16\n+line-17\n', range: [[16, 0], [17, 7]]}, - {kind: 'unchanged', string: ' line-18\n', range: [[18, 0], [18, 7]]}, + {kind: 'unchanged', string: ' line-18', range: [[18, 0], [18, 7]]}, ], }, ); @@ -229,7 +229,7 @@ describe('buildFilePatch', function() { assert.isFalse(p.getNewFile().isPresent()); assert.strictEqual(p.getPatch().getStatus(), 'deleted'); - const bufferText = 'line-0\nline-1\nline-2\nline-3\n\n'; + const bufferText = 'line-0\nline-1\nline-2\nline-3\n'; assert.strictEqual(buffer.getText(), bufferText); assertInPatch(p, buffer).hunks( @@ -238,7 +238,7 @@ describe('buildFilePatch', function() { endRow: 4, header: '@@ -1,5 +0,0 @@', regions: [ - {kind: 'deletion', string: '-line-0\n-line-1\n-line-2\n-line-3\n-\n', range: [[0, 0], [4, 0]]}, + {kind: 'deletion', string: '-line-0\n-line-1\n-line-2\n-line-3\n-', range: [[0, 0], [4, 0]]}, ], }, ); @@ -276,7 +276,7 @@ describe('buildFilePatch', function() { assert.strictEqual(p.getNewMode(), '100755'); assert.strictEqual(p.getPatch().getStatus(), 'added'); - const bufferText = 'line-0\nline-1\nline-2\n'; + const bufferText = 'line-0\nline-1\nline-2'; assert.strictEqual(buffer.getText(), bufferText); assertInPatch(p, buffer).hunks( @@ -285,7 +285,7 @@ describe('buildFilePatch', function() { endRow: 2, header: '@@ -0,0 +1,3 @@', regions: [ - {kind: 'addition', string: '+line-0\n+line-1\n+line-2\n', range: [[0, 0], [2, 6]]}, + {kind: 'addition', string: '+line-0\n+line-1\n+line-2', range: [[0, 0], [2, 6]]}, ], }, ); @@ -319,7 +319,7 @@ describe('buildFilePatch', function() { assert.lengthOf(multiFilePatch.getFilePatches(), 1); const [p] = multiFilePatch.getFilePatches(); const buffer = multiFilePatch.getBuffer(); - assert.strictEqual(buffer.getText(), 'line-0\nline-1\n No newline at end of file\n'); + assert.strictEqual(buffer.getText(), 'line-0\nline-1\n No newline at end of file'); assertInPatch(p, buffer).hunks({ startRow: 0, @@ -328,7 +328,7 @@ describe('buildFilePatch', function() { regions: [ {kind: 'addition', string: '+line-0\n', range: [[0, 0], [0, 6]]}, {kind: 'deletion', string: '-line-1\n', range: [[1, 0], [1, 6]]}, - {kind: 'nonewline', string: '\\ No newline at end of file\n', range: [[2, 0], [2, 26]]}, + {kind: 'nonewline', string: '\\ No newline at end of file', range: [[2, 0], [2, 26]]}, ], }); }); @@ -383,13 +383,13 @@ describe('buildFilePatch', function() { assert.strictEqual(p.getNewSymlink(), 'the-destination'); assert.strictEqual(p.getStatus(), 'deleted'); - assert.strictEqual(buffer.getText(), 'line-0\nline-1\n'); + assert.strictEqual(buffer.getText(), 'line-0\nline-1'); assertInPatch(p, buffer).hunks({ startRow: 0, endRow: 1, header: '@@ -0,0 +0,2 @@', regions: [ - {kind: 'addition', string: '+line-0\n+line-1\n', range: [[0, 0], [1, 6]]}, + {kind: 'addition', string: '+line-0\n+line-1', range: [[0, 0], [1, 6]]}, ], }); }); @@ -442,13 +442,13 @@ describe('buildFilePatch', function() { assert.isNull(p.getNewSymlink()); assert.strictEqual(p.getStatus(), 'added'); - assert.strictEqual(buffer.getText(), 'line-0\nline-1\n'); + assert.strictEqual(buffer.getText(), 'line-0\nline-1'); assertInPatch(p, buffer).hunks({ startRow: 0, endRow: 1, header: '@@ -0,2 +0,0 @@', regions: [ - {kind: 'deletion', string: '-line-0\n-line-1\n', range: [[0, 0], [1, 6]]}, + {kind: 'deletion', string: '-line-0\n-line-1', range: [[0, 0], [1, 6]]}, ], }); }); @@ -500,13 +500,13 @@ describe('buildFilePatch', function() { assert.strictEqual(p.getNewSymlink(), 'the-destination'); assert.strictEqual(p.getStatus(), 'deleted'); - assert.strictEqual(buffer.getText(), 'line-0\nline-1\n'); + assert.strictEqual(buffer.getText(), 'line-0\nline-1'); assertInPatch(p, buffer).hunks({ startRow: 0, endRow: 1, header: '@@ -0,0 +0,2 @@', regions: [ - {kind: 'addition', string: '+line-0\n+line-1\n', range: [[0, 0], [1, 6]]}, + {kind: 'addition', string: '+line-0\n+line-1', range: [[0, 0], [1, 6]]}, ], }); }); @@ -599,7 +599,7 @@ describe('buildFilePatch', function() { mp.getBuffer().getText(), 'line-0\nline-1\nline-2\nline-3\nline-4\nline-5\nline-6\n' + 'line-5\nline-6\nline-7\nline-8\n' + - 'line-0\nline-1\nline-2\n', + 'line-0\nline-1\nline-2', ); assert.strictEqual(mp.getFilePatches()[0].getOldPath(), 'first'); @@ -637,7 +637,7 @@ describe('buildFilePatch', function() { assertInFilePatch(mp.getFilePatches()[2], buffer).hunks( { startRow: 11, endRow: 13, header: '@@ -1,0 +1,3 @@', regions: [ - {kind: 'addition', string: '+line-0\n+line-1\n+line-2\n', range: [[11, 0], [13, 6]]}, + {kind: 'addition', string: '+line-0\n+line-1\n+line-2', range: [[11, 0], [13, 6]]}, ], }, ); From f4ea1a2e6155274bcbe4c1cbb4ac759a475896bd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 15:41:03 -0500 Subject: [PATCH 2660/4847] Remove console.logs :eyes: --- lib/models/patch/builder.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 555f54a173..b993d74214 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -195,7 +195,6 @@ function buildHunks(diff, patchBuffer) { // Separate multiple patches on the same buffer with an unmarked newline if (patchBuffer.getBuffer().getLength() > 0) { - console.log('inserting newline to separate Patches'); inserter.insert('\n'); } @@ -208,7 +207,6 @@ function buildHunks(diff, patchBuffer) { if (firstHunk) { firstHunk = false; } else { - console.log('inserting newline to separate Hunks'); inserter.insert('\n'); } @@ -225,7 +223,6 @@ function buildHunks(diff, patchBuffer) { if (firstRegion) { firstRegion = false; } else { - console.log('inserting newline to separate Regions'); inserter.insert('\n'); } From 57c03e16bb5681373ab92acb89c5b7fdd1bb02c8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 15:50:29 -0500 Subject: [PATCH 2661/4847] Mark zero-length patches --- lib/models/patch/builder.js | 4 ++-- test/models/patch/builder.test.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index b993d74214..df38c7807e 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -193,8 +193,8 @@ function buildHunks(diff, patchBuffer) { let firstHunk = true; const hunks = []; - // Separate multiple patches on the same buffer with an unmarked newline - if (patchBuffer.getBuffer().getLength() > 0) { + // Separate multiple non-empty patches on the same buffer with an unmarked newline + if (patchBuffer.getBuffer().getLength() > 0 && diff.hunks.length > 0) { inserter.insert('\n'); } diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index a8cd12b2db..3555a3fc48 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -740,7 +740,7 @@ describe('buildFilePatch', function() { assert.strictEqual(fp3.getNewPath(), 'third'); assertInFilePatch(fp3, buffer).hunks({ startRow: 7, endRow: 9, header: '@@ -1,3 +1,0 @@', regions: [ - {kind: 'deletion', string: '-line-0\n-line-1\n-line-2\n', range: [[7, 0], [9, 6]]}, + {kind: 'deletion', string: '-line-0\n-line-1\n-line-2', range: [[7, 0], [9, 6]]}, ], }); }); @@ -794,7 +794,7 @@ describe('buildFilePatch', function() { assert.strictEqual(mp.getFilePatches()[1].getOldPath(), 'second'); assert.deepEqual(mp.getFilePatches()[1].getHunks(), []); - assert.deepEqual(mp.getFilePatches()[1].getMarker().getRange().serialize(), [[7, 0], [7, 0]]); + assert.deepEqual(mp.getFilePatches()[1].getMarker().getRange().serialize(), [[6, 6], [6, 6]]); assert.strictEqual(mp.getFilePatches()[2].getOldPath(), 'third'); assert.deepEqual(mp.getFilePatches()[2].getMarker().getRange().serialize(), [[7, 0], [10, 6]]); From 869ec0ebacc76148cd610392dcc349a8b0bdb927 Mon Sep 17 00:00:00 2001 From: annthurium Date: Tue, 22 Jan 2019 16:09:50 -0800 Subject: [PATCH 2662/4847] [wip] make Patch model tests use a PatchBuffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sometimes `Region.marker` is a `Marker` (as it should be) and sometimes it’s a `MarkerLayer` (wtf). I think Patch.clone() is the problem but needs more investigation. Pushing what I've got so others can take a look tomorrow. --- lib/models/patch/patch.js | 8 ++++---- test/models/patch/patch.test.js | 11 ++++------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index d5c5982ccd..ede2804b97 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -192,9 +192,9 @@ export default class Patch { } } - const marker = nextLayeredBuffer.buffer.markRange( + const marker = nextLayeredBuffer.markRange( this.constructor.layerName, - [[0, 0], [nextLayeredBuffer.buffer.getLastRow() - 1, Infinity]], + [[0, 0], [nextLayeredBuffer.getBuffer().getLastRow() - 1, Infinity]], {invalidate: 'never', exclusive: false}, ); @@ -427,7 +427,7 @@ class BufferBuilder { // The ranges provided to builder methods are expected to be valid within the original buffer. Account for // the position of the Patch within its original TextBuffer, and any existing content already on the next // TextBuffer. - this.offset = this.nextLayeredBuffer.buffer.getLastRow() - originalBaseOffset; + this.offset = this.nextLayeredBuffer.getBuffer().getLastRow() - originalBaseOffset; this.hunkBufferText = ''; this.hunkRowCount = 0; @@ -476,7 +476,7 @@ class BufferBuilder { return new RegionKind(this.nextLayeredBuffer.layers[RegionKind.layerName]); }); - const marker = this.nextLayeredBuffer.buffer.markRange('hunk', this.hunkRange, {invalidate: 'never', exclusive: false}); + const marker = this.nextLayeredBuffer.markRange('hunk', this.hunkRange, {invalidate: 'never', exclusive: false}); this.hunkBufferText = ''; this.hunkRowCount = 0; diff --git a/test/models/patch/patch.test.js b/test/models/patch/patch.test.js index b5989ab3fe..a543deec8f 100644 --- a/test/models/patch/patch.test.js +++ b/test/models/patch/patch.test.js @@ -1,11 +1,12 @@ import {TextBuffer} from 'atom'; import Patch from '../../../lib/models/patch/patch'; +import PatchBuffer from '../../../lib/models/patch/patch-buffer'; import Hunk from '../../../lib/models/patch/hunk'; import {Unchanged, Addition, Deletion, NoNewline} from '../../../lib/models/patch/region'; import {assertInPatch} from '../../helpers'; -describe('Patch', function() { +describe.only('Patch', function() { it('has some standard accessors', function() { const buffer = new TextBuffer({text: 'bufferText'}); const layers = buildLayers(buffer); @@ -165,9 +166,7 @@ describe('Patch', function() { let stageLayeredBuffer; beforeEach(function() { - const stageBuffer = new TextBuffer(); - const stageLayers = buildLayers(stageBuffer); - stageLayeredBuffer = {buffer: stageBuffer, layers: stageLayers}; + stageLayeredBuffer = new PatchBuffer(); }); it('creates a patch that applies selected lines from only the first hunk', function() { @@ -372,9 +371,7 @@ describe('Patch', function() { let unstageLayeredBuffer; beforeEach(function() { - const unstageBuffer = new TextBuffer(); - const unstageLayers = buildLayers(unstageBuffer); - unstageLayeredBuffer = {buffer: unstageBuffer, layers: unstageLayers}; + unstageLayeredBuffer = new PatchBuffer(); }); it('creates a patch that updates the index to unapply selected lines from a single hunk', function() { From d1fcf707d55e97b2f498270bb19b99372d009661 Mon Sep 17 00:00:00 2001 From: annthurium Date: Tue, 22 Jan 2019 16:11:40 -0800 Subject: [PATCH 2663/4847] :fire: .only --- test/models/patch/patch.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/patch/patch.test.js b/test/models/patch/patch.test.js index a543deec8f..8307d832b7 100644 --- a/test/models/patch/patch.test.js +++ b/test/models/patch/patch.test.js @@ -6,7 +6,7 @@ import Hunk from '../../../lib/models/patch/hunk'; import {Unchanged, Addition, Deletion, NoNewline} from '../../../lib/models/patch/region'; import {assertInPatch} from '../../helpers'; -describe.only('Patch', function() { +describe('Patch', function() { it('has some standard accessors', function() { const buffer = new TextBuffer({text: 'bufferText'}); const layers = buildLayers(buffer); From d13d1849d82d2bfa097adaf929b172b25e6c4688 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 21:42:23 -0500 Subject: [PATCH 2664/4847] DelayedPatch :point_right: HiddenPatch --- test/models/patch/builder.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 3555a3fc48..1f279c5c32 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -802,7 +802,7 @@ describe('buildFilePatch', function() { }); describe('with a large diff', function() { - it('creates a DelayedPatch when the diff is "too large"', function() { + it('creates a HiddenPatch when the diff is "too large"', function() { const mfp = buildMultiFilePatch([ { oldPath: 'first', oldMode: '100644', newPath: 'first', newMode: '100755', status: 'modified', @@ -847,7 +847,7 @@ describe('buildFilePatch', function() { ); }); - it('re-parse a DelayedPatch as a Patch', function() { + it('re-parse a HiddenPatch as a Patch', function() { const mfp = buildMultiFilePatch([ { oldPath: 'first', oldMode: '100644', newPath: 'first', newMode: '100644', status: 'modified', @@ -1028,7 +1028,7 @@ describe('buildFilePatch', function() { assert.deepEqual(fp2.getMarker().getRange().serialize(), [[4, 0], [4, 0]]); }); - it('does not create a DelayedPatch when the patch has been explicitly expanded', function() { + it('does not create a HiddenPatch when the patch has been explicitly expanded', function() { const mfp = buildMultiFilePatch([ { oldPath: 'big/file.txt', oldMode: '100644', newPath: 'big/file.txt', newMode: '100755', status: 'modified', From d25db25239f98660849b63332818f1fbbacac2af Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 21:42:43 -0500 Subject: [PATCH 2665/4847] More trailing newlines --- test/models/patch/builder.test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 1f279c5c32..d47ccdff1e 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -841,7 +841,7 @@ describe('buildFilePatch', function() { { startRow: 0, endRow: 1, header: '@@ -1,1 +1,2 @@', regions: [ {kind: 'unchanged', string: ' line-4\n', range: [[0, 0], [0, 6]]}, - {kind: 'addition', string: '+line-5\n', range: [[1, 0], [1, 6]]}, + {kind: 'addition', string: '+line-5', range: [[1, 0], [1, 6]]}, ], }, ); @@ -879,7 +879,7 @@ describe('buildFilePatch', function() { {kind: 'unchanged', string: ' line-0\n', range: [[0, 0], [0, 6]]}, {kind: 'addition', string: '+line-1\n', range: [[1, 0], [1, 6]]}, {kind: 'deletion', string: '-line-2\n', range: [[2, 0], [2, 6]]}, - {kind: 'unchanged', string: ' line-3\n', range: [[3, 0], [3, 6]]}, + {kind: 'unchanged', string: ' line-3', range: [[3, 0], [3, 6]]}, ], }, ); @@ -940,7 +940,7 @@ describe('buildFilePatch', function() { {kind: 'unchanged', string: ' line-0\n', range: [[4, 0], [4, 6]]}, {kind: 'addition', string: '+line-1\n', range: [[5, 0], [5, 6]]}, {kind: 'deletion', string: '-line-2\n', range: [[6, 0], [6, 6]]}, - {kind: 'unchanged', string: ' line-3\n', range: [[7, 0], [7, 6]]}, + {kind: 'unchanged', string: ' line-3', range: [[7, 0], [7, 6]]}, ], }, ); @@ -978,7 +978,7 @@ describe('buildFilePatch', function() { {kind: 'unchanged', string: ' line-0\n', range: [[9, 0], [9, 6]]}, {kind: 'addition', string: '+line-1\n', range: [[10, 0], [10, 6]]}, {kind: 'deletion', string: '-line-2\n', range: [[11, 0], [11, 6]]}, - {kind: 'unchanged', string: ' line-3\n', range: [[12, 0], [12, 6]]}, + {kind: 'unchanged', string: ' line-3', range: [[12, 0], [12, 6]]}, ], }, ); @@ -1054,7 +1054,7 @@ describe('buildFilePatch', function() { {kind: 'unchanged', string: ' line-0\n', range: [[0, 0], [0, 6]]}, {kind: 'addition', string: '+line-1\n', range: [[1, 0], [1, 6]]}, {kind: 'deletion', string: '-line-2\n', range: [[2, 0], [2, 6]]}, - {kind: 'unchanged', string: ' line-3\n', range: [[3, 0], [3, 6]]}, + {kind: 'unchanged', string: ' line-3', range: [[3, 0], [3, 6]]}, ], }, ); From 92a113087c05a53ec3194be57aa1f4ddbe3c83fa Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 21:44:08 -0500 Subject: [PATCH 2666/4847] updateMarkers methods to consume marker Maps --- lib/models/patch/file-patch.js | 8 ++------ lib/models/patch/hunk.js | 7 +++++++ lib/models/patch/patch.js | 7 +++++++ lib/models/patch/region.js | 4 ++++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index 7c76d6a0e9..677e8a4e3e 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -119,12 +119,8 @@ export default class FilePatch { return this.getPatch().getHunks(); } - triggerDelayedRender() { - const nextPatch = this.patch.parseFn(this.patch); - if (nextPatch !== this.patch) { - this.patch = nextPatch; - this.didChangeRenderStatus(); - } + updateMarkers(map) { + return this.patch.updateMarkers(map); } triggerCollapse = () => { diff --git a/lib/models/patch/hunk.js b/lib/models/patch/hunk.js index 074f86f7f3..6922203bb9 100644 --- a/lib/models/patch/hunk.js +++ b/lib/models/patch/hunk.js @@ -141,6 +141,13 @@ export default class Hunk { this.marker = markable.markRange(this.getRange(), {invalidate: 'never', exclusive: false}); } + updateMarkers(map) { + this.marker = map.get(this.marker) || this.marker; + for (const region of this.regions) { + region.updateMarkers(map); + } + } + toStringIn(buffer) { return this.getRegions().reduce((str, region) => str + region.toStringIn(buffer), this.getHeader() + '\n'); } diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index ede2804b97..3bc53902cc 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -83,6 +83,13 @@ export default class Patch { ); } + updateMarkers(map) { + this.marker = map.get(this.marker) || this.marker; + for (const hunk of this.hunks) { + hunk.updateMarkers(map); + } + } + getMaxLineNumberWidth() { const lastHunk = this.hunks[this.hunks.length - 1]; return lastHunk ? lastHunk.getMaxLineNumberWidth() : 0; diff --git a/lib/models/patch/region.js b/lib/models/patch/region.js index d246b911bc..ea30b4b024 100644 --- a/lib/models/patch/region.js +++ b/lib/models/patch/region.js @@ -111,6 +111,10 @@ class Region { this.marker = markable.markRange(this.getRange(), {invalidate: 'never', exclusive: false}); } + updateMarkers(map) { + this.marker = map.get(this.marker) || this.marker; + } + toStringIn(buffer) { const raw = buffer.getTextInRange(this.getRange()); return this.constructor.origin + raw.replace(/\r?\n/g, '$&' + this.constructor.origin) + From 70ea3024605130ae4849d805ba2fe91d72020f2f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 21:45:08 -0500 Subject: [PATCH 2667/4847] Implement HiddenPatch --- lib/models/patch/file-patch.js | 4 +-- lib/models/patch/patch.js | 48 ++++++++++++++-------------------- 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index 677e8a4e3e..923f0b039d 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -9,8 +9,8 @@ export default class FilePatch { return new this(nullFile, nullFile, Patch.createNull()); } - static createDelayedFilePatch(oldFile, newFile, marker, renderStatus, parseFn) { - return new this(oldFile, newFile, Patch.createDelayedPatch(marker, renderStatus, parseFn)); + static createHiddenFilePatch(oldFile, newFile, marker, renderStatus, showFn) { + return new this(oldFile, newFile, Patch.createHiddenPatch(marker, renderStatus, showFn)); } constructor(oldFile, newFile, patch) { diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index 3bc53902cc..e734b130b5 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -28,22 +28,16 @@ export default class Patch { return new NullPatch(); } - static createDelayedPatch(marker, renderStatus, parseFn) { - return new this({status: null, hunks: [], marker, renderStatus, parseFn}); + static createHiddenPatch(marker, renderStatus, showFn) { + return new HiddenPatch(marker, renderStatus, showFn); } - constructor({status, hunks, marker, renderStatus, parseFn}) { + constructor({status, hunks, marker}) { this.status = status; this.hunks = hunks; this.marker = marker; - this.renderStatus = renderStatus || EXPANDED; this.changedLineCount = this.getHunks().reduce((acc, hunk) => acc + hunk.changedLineCount(), 0); - - if (parseFn) { - // Override the prototype's method - this.parseFn = parseFn; - } } getStatus() { @@ -100,24 +94,11 @@ export default class Patch { status: opts.status !== undefined ? opts.status : this.getStatus(), hunks: opts.hunks !== undefined ? opts.hunks : this.getHunks(), marker: opts.marker !== undefined ? opts.marker : this.getMarker(), - renderStatus: opts.renderStatus !== undefined ? opts.renderStatus : this.getRenderStatus(), }); } - collapsed() { - if (this.getRenderStatus() === COLLAPSED) { - return this; } - - return this.clone({renderStatus: COLLAPSED}); - } - - expanded() { - if (this.getRenderStatus() === EXPANDED) { - return this; } - - return this.clone({renderStatus: EXPANDED}); } buildStagePatchForLines(originalBuffer, nextLayeredBuffer, rowSet) { @@ -329,11 +310,24 @@ export default class Patch { } getRenderStatus() { - return this.renderStatus; + return EXPANDED; + } +} + +class HiddenPatch extends Patch { + constructor(marker, renderStatus, showFn) { + super({status: null, hunks: [], marker}); + + this.renderStatus = renderStatus; + this.show = showFn; } - parseFn() { - return this; + getInsertionPoint() { + return this.getRange().end; + } + + getRenderStatus() { + return this.renderStatus; } } @@ -420,10 +414,6 @@ class NullPatch { getRenderStatus() { return EXPANDED; } - - parseFn() { - return this; - } } class BufferBuilder { From 24515a1033cd037c349deaf0aafdeb00bce96941 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 21:45:30 -0500 Subject: [PATCH 2668/4847] Get starting and ending Marker sets --- lib/models/patch/patch.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index e734b130b5..3a2e1e1367 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -97,8 +97,32 @@ export default class Patch { }); } + /* Return the set of Markers owned by this Patch that butt up against the patch's beginning. */ + getStartingMarkers() { + const markers = [this.marker]; + if (this.hunks.length > 0) { + const firstHunk = this.hunks[0]; + markers.push(firstHunk.getMarker()); + if (firstHunk.getRegions().length > 0) { + const firstRegion = firstHunk.getRegions()[0]; + markers.push(firstRegion.getMarker()); + } } + return markers; + } + + /* Return the set of Markers owned by this Patch that end at the patch's end position. */ + getEndingMarkers() { + const markers = [this.marker]; + if (this.hunks.length > 0) { + const lastHunk = this.hunks[this.hunks.length - 1]; + markers.push(lastHunk.getMarker()); + if (lastHunk.getRegions().length > 0) { + const lastRegion = lastHunk.getRegions()[lastHunk.getRegions().length - 1]; + markers.push(lastRegion.getMarker()); + } } + return markers; } buildStagePatchForLines(originalBuffer, nextLayeredBuffer, rowSet) { From f27f5ab8509b05e70aaccf374c5256ea3a756e9c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 21:45:56 -0500 Subject: [PATCH 2669/4847] Create a HiddenFilePatch for diff sets that are too large --- lib/models/patch/builder.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index df38c7807e..04164d89d1 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -110,18 +110,19 @@ function singleDiffFilePatch(diff, patchBuffer, opts) { EXPANDED; if (renderStatus === TOO_LARGE) { - const insertRow = patchBuffer.getBuffer().getLastRow(); const patchMarker = patchBuffer.markPosition( Patch.layerName, - [insertRow, 0], + patchBuffer.getBuffer().getEndPosition(), {invalidate: 'never', exclusive: false}, ); - return FilePatch.createDelayedFilePatch( + return FilePatch.createHiddenFilePatch( oldFile, newFile, patchMarker, TOO_LARGE, () => { - const [hunks] = buildHunks(diff, patchBuffer); - return new Patch({status: diff.status, hunks, marker: patchMarker}); + const subPatchBuffer = new PatchBuffer(); + const [hunks, nextPatchMarker] = buildHunks(diff, patchBuffer); + const nextPatch = new Patch({status: diff.status, hunks, marker: nextPatchMarker}); + return {patch: nextPatch, patchBuffer: subPatchBuffer}; }, ); } else { From 36ac87cd0af4d9e54f71902aca67a3c4874a1608 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 21:46:28 -0500 Subject: [PATCH 2670/4847] Move collapsing and expanding to MFP --- lib/models/patch/file-patch.js | 53 ++++++++++++++++++++++------ lib/models/patch/multi-file-patch.js | 18 +++++++++- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index 923f0b039d..aec7896cb9 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -1,7 +1,7 @@ import {Emitter} from 'event-kit'; import {nullFile} from './file'; -import Patch from './patch'; +import Patch, {COLLAPSED} from './patch'; import {toGitPathSep} from '../../helpers'; export default class FilePatch { @@ -123,20 +123,43 @@ export default class FilePatch { return this.patch.updateMarkers(map); } - triggerCollapse = () => { - const nextPatch = this.patch.collapsed(); - if (nextPatch !== this.patch) { - this.patch = nextPatch; - this.didChangeRenderStatus(); + triggerCollapseIn(patchBuffer) { + if (!this.patch.getRenderStatus().isVisible()) { + return false; } + + const {patchBuffer: subPatchBuffer, markerMap} = patchBuffer.extractPatchBuffer(this.patch.getRange()); + + const oldPatch = this.patch; + this.patch = Patch.createHiddenPatch(oldPatch.getMarker(), COLLAPSED, () => { + const [marker] = subPatchBuffer.findMarkers(Patch.layerName, {}); + const newPatch = oldPatch.clone({marker}); + + return {patch: newPatch, patchBuffer: subPatchBuffer}; + }); + this.updateMarkers(markerMap); + + this.didChangeRenderStatus(); + return true; } - triggerExpand = () => { - const nextPatch = this.patch.expanded(); - if (nextPatch !== this.patch) { - this.patch = nextPatch; - this.didChangeRenderStatus(); + triggerExpandIn(patchBuffer, {before, after}) { + if (this.patch.getRenderStatus().isVisible()) { + return false; } + + const {patch: nextPatch, patchBuffer: subPatchBuffer} = this.patch.show(); + + patchBuffer + .createInserterAt(this.patch.getInsertionPoint()) + .keepBefore(before) + .keepAfter(after) + .insertPatchBuffer(subPatchBuffer, {callback: map => this.updateMarkers(map)}) + .apply(); + + this.patch = nextPatch; + this.didChangeRenderStatus(); + return true; } didChangeRenderStatus() { @@ -155,6 +178,14 @@ export default class FilePatch { ); } + getStartingMarkers() { + return this.patch.getStartingMarkers(); + } + + getEndingMarkers() { + return this.patch.getEndingMarkers(); + } + buildStagePatchForLines(originalBuffer, nextLayeredBuffer, selectedLineSet) { let newFile = this.getNewFile(); if (this.getStatus() === 'deleted') { diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 7d0a9ae8d4..9c0f738bfe 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -98,7 +98,7 @@ export default class MultiFilePatch { } getFilePatchAt(bufferRow) { - if (bufferRow < 0) { + if (bufferRow < 0 || bufferRow > this.patchBuffer.getBuffer().getLastRow()) { return undefined; } const [marker] = this.patchBuffer.findMarkers('patch', {intersectsRow: bufferRow}); @@ -301,6 +301,22 @@ export default class MultiFilePatch { return false; } + collapseFilePatch(filePatch) { + filePatch.triggerCollapseIn(this.patchBuffer); + } + + expandFilePatch(filePatch) { + const range = filePatch.getMarker().getRange(); + + const beforeFilePatch = this.getFilePatchAt(range.start.row - 1); + const before = beforeFilePatch ? beforeFilePatch.getEndingMarkers() : []; + + const afterFilePatch = this.getFilePatchAt(range.end.row + 1); + const after = afterFilePatch ? afterFilePatch.getStartingMarkers() : []; + + filePatch.triggerExpandIn(this.patchBuffer, {before, after}); + } + isPatchTooLargeOrCollapsed = filePatchPath => { const patch = this.filePatchesByPath.get(filePatchPath); if (!patch) { From 4bba2f41570bf1e2e277c84a350238b7cc5173b2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 21:46:42 -0500 Subject: [PATCH 2671/4847] Use getRenderStatus() methods --- lib/views/multi-file-patch-view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 5bb93e7c7b..bab2e28737 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -22,7 +22,7 @@ import CommitDetailItem from '../items/commit-detail-item'; import IssueishDetailItem from '../items/issueish-detail-item'; import File from '../models/patch/file'; -import {TOO_LARGE, COLLAPSED} from '../models/patch/patch'; +import {TOO_LARGE} from '../models/patch/patch'; const executableText = { [File.modes.NORMAL]: 'non executable', @@ -351,7 +351,7 @@ export default class MultiFilePatchView extends React.Component { openFile={() => this.didOpenFile({selectedFilePatch: filePatch})} toggleFile={() => this.props.toggleFile(filePatch)} - isCollapsed={filePatch.getRenderStatus === TOO_LARGE || filePatch.getRenderStatus === COLLAPSED} + isCollapsed={!filePatch.getRenderStatus().isVisible()} triggerCollapse={filePatch.triggerCollapse} triggerExpand={filePatch.triggerExpand} /> From 5ca5f1207fc17d47b5901639670be9a8651fdb57 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 22 Jan 2019 21:47:00 -0500 Subject: [PATCH 2672/4847] Use MFP-level expand and collapse methods --- test/models/patch/builder.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index d47ccdff1e..1f300a7854 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -869,7 +869,7 @@ describe('buildFilePatch', function() { assert.deepEqual(fp.getStartRange().serialize(), [[0, 0], [0, 0]]); assertInFilePatch(fp).hunks(); - fp.triggerDelayedRender(); + mfp.expandFilePatch(fp); assert.strictEqual(fp.getRenderStatus(), EXPANDED); assert.deepEqual(fp.getMarker().getRange().serialize(), [[0, 0], [3, 6]]); @@ -945,7 +945,7 @@ describe('buildFilePatch', function() { }, ); - fp1.triggerDelayedRender(); + mfp.expandFilePatch(fp1); assert.strictEqual(fp0.getRenderStatus(), EXPANDED); assertInFilePatch(fp0, mfp.getBuffer()).hunks( @@ -1021,7 +1021,7 @@ describe('buildFilePatch', function() { assert.deepEqual(fp1.getMarker().getRange().serialize(), [[0, 0], [0, 0]]); assert.deepEqual(fp2.getMarker().getRange().serialize(), [[0, 0], [0, 0]]); - fp1.triggerDelayedRender(); + mfp.expandFilePatch(fp1); assert.deepEqual(fp0.getMarker().getRange().serialize(), [[0, 0], [0, 0]]); assert.deepEqual(fp1.getMarker().getRange().serialize(), [[0, 0], [3, 6]]); From fae0a50bfa9f38e547fed08636303f28b5a23ed9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 12:00:48 -0500 Subject: [PATCH 2673/4847] Show specific marker layers in PatchBuffer::inspect() --- lib/models/patch/patch-buffer.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 936e9a7735..8858fd4f21 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -87,11 +87,16 @@ export default class PatchBuffer { return {patchBuffer: subBuffer, markerMap}; } - inspect() { + inspect(opts = {}) { + const options = { + layerNames: LAYER_NAMES, + ...opts, + }; + let inspectString = ''; const increasingMarkers = []; - for (const layerName of LAYER_NAMES) { + for (const layerName of options.layerNames) { for (const marker of this.findMarkers(layerName, {})) { increasingMarkers.push({layerName, point: marker.getRange().start, start: true, id: marker.id}); increasingMarkers.push({layerName, point: marker.getRange().end, end: true, id: marker.id}); From 219a4093d8b547d0c1563a4c4f7d25345f8951e1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 13:07:05 -0500 Subject: [PATCH 2674/4847] Implement inspect() methods on patch model classes --- lib/models/patch/file-patch.js | 28 ++++++++++++++ lib/models/patch/hunk.js | 22 +++++++++++ lib/models/patch/multi-file-patch.js | 14 +++++++ lib/models/patch/patch.js | 56 ++++++++++++++++++++++++++++ lib/models/patch/region.js | 17 +++++++++ 5 files changed, 137 insertions(+) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index aec7896cb9..d2d57a3c51 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -271,6 +271,34 @@ export default class FilePatch { } } + /* + * Construct a String containing diagnostic information about the internal state of this FilePatch. + */ + inspect(opts = {}) { + const options = { + indent: 0, + ...opts, + }; + + let indentation = ''; + for (let i = 0; i < options.indent; i++) { + indentation += ' '; + } + + let inspectString = `${indentation}(FilePatch `; + if (this.getOldPath() !== this.getNewPath()) { + inspectString += `oldPath=${this.getOldPath()} newPath=${this.getNewPath()}`; + } else { + inspectString += `path=${this.getPath()}`; + } + inspectString += '\n'; + + inspectString += this.patch.inspect({indent: options.indent + 2}); + + inspectString += `${indentation})\n`; + return inspectString; + } + getHeaderString() { const fromPath = this.getOldPath() || this.getNewPath(); const toPath = this.getNewPath() || this.getOldPath(); diff --git a/lib/models/patch/hunk.js b/lib/models/patch/hunk.js index 6922203bb9..c9302e6aa5 100644 --- a/lib/models/patch/hunk.js +++ b/lib/models/patch/hunk.js @@ -151,4 +151,26 @@ export default class Hunk { toStringIn(buffer) { return this.getRegions().reduce((str, region) => str + region.toStringIn(buffer), this.getHeader() + '\n'); } + + /* + * Construct a String containing internal diagnostic information. + */ + inspect(opts = {}) { + const options = { + indent: 0, + ...opts, + }; + + let indentation = ''; + for (let i = 0; i < options.indent; i++) { + indentation += ' '; + } + + let inspectString = `${indentation}(Hunk marker=${this.marker.id}\n`; + for (const region of this.regions) { + inspectString += region.inspect({indent: options.indent + 2}); + } + inspectString += `${indentation})\n`; + return inspectString; + } } diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 9c0f738bfe..611a4639df 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -339,6 +339,20 @@ export default class MultiFilePatch { return this.filePatches.map(fp => fp.toStringIn(this.getBuffer())).join(''); } + /* + * Construct a string of diagnostic information useful for debugging. + */ + inspect(opts = {}) { + let inspectString = '(MultiFilePatch'; + inspectString += ` filePatchesByMarker=(${Array.from(this.filePatchesByMarker.keys(), m => m.id).join(', ')})`; + inspectString += ` hunksByMarker=(${Array.from(this.hunksByMarker.keys(), m => m.id).join(', ')})\n`; + for (const filePatch of this.filePatches) { + inspectString += filePatch.inspect({indent: 2}); + } + inspectString += ')\n'; + return inspectString; + } + isEqual(other) { return this.toString() === other.toString(); } diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index 3a2e1e1367..0e9c681de1 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -329,6 +329,28 @@ export default class Patch { return this.getHunks().reduce((str, hunk) => str + hunk.toStringIn(buffer), ''); } + /* + * Construct a String containing internal diagnostic information. + */ + inspect(opts = {}) { + const options = { + indent: 0, + ...opts, + }; + + let indentation = ''; + for (let i = 0; i < options.indent; i++) { + indentation += ' '; + } + + let inspectString = `${indentation}(Patch marker=${this.marker.id}\n`; + for (const hunk of this.hunks) { + inspectString += hunk.inspect({indent: options.indent + 2}); + } + inspectString += `${indentation})\n`; + return inspectString; + } + isPresent() { return true; } @@ -353,6 +375,23 @@ class HiddenPatch extends Patch { getRenderStatus() { return this.renderStatus; } + + /* + * Construct a String containing internal diagnostic information. + */ + inspect(opts = {}) { + const options = { + indent: 0, + ...opts, + }; + + let indentation = ''; + for (let i = 0; i < options.indent; i++) { + indentation += ' '; + } + + return `${indentation}(HiddenPatch marker=${this.marker.id})\n`; + } } class NullPatch { @@ -431,6 +470,23 @@ class NullPatch { return ''; } + /* + * Construct a String containing internal diagnostic information. + */ + inspect(opts = {}) { + const options = { + indent: 0, + ...opts, + }; + + let indentation = ''; + for (let i = 0; i < options.indent; i++) { + indentation += ' '; + } + + return `${indentation}(NullPatch)\n`; + } + isPresent() { return false; } diff --git a/lib/models/patch/region.js b/lib/models/patch/region.js index ea30b4b024..43bf03519a 100644 --- a/lib/models/patch/region.js +++ b/lib/models/patch/region.js @@ -121,6 +121,23 @@ class Region { buffer.lineEndingForRow(this.getRange().end.row); } + /* + * Construct a String containing internal diagnostic information. + */ + inspect(opts = {}) { + const options = { + indent: 0, + ...opts, + }; + + let indentation = ''; + for (let i = 0; i < options.indent; i++) { + indentation += ' '; + } + + return `${indentation}(${this.constructor.name} marker=${this.marker.id})\n`; + } + isChange() { return true; } From 9767a871066704701b98e5a0a4acd0905e906b3b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 13:31:42 -0500 Subject: [PATCH 2675/4847] destroyMarkers() calls to... destroy... the markers --- lib/models/patch/hunk.js | 7 +++++++ lib/models/patch/patch.js | 7 +++++++ lib/models/patch/region.js | 4 ++++ 3 files changed, 18 insertions(+) diff --git a/lib/models/patch/hunk.js b/lib/models/patch/hunk.js index c9302e6aa5..c8b69aef57 100644 --- a/lib/models/patch/hunk.js +++ b/lib/models/patch/hunk.js @@ -148,6 +148,13 @@ export default class Hunk { } } + destroyMarkers() { + this.marker.destroy(); + for (const region of this.regions) { + region.destroyMarkers(); + } + } + toStringIn(buffer) { return this.getRegions().reduce((str, region) => str + region.toStringIn(buffer), this.getHeader() + '\n'); } diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index 0e9c681de1..b111ddd314 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -77,6 +77,13 @@ export default class Patch { ); } + destroyMarkers() { + this.marker.destroy(); + for (const hunk of this.hunks) { + hunk.destroyMarkers(); + } + } + updateMarkers(map) { this.marker = map.get(this.marker) || this.marker; for (const hunk of this.hunks) { diff --git a/lib/models/patch/region.js b/lib/models/patch/region.js index 43bf03519a..4d0a14e200 100644 --- a/lib/models/patch/region.js +++ b/lib/models/patch/region.js @@ -115,6 +115,10 @@ class Region { this.marker = map.get(this.marker) || this.marker; } + destroyMarkers() { + this.marker.destroy(); + } + toStringIn(buffer) { const raw = buffer.getTextInRange(this.getRange()); return this.constructor.origin + raw.replace(/\r?\n/g, '$&' + this.constructor.origin) + From b1d7ff5b70fcfdf4180f894c0d7ce3537d258774 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 13:32:08 -0500 Subject: [PATCH 2676/4847] Build hunk data for expanding too-large patches on the correct buffer --- lib/models/patch/builder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 04164d89d1..396ab72601 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -120,7 +120,7 @@ function singleDiffFilePatch(diff, patchBuffer, opts) { oldFile, newFile, patchMarker, TOO_LARGE, () => { const subPatchBuffer = new PatchBuffer(); - const [hunks, nextPatchMarker] = buildHunks(diff, patchBuffer); + const [hunks, nextPatchMarker] = buildHunks(diff, subPatchBuffer); const nextPatch = new Patch({status: diff.status, hunks, marker: nextPatchMarker}); return {patch: nextPatch, patchBuffer: subPatchBuffer}; }, From fc3d89c602ba73411ab3e416f47dbba697391b49 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 13:32:37 -0500 Subject: [PATCH 2677/4847] Fix up Marker-keyed maps in MFP after expand or collapse --- lib/models/patch/multi-file-patch.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 611a4639df..8d1dfe3b4d 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -302,10 +302,26 @@ export default class MultiFilePatch { } collapseFilePatch(filePatch) { + this.filePatchesByMarker.delete(filePatch.getMarker()); + for (const hunk of filePatch.getHunks()) { + this.hunksByMarker.delete(hunk.getMarker()); + } + filePatch.triggerCollapseIn(this.patchBuffer); + + this.filePatchesByMarker.set(filePatch.getMarker(), filePatch); + // This hunk collection should be empty, but let's iterate anyway just in case filePatch was already collapsed + for (const hunk of filePatch.getHunks()) { + this.hunksByMarker.set(hunk.getMarker(), hunk); + } } expandFilePatch(filePatch) { + this.filePatchesByMarker.delete(filePatch.getMarker()); + for (const hunk of filePatch.getHunks()) { + this.hunksByMarker.delete(hunk.getMarker()); + } + const range = filePatch.getMarker().getRange(); const beforeFilePatch = this.getFilePatchAt(range.start.row - 1); @@ -315,6 +331,11 @@ export default class MultiFilePatch { const after = afterFilePatch ? afterFilePatch.getStartingMarkers() : []; filePatch.triggerExpandIn(this.patchBuffer, {before, after}); + + this.filePatchesByMarker.set(filePatch.getMarker(), filePatch); + for (const hunk of filePatch.getHunks()) { + this.hunksByMarker.set(hunk.getMarker(), hunk); + } } isPatchTooLargeOrCollapsed = filePatchPath => { From e1a1a5cd07363212874cf336b3a47381b0eba78a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 13:33:01 -0500 Subject: [PATCH 2678/4847] NullPatch implementations of adjacent-marker methods --- lib/models/patch/patch.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index b111ddd314..5880e67da2 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -461,6 +461,14 @@ class NullPatch { } } + getStartingMarkers() { + return []; + } + + getEndingMarkers() { + return []; + } + buildStagePatchForLines() { return this; } From 37c53cae1b4758684b53172fd3beee8591c22f90 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 13:33:34 -0500 Subject: [PATCH 2679/4847] Defer insertPatchBuffer()'s callback until the marker map is populated --- lib/models/patch/patch-buffer.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 8858fd4f21..761eec0df7 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -144,6 +144,7 @@ class Inserter { this.startPoint = clipped.copy(); this.insertionPoint = clipped.copy(); this.markerBlueprints = []; + this.markerMapCallbacks = []; this.markersBefore = new Set(); this.markersAfter = new Set(); @@ -205,7 +206,7 @@ class Inserter { } if (opts.callback) { - opts.callback(subMarkerMap); + this.markerMapCallbacks.push({markerMap: subMarkerMap, callback: opts.callback}); } return this; @@ -222,6 +223,10 @@ class Inserter { } } + for (const {markerMap, callback} of this.markerMapCallbacks) { + callback(markerMap); + } + for (const beforeMarker of this.markersBefore) { if (!beforeMarker.isReversed()) { beforeMarker.setHeadPosition(this.startPoint); From 9d174a3f5b16020a6336a5a4d53ab2d76c77c0e4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 13:34:45 -0500 Subject: [PATCH 2680/4847] More collapse and expand work --- lib/models/patch/file-patch.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index d2d57a3c51..9196e29c6b 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -128,16 +128,16 @@ export default class FilePatch { return false; } - const {patchBuffer: subPatchBuffer, markerMap} = patchBuffer.extractPatchBuffer(this.patch.getRange()); - const oldPatch = this.patch; - this.patch = Patch.createHiddenPatch(oldPatch.getMarker(), COLLAPSED, () => { - const [marker] = subPatchBuffer.findMarkers(Patch.layerName, {}); - const newPatch = oldPatch.clone({marker}); - - return {patch: newPatch, patchBuffer: subPatchBuffer}; + const position = oldPatch.getRange().start.copy(); + const {patchBuffer: subPatchBuffer, markerMap} = patchBuffer.extractPatchBuffer(oldPatch.getRange()); + oldPatch.destroyMarkers(); + oldPatch.updateMarkers(markerMap); + + const patchMarker = patchBuffer.markPosition(Patch.layerName, position, {invalidate: 'never', exclude: true}); + this.patch = Patch.createHiddenPatch(patchMarker, COLLAPSED, () => { + return {patch: oldPatch, patchBuffer: subPatchBuffer}; }); - this.updateMarkers(markerMap); this.didChangeRenderStatus(); return true; @@ -149,14 +149,17 @@ export default class FilePatch { } const {patch: nextPatch, patchBuffer: subPatchBuffer} = this.patch.show(); + const atStart = this.patch.getInsertionPoint().isEqual([0, 0]); patchBuffer .createInserterAt(this.patch.getInsertionPoint()) .keepBefore(before) .keepAfter(after) - .insertPatchBuffer(subPatchBuffer, {callback: map => this.updateMarkers(map)}) + .insert(atStart ? '' : '\n') + .insertPatchBuffer(subPatchBuffer, {callback: map => nextPatch.updateMarkers(map)}) .apply(); + this.patch.destroyMarkers(); this.patch = nextPatch; this.didChangeRenderStatus(); return true; From a0ae01ca9f617d7e206a95bde4468966fc935e9f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 14:03:44 -0500 Subject: [PATCH 2681/4847] Find adjacent FilePatches by array index instead of markers --- lib/models/patch/multi-file-patch.js | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 8d1dfe3b4d..f47f673c8e 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -317,18 +317,36 @@ export default class MultiFilePatch { } expandFilePatch(filePatch) { + const index = this.filePatches.indexOf(filePatch); + this.filePatchesByMarker.delete(filePatch.getMarker()); for (const hunk of filePatch.getHunks()) { this.hunksByMarker.delete(hunk.getMarker()); } - const range = filePatch.getMarker().getRange(); + const before = []; + let beforeIndex = index - 1; + while (beforeIndex >= 0) { + const beforeFilePatch = this.filePatches[beforeIndex]; + before.push(...beforeFilePatch.getEndingMarkers()); + + if (!beforeFilePatch.getMarker().getRange().isEmpty()) { + break; + } + beforeIndex--; + } - const beforeFilePatch = this.getFilePatchAt(range.start.row - 1); - const before = beforeFilePatch ? beforeFilePatch.getEndingMarkers() : []; + const after = []; + let afterIndex = index + 1; + while (afterIndex < this.filePatches.length) { + const afterFilePatch = this.filePatches[afterIndex]; + after.push(...afterFilePatch.getStartingMarkers()); - const afterFilePatch = this.getFilePatchAt(range.end.row + 1); - const after = afterFilePatch ? afterFilePatch.getStartingMarkers() : []; + if (!afterFilePatch.getMarker().getRange().isEmpty()) { + break; + } + afterIndex++; + } filePatch.triggerExpandIn(this.patchBuffer, {before, after}); From cba6f0578a14e3bd9675837873b7671a3987dfca Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 14:03:50 -0500 Subject: [PATCH 2682/4847] Remove unused argument --- lib/models/patch/multi-file-patch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index f47f673c8e..b9f7f7572f 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -381,7 +381,7 @@ export default class MultiFilePatch { /* * Construct a string of diagnostic information useful for debugging. */ - inspect(opts = {}) { + inspect() { let inspectString = '(MultiFilePatch'; inspectString += ` filePatchesByMarker=(${Array.from(this.filePatchesByMarker.keys(), m => m.id).join(', ')})`; inspectString += ` hunksByMarker=(${Array.from(this.hunksByMarker.keys(), m => m.id).join(', ')})\n`; From 715f10a3823238ab4de29749dfe0c9e72c6b1953 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 14:04:02 -0500 Subject: [PATCH 2683/4847] Touch up expected marker range --- test/models/patch/builder.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 1f300a7854..956a348ec8 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -1025,7 +1025,7 @@ describe('buildFilePatch', function() { assert.deepEqual(fp0.getMarker().getRange().serialize(), [[0, 0], [0, 0]]); assert.deepEqual(fp1.getMarker().getRange().serialize(), [[0, 0], [3, 6]]); - assert.deepEqual(fp2.getMarker().getRange().serialize(), [[4, 0], [4, 0]]); + assert.deepEqual(fp2.getMarker().getRange().serialize(), [[3, 6], [3, 6]]); }); it('does not create a HiddenPatch when the patch has been explicitly expanded', function() { From cff0d2929d8fab24f620a74cf10e06e3a3be6aaa Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 14:05:32 -0500 Subject: [PATCH 2684/4847] Correct expected Hunk header --- test/models/patch/builder.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 956a348ec8..9b0ca9f957 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -1050,7 +1050,7 @@ describe('buildFilePatch', function() { assert.deepEqual(fp.getMarker().getRange().serialize(), [[0, 0], [3, 6]]); assertInFilePatch(fp, mfp.getBuffer()).hunks( { - startRow: 0, endRow: 3, header: '@@ -1,1 +1,2 @@', regions: [ + startRow: 0, endRow: 3, header: '@@ -1,3 +1,3 @@', regions: [ {kind: 'unchanged', string: ' line-0\n', range: [[0, 0], [0, 6]]}, {kind: 'addition', string: '+line-1\n', range: [[1, 0], [1, 6]]}, {kind: 'deletion', string: '-line-2\n', range: [[2, 0], [2, 6]]}, From 2d7c81a74a6e1c9b82b3e473edd7fdf8ab1839e9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 15:49:50 -0500 Subject: [PATCH 2685/4847] Build what-the-diff output instead of just model objects --- test/builder/patch.js | 269 ++++++++++++++++++++++-------------------- 1 file changed, 143 insertions(+), 126 deletions(-) diff --git a/test/builder/patch.js b/test/builder/patch.js index cd8f45a79f..bc02cf6afd 100644 --- a/test/builder/patch.js +++ b/test/builder/patch.js @@ -1,93 +1,74 @@ // Builders for classes related to MultiFilePatches. -import PatchBuffer from '../../lib/models/patch/patch-buffer'; -import MultiFilePatch from '../../lib/models/patch/multi-file-patch'; -import FilePatch from '../../lib/models/patch/file-patch'; -import File, {nullFile} from '../../lib/models/patch/file'; -import Patch from '../../lib/models/patch/patch'; -import Hunk from '../../lib/models/patch/hunk'; -import {Unchanged, Addition, Deletion, NoNewline} from '../../lib/models/patch/region'; - -function appendMarked(patchBuffer, layerName, lines) { - const startPosition = patchBuffer.getInsertionPoint(); - patchBuffer.getBuffer().append(lines.join('\n')); - const marker = patchBuffer.markRange( - layerName, - [startPosition, patchBuffer.getInsertionPoint()], - {invalidate: 'never', exclusive: false}, - ); - patchBuffer.getBuffer().append('\n'); - return marker; -} - -function markFrom(patchBuffer, layerName, startPosition) { - const endPosition = patchBuffer.getInsertionPoint().translate([-1, Infinity]); - return patchBuffer.markRange( - layerName, - [startPosition, endPosition], - {invalidate: 'never', exclusive: false}, - ); -} - -function wrapReturn(patchBuffer, object) { - return {buffer: patchBuffer.getBuffer(), layers: patchBuffer.getLayers(), ...object}; -} +import {buildMultiFilePatch} from '../../lib/models/patch/builder'; +import File from '../../lib/models/patch/file'; class MultiFilePatchBuilder { - constructor(patchBuffer = null) { - this.patchBuffer = patchBuffer; - - this.filePatches = []; + constructor() { + this.rawFilePatches = []; } addFilePatch(block = () => {}) { - const filePatch = new FilePatchBuilder(this.patchBuffer); + const filePatch = new FilePatchBuilder(); block(filePatch); - this.filePatches.push(filePatch.build().filePatch); + this.rawFilePatches.push(filePatch.build().raw); return this; } - build() { - return wrapReturn(this.patchBuffer, { - multiFilePatch: new MultiFilePatch({ - patchBuffer: this.patchBuffer, - filePatches: this.filePatches, - }), - }); + build(opts = {}) { + const raw = this.rawFilePatches; + const multiFilePatch = buildMultiFilePatch(raw, opts); + return {raw, multiFilePatch}; } } class FilePatchBuilder { - constructor(patchBuffer = null) { - this.patchBuffer = patchBuffer; - - this.oldFile = new File({path: 'file', mode: File.modes.NORMAL}); - this.newFile = null; + constructor() { + this._oldPath = 'file'; + this._oldMode = File.modes.NORMAL; + this._oldSymlink = null; + this._newPath = null; + this._newMode = null; + this._newSymlink = null; - this.patchBuilder = new PatchBuilder(this.patchBuffer); + this.patchBuilder = new PatchBuilder(); } setOldFile(block) { const file = new FileBuilder(); block(file); - this.oldFile = file.build().file; + const rawFile = file.build(); + this._oldPath = rawFile.path; + this._oldMode = rawFile.mode; + if (rawFile.symlink) { + this._oldSymlink = rawFile.symlink; + } return this; } nullOldFile() { - this.oldFile = nullFile; + this._oldPath = null; + this._oldMode = null; + this._oldSymlink = null; return this; } setNewFile(block) { const file = new FileBuilder(); block(file); - this.newFile = file.build().file; + const rawFile = file.build(); + this._newPath = rawFile.path; + this._newMode = rawFile.mode; + if (rawFile.symlink) { + this._newSymlink = rawFile.symlink; + } return this; } nullNewFile() { - this.newFile = nullFile; + this._newPath = null; + this._newMode = null; + this._newSymlink = null; return this; } @@ -101,26 +82,54 @@ class FilePatchBuilder { return this; } - renderStatus(...args) { - this.patchBuilder.renderStatus(...args); - return this; - } - empty() { this.patchBuilder.empty(); return this; } - build() { - const {patch} = this.patchBuilder.build(); + build(opts = {}) { + const {raw: rawPatch} = this.patchBuilder.build(); + + if (this._newPath === null) { + this._newPath = this._oldPath; + } - if (this.newFile === null) { - this.newFile = this.oldFile.clone(); + if (this._newMode === null) { + this._newMode = this._oldMode; } - return this.patchBuffer.wrapReturn({ - filePatch: new FilePatch(this.oldFile, this.newFile, patch), - }); + if (this._oldSymlink !== null || this._newSymlink !== null) { + if (rawPatch.hunks.length > 0) { + throw new Error('Cannot have both a symlink target and hunk content'); + } + + const lines = []; + if (this._oldSymlink !== null) { + lines.push(` ${this._oldSymlink}`); + } + if (this._oldSymlink !== null && this._newSymlink !== null) { + lines.push(' --'); + } + if (this._newSymlink !== null) { + lines.push(` ${this._newSymlink}`); + } + } + + const raw = { + oldPath: this._oldPath, + oldMode: this._oldMode, + newPath: this._newPath, + newMode: this._newMode, + ...rawPatch, + }; + + const mfp = buildMultiFilePatch([raw], opts); + const [filePatch] = mfp.getFilePatches(); + + return { + raw, + filePatch, + }; } } @@ -142,37 +151,27 @@ class FileBuilder { } executable() { - return this.mode('100755'); + return this.mode(File.modes.EXECUTABLE); } symlinkTo(destinationPath) { this._symlink = destinationPath; - return this.mode('120000'); + return this.mode(File.modes.SYMLINK); } build() { - return {file: new File({path: this._path, mode: this._mode, symlink: this._symlink})}; + return {path: this._path, mode: this._mode, symlink: this._symlink}; } } class PatchBuilder { - constructor(patchBuffer = null) { - this.patchBuffer = patchBuffer; - - this._renderStatus = undefined; + constructor() { this._status = 'modified'; - this.hunks = []; - - this.patchStart = this.patchBuffer.getInsertionPoint(); + this.rawHunks = []; this.drift = 0; this.explicitlyEmpty = false; } - renderStatus(status) { - this._renderStatus = status; - return this; - } - status(st) { if (['modified', 'added', 'deleted'].indexOf(st) === -1) { throw new Error(`Unrecognized status: ${st} (must be 'modified', 'added' or 'deleted')`); @@ -183,10 +182,10 @@ class PatchBuilder { } addHunk(block = () => {}) { - const builder = new HunkBuilder(this.patchBuffer, this.drift); + const builder = new HunkBuilder(this.drift); block(builder); - const {hunk, drift} = builder.build(); - this.hunks.push(hunk); + const {raw, drift} = builder.build(); + this.rawHunks.push(raw); this.drift = drift; return this; } @@ -197,7 +196,7 @@ class PatchBuilder { } build() { - if (this.hunks.length === 0 && !this.explicitlyEmpty) { + if (this.rawHunks.length === 0 && !this.explicitlyEmpty) { if (this._status === 'modified') { this.addHunk(hunk => hunk.oldRow(1).unchanged('0000').added('0001').deleted('0002').unchanged('0003')); this.addHunk(hunk => hunk.oldRow(10).unchanged('0004').added('0005').deleted('0006').unchanged('0007')); @@ -208,17 +207,27 @@ class PatchBuilder { } } - const marker = markFrom(this.patchBuffer, 'patch', this.patchStart); + const raw = { + status: this._status, + hunks: this.rawHunks, + }; - return wrapReturn(this.patchBuffer, { - patch: new Patch({status: this._status, hunks: this.hunks, marker, renderStatus: this._renderStatus}), - }); + const mfp = buildMultiFilePatch([{ + oldPath: 'file', + oldMode: File.modes.NORMAL, + newPath: 'file', + newMode: File.modes.NORMAL, + ...raw, + }]); + const [filePatch] = mfp.getFilePatches(); + const patch = filePatch.getPatch(); + + return {raw, patch}; } } class HunkBuilder { - constructor(patchBuffer = null, drift = 0) { - this.patchBuffer = patchBuffer; + constructor(drift = 0) { this.drift = drift; this.oldStartRow = 0; @@ -228,8 +237,7 @@ class HunkBuilder { this.sectionHeading = "don't care"; - this.hunkStartPoint = this.patchBuffer.getInsertionPoint(); - this.regions = []; + this.lines = []; } oldRow(rowNumber) { @@ -238,36 +246,38 @@ class HunkBuilder { } unchanged(...lines) { - this.regions.push(new Unchanged(appendMarked(this.patchBuffer, 'unchanged', lines))); + for (const line of lines) { + this.lines.push(` ${line}`); + } return this; } added(...lines) { - this.regions.push(new Addition(appendMarked(this.patchBuffer, 'addition', lines))); + for (const line of lines) { + this.lines.push(`+${line}`); + } return this; } deleted(...lines) { - this.regions.push(new Deletion(appendMarked(this.patchBuffer, 'deletion', lines))); + for (const line of lines) { + this.lines.push(`-${line}`); + } return this; } noNewline() { - this.regions.push(new NoNewline(appendMarked(this.patchBuffer, 'nonewline', [' No newline at end of file']))); + this.lines.push('\\ No newline at end of file'); return this; } build() { - if (this.regions.length === 0) { + if (this.lines.length === 0) { this.unchanged('0000').added('0001').deleted('0002').unchanged('0003'); } if (this.oldRowCount === null) { - this.oldRowCount = this.regions.reduce((count, region) => region.when({ - unchanged: () => count + region.bufferRowCount(), - deletion: () => count + region.bufferRowCount(), - default: () => count, - }), 0); + this.oldRowCount = this.lines.filter(line => /^[ -]/.test(line)).length; } if (this.newStartRow === null) { @@ -275,42 +285,49 @@ class HunkBuilder { } if (this.newRowCount === null) { - this.newRowCount = this.regions.reduce((count, region) => region.when({ - unchanged: () => count + region.bufferRowCount(), - addition: () => count + region.bufferRowCount(), - default: () => count, - }), 0); + this.newRowCount = this.lines.filter(line => /^[ +]/.test(line)).length; } - const marker = markFrom(this.patchBuffer, 'hunk', this.hunkStartPoint); - - return wrapReturn(this.patchBuffer, { - hunk: new Hunk({ - oldStartRow: this.oldStartRow, - oldRowCount: this.oldRowCount, - newStartRow: this.newStartRow, - newRowCount: this.newRowCount, - sectionHeading: this.sectionHeading, - marker, - regions: this.regions, - }), + const raw = { + oldStartLine: this.oldStartRow, + oldLineCount: this.oldRowCount, + newStartLine: this.newStartRow, + newLineCount: this.newRowCount, + heading: this.sectionHeading, + lines: this.lines, + }; + + const mfp = buildMultiFilePatch([{ + oldPath: 'file', + oldMode: File.modes.NORMAL, + newPath: 'file', + newMode: File.modes.NORMAL, + status: 'modified', + hunks: [raw], + }]); + const [fp] = mfp.getFilePatches(); + const [hunk] = fp.getHunks(); + + return { + raw, + hunk, drift: this.drift + this.newRowCount - this.oldRowCount, - }); + }; } } export function multiFilePatchBuilder() { - return new MultiFilePatchBuilder(new PatchBuffer()); + return new MultiFilePatchBuilder(); } export function filePatchBuilder() { - return new FilePatchBuilder(new PatchBuffer()); + return new FilePatchBuilder(); } export function patchBuilder() { - return new PatchBuilder(new PatchBuffer()); + return new PatchBuilder(); } export function hunkBuilder() { - return new HunkBuilder(new PatchBuffer()); + return new HunkBuilder(); } From 537fd0efccaa5ca32d4a47e09a79f18ea8c86925 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 16:19:25 -0500 Subject: [PATCH 2686/4847] Fix building symlink related FilePatches --- test/builder/patch.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/builder/patch.js b/test/builder/patch.js index bc02cf6afd..dbe3f22d27 100644 --- a/test/builder/patch.js +++ b/test/builder/patch.js @@ -41,6 +41,7 @@ class FilePatchBuilder { this._oldPath = rawFile.path; this._oldMode = rawFile.mode; if (rawFile.symlink) { + this.empty(); this._oldSymlink = rawFile.symlink; } return this; @@ -60,6 +61,7 @@ class FilePatchBuilder { this._newPath = rawFile.path; this._newMode = rawFile.mode; if (rawFile.symlink) { + this.empty(); this._newSymlink = rawFile.symlink; } return this; @@ -103,16 +105,18 @@ class FilePatchBuilder { throw new Error('Cannot have both a symlink target and hunk content'); } - const lines = []; + const hb = new HunkBuilder(); if (this._oldSymlink !== null) { - lines.push(` ${this._oldSymlink}`); + hb.unchanged(this._oldSymlink); } if (this._oldSymlink !== null && this._newSymlink !== null) { - lines.push(' --'); + hb.unchanged('--'); } if (this._newSymlink !== null) { - lines.push(` ${this._newSymlink}`); + hb.unchanged(this._newSymlink); } + + rawPatch.hunks = [hb.build().raw]; } const raw = { From 6685330b042a644b5061cf35ee895321b31a12e4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 16:19:46 -0500 Subject: [PATCH 2687/4847] ::reMarkOn() accepts a PatchBuffer --- lib/models/patch/hunk.js | 6 +++++- lib/models/patch/region.js | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/models/patch/hunk.js b/lib/models/patch/hunk.js index c8b69aef57..8bff265dd4 100644 --- a/lib/models/patch/hunk.js +++ b/lib/models/patch/hunk.js @@ -138,7 +138,11 @@ export default class Hunk { } reMarkOn(markable) { - this.marker = markable.markRange(this.getRange(), {invalidate: 'never', exclusive: false}); + this.marker = markable.markRange( + this.constructor.layerName, + this.getRange(), + {invalidate: 'never', exclusive: false}, + ); } updateMarkers(map) { diff --git a/lib/models/patch/region.js b/lib/models/patch/region.js index 4d0a14e200..c4835d4e83 100644 --- a/lib/models/patch/region.js +++ b/lib/models/patch/region.js @@ -108,7 +108,11 @@ class Region { } reMarkOn(markable) { - this.marker = markable.markRange(this.getRange(), {invalidate: 'never', exclusive: false}); + this.marker = markable.markRange( + this.constructor.layerName, + this.getRange(), + {invalidate: 'never', exclusive: false}, + ); } updateMarkers(map) { From 2cd40d3527624151f4f13c980a4404f65c7e3ce1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 23 Jan 2019 16:20:52 -0500 Subject: [PATCH 2688/4847] Adapt MultiFilePatch tests to model changes --- test/models/patch/multi-file-patch.test.js | 65 ++++++++++------------ 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index b5e665da38..ae2c472137 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -2,16 +2,14 @@ import dedent from 'dedent-js'; import {multiFilePatchBuilder, filePatchBuilder} from '../../builder/patch'; -import {TOO_LARGE} from '../../../lib/models/patch/patch'; import {DEFAULT_OPTIONS} from '../../../lib/models/patch/builder.js'; import MultiFilePatch from '../../../lib/models/patch/multi-file-patch'; import {assertInFilePatch} from '../../helpers'; - describe('MultiFilePatch', function() { - it('creates an empty patch when constructed with no arguments', function() { - const empty = new MultiFilePatch({}); + it('creates an empty patch', function() { + const empty = MultiFilePatch.createNull(); assert.isFalse(empty.anyPresent()); assert.lengthOf(empty.getFilePatches(), 0); }); @@ -52,17 +50,17 @@ describe('MultiFilePatch', function() { assert.strictEqual(dup.getFilePatches(), original.getFilePatches()); }); - it('creates a copy with a new buffer and layer set', function() { - const {buffer, layers} = multiFilePatchBuilder().build(); - const dup = original.clone({buffer, layers}); - - assert.strictEqual(dup.getBuffer(), buffer); - assert.strictEqual(dup.getPatchLayer(), layers.patch); - assert.strictEqual(dup.getHunkLayer(), layers.hunk); - assert.strictEqual(dup.getUnchangedLayer(), layers.unchanged); - assert.strictEqual(dup.getAdditionLayer(), layers.addition); - assert.strictEqual(dup.getDeletionLayer(), layers.deletion); - assert.strictEqual(dup.getNoNewlineLayer(), layers.noNewline); + it('creates a copy with a new PatchBuffer', function() { + const {multiFilePatch} = multiFilePatchBuilder().build(); + const dup = original.clone({patchBuffer: multiFilePatch.getLayeredBuffer()}); + + assert.strictEqual(dup.getBuffer(), multiFilePatch.getBuffer()); + assert.strictEqual(dup.getPatchLayer(), multiFilePatch.getPatchLayer()); + assert.strictEqual(dup.getHunkLayer(), multiFilePatch.getHunkLayer()); + assert.strictEqual(dup.getUnchangedLayer(), multiFilePatch.getUnchangedLayer()); + assert.strictEqual(dup.getAdditionLayer(), multiFilePatch.getAdditionLayer()); + assert.strictEqual(dup.getDeletionLayer(), multiFilePatch.getDeletionLayer()); + assert.strictEqual(dup.getNoNewlineLayer(), multiFilePatch.getNoNewlineLayer()); assert.strictEqual(dup.getFilePatches(), original.getFilePatches()); }); @@ -272,12 +270,11 @@ describe('MultiFilePatch', function() { +1;1;1 -1;1;2 1;1;3 - `); }); it('adopts a buffer from a previous patch', function() { - const {multiFilePatch: lastMultiPatch, buffer: lastBuffer, layers: lastLayers} = multiFilePatchBuilder() + const {multiFilePatch: lastMultiPatch} = multiFilePatchBuilder() .addFilePatch(fp => { fp.setOldFile(f => f.path('A0.txt')); fp.addHunk(h => h.unchanged('a0').added('a1').deleted('a2').unchanged('a3')); @@ -293,7 +290,7 @@ describe('MultiFilePatch', function() { }) .build(); - const {multiFilePatch: nextMultiPatch, buffer: nextBuffer, layers: nextLayers} = multiFilePatchBuilder() + const {multiFilePatch: nextMultiPatch} = multiFilePatchBuilder() .addFilePatch(fp => { fp.setOldFile(f => f.path('B0.txt')); fp.addHunk(h => h.unchanged('b0', 'b1').added('b2').unchanged('b3', 'b4')); @@ -309,20 +306,19 @@ describe('MultiFilePatch', function() { }) .build(); - assert.notStrictEqual(nextBuffer, lastBuffer); - assert.notStrictEqual(nextLayers, lastLayers); + assert.notStrictEqual(nextMultiPatch.getBuffer(), lastMultiPatch.getBuffer()); nextMultiPatch.adoptBufferFrom(lastMultiPatch); - assert.strictEqual(nextMultiPatch.getBuffer(), lastBuffer); - assert.strictEqual(nextMultiPatch.getPatchLayer(), lastLayers.patch); - assert.strictEqual(nextMultiPatch.getHunkLayer(), lastLayers.hunk); - assert.strictEqual(nextMultiPatch.getUnchangedLayer(), lastLayers.unchanged); - assert.strictEqual(nextMultiPatch.getAdditionLayer(), lastLayers.addition); - assert.strictEqual(nextMultiPatch.getDeletionLayer(), lastLayers.deletion); - assert.strictEqual(nextMultiPatch.getNoNewlineLayer(), lastLayers.noNewline); + assert.strictEqual(nextMultiPatch.getBuffer(), lastMultiPatch.getBuffer()); + assert.strictEqual(nextMultiPatch.getPatchLayer(), lastMultiPatch.getPatchLayer()); + assert.strictEqual(nextMultiPatch.getHunkLayer(), lastMultiPatch.getHunkLayer()); + assert.strictEqual(nextMultiPatch.getUnchangedLayer(), lastMultiPatch.getUnchangedLayer()); + assert.strictEqual(nextMultiPatch.getAdditionLayer(), lastMultiPatch.getAdditionLayer()); + assert.strictEqual(nextMultiPatch.getDeletionLayer(), lastMultiPatch.getDeletionLayer()); + assert.strictEqual(nextMultiPatch.getNoNewlineLayer(), lastMultiPatch.getNoNewlineLayer()); - assert.deepEqual(lastBuffer.getText(), dedent` + assert.deepEqual(nextMultiPatch.getBuffer().getText(), dedent` b0 b1 b2 @@ -337,29 +333,28 @@ describe('MultiFilePatch', function() { b11 b12 No newline at end of file - `); const assertMarkedLayerRanges = (layer, ranges) => { assert.deepEqual(layer.getMarkers().map(m => m.getRange().serialize()), ranges); }; - assertMarkedLayerRanges(lastLayers.patch, [ + assertMarkedLayerRanges(nextMultiPatch.getPatchLayer(), [ [[0, 0], [4, 2]], [[5, 0], [7, 2]], [[8, 0], [13, 26]], ]); - assertMarkedLayerRanges(lastLayers.hunk, [ + assertMarkedLayerRanges(nextMultiPatch.getHunkLayer(), [ [[0, 0], [4, 2]], [[5, 0], [7, 2]], [[8, 0], [11, 3]], [[12, 0], [13, 26]], ]); - assertMarkedLayerRanges(lastLayers.unchanged, [ + assertMarkedLayerRanges(nextMultiPatch.getUnchangedLayer(), [ [[0, 0], [1, 2]], [[3, 0], [4, 2]], [[5, 0], [6, 2]], [[8, 0], [9, 2]], [[11, 0], [11, 3]], ]); - assertMarkedLayerRanges(lastLayers.addition, [ + assertMarkedLayerRanges(nextMultiPatch.getAdditionLayer(), [ [[2, 0], [2, 2]], [[7, 0], [7, 2]], ]); - assertMarkedLayerRanges(lastLayers.deletion, [ + assertMarkedLayerRanges(nextMultiPatch.getDeletionLayer(), [ [[10, 0], [10, 3]], [[12, 0], [12, 3]], ]); - assertMarkedLayerRanges(lastLayers.noNewline, [ + assertMarkedLayerRanges(nextMultiPatch.getNoNewlineLayer(), [ [[13, 0], [13, 26]], ]); From 5af6a872e0a106ac997bc806f1c597a176395fc9 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 Jan 2019 09:03:44 -0500 Subject: [PATCH 2689/4847] Distinguish between unset and null files --- test/builder/patch.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/builder/patch.js b/test/builder/patch.js index dbe3f22d27..f27429cb92 100644 --- a/test/builder/patch.js +++ b/test/builder/patch.js @@ -3,6 +3,8 @@ import {buildMultiFilePatch} from '../../lib/models/patch/builder'; import File from '../../lib/models/patch/file'; +const UNSET = Symbol('unset'); + class MultiFilePatchBuilder { constructor() { this.rawFilePatches = []; @@ -27,8 +29,9 @@ class FilePatchBuilder { this._oldPath = 'file'; this._oldMode = File.modes.NORMAL; this._oldSymlink = null; - this._newPath = null; - this._newMode = null; + + this._newPath = UNSET; + this._newMode = UNSET; this._newSymlink = null; this.patchBuilder = new PatchBuilder(); @@ -92,11 +95,11 @@ class FilePatchBuilder { build(opts = {}) { const {raw: rawPatch} = this.patchBuilder.build(); - if (this._newPath === null) { + if (this._newPath === UNSET) { this._newPath = this._oldPath; } - if (this._newMode === null) { + if (this._newMode === UNSET) { this._newMode = this._oldMode; } From 8bab5ed828debc4ee41d73c31f1d9babd0700f28 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 Jan 2019 09:04:34 -0500 Subject: [PATCH 2690/4847] Set file patch status on symlink pairs --- test/views/multi-file-patch-view.test.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/test/views/multi-file-patch-view.test.js b/test/views/multi-file-patch-view.test.js index d3436debf5..f56be37719 100644 --- a/test/views/multi-file-patch-view.test.js +++ b/test/views/multi-file-patch-view.test.js @@ -1034,7 +1034,13 @@ describe('MultiFilePatchView', function() { const {multiFilePatch} = multiFilePatchBuilder() .addFilePatch(fp => { + fp.status('deleted'); fp.setOldFile(f => f.path('f0').symlinkTo('elsewhere')); + fp.nullNewFile(); + }) + .addFilePatch(fp => { + fp.status('added'); + fp.nullOldFile(); fp.setNewFile(f => f.path('f0')); tenLineHunk(fp); }) @@ -1043,12 +1049,25 @@ describe('MultiFilePatchView', function() { tenLineHunk(fp); }) .addFilePatch(fp => { - fp.setNewFile(f => f.path('f2')); + fp.status('deleted'); fp.setOldFile(f => f.path('f2').symlinkTo('somewhere')); + fp.nullNewFile(); + }) + .addFilePatch(fp => { + fp.status('added'); + fp.nullOldFile(); + fp.setNewFile(f => f.path('f2')); tenLineHunk(fp); }) .addFilePatch(fp => { + fp.status('deleted'); fp.setOldFile(f => f.path('f3').symlinkTo('unchanged')); + fp.nullNewFile(); + }) + .addFilePatch(fp => { + fp.status('added'); + fp.nullOldFile(); + fp.setNewFile(f => f.path('f3')); tenLineHunk(fp); }) .addFilePatch(fp => { From 97154cbeb7ef8c69b14ccdcd356f7f1dca5dba7f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 Jan 2019 09:12:31 -0500 Subject: [PATCH 2691/4847] fp3 isn't supposed to be a symlink change? --- test/views/multi-file-patch-view.test.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/test/views/multi-file-patch-view.test.js b/test/views/multi-file-patch-view.test.js index f56be37719..bf775699f5 100644 --- a/test/views/multi-file-patch-view.test.js +++ b/test/views/multi-file-patch-view.test.js @@ -1060,14 +1060,7 @@ describe('MultiFilePatchView', function() { tenLineHunk(fp); }) .addFilePatch(fp => { - fp.status('deleted'); - fp.setOldFile(f => f.path('f3').symlinkTo('unchanged')); - fp.nullNewFile(); - }) - .addFilePatch(fp => { - fp.status('added'); - fp.nullOldFile(); - fp.setNewFile(f => f.path('f3')); + fp.setOldFile(f => f.path('f3')); tenLineHunk(fp); }) .addFilePatch(fp => { From 5b35a4f5da3d2473e85c683b62925e3eaf52e3fb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 Jan 2019 09:12:42 -0500 Subject: [PATCH 2692/4847] Use MFP-level collapse and expand functions --- lib/views/multi-file-patch-view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index bab2e28737..3fa7418f6a 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -352,8 +352,8 @@ export default class MultiFilePatchView extends React.Component { toggleFile={() => this.props.toggleFile(filePatch)} isCollapsed={!filePatch.getRenderStatus().isVisible()} - triggerCollapse={filePatch.triggerCollapse} - triggerExpand={filePatch.triggerExpand} + triggerCollapse={() => this.props.multiFilePatch.collapseFilePatch(filePatch)} + triggerExpand={() => this.props.multiFilePatch.expandFilePatch(filePatch)} /> {this.renderSymlinkChangeMeta(filePatch)} {this.renderExecutableModeChangeMeta(filePatch)} From ecb49ead4937e509e5fbeb0eba503e8d59c79532 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 Jan 2019 09:31:13 -0500 Subject: [PATCH 2693/4847] Retain the TextBuffer within a PatchBuffer --- lib/models/patch/patch-buffer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 761eec0df7..82a1c5d40f 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -6,6 +6,8 @@ const LAYER_NAMES = ['unchanged', 'addition', 'deletion', 'nonewline', 'hunk', ' export default class PatchBuffer { constructor() { this.buffer = new TextBuffer(); + this.buffer.retain(); + this.layers = LAYER_NAMES.reduce((map, layerName) => { map[layerName] = this.buffer.addMarkerLayer(); return map; From e6a74b011fdd9f61788eb8f30664f41adec94c8e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 24 Jan 2019 09:31:23 -0500 Subject: [PATCH 2694/4847] NullPatch::reMarkOn() accepts a PatchBuffer --- lib/models/patch/patch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index 5880e67da2..93a6c66a87 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -436,7 +436,7 @@ class NullPatch { } reMarkOn(markable) { - this.marker = markable.markRange(this.getRange(), {invalidate: 'never', exclusive: false}); + this.marker = markable.markRange(Patch.layerName, this.getRange(), {invalidate: 'never', exclusive: false}); } getMaxLineNumberWidth() { From d3fbe3602425aee830dfb7a5e3f7ae7b7d26e93a Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 25 Jan 2019 15:43:01 +0100 Subject: [PATCH 2695/4847] fix filePatches not iterable error when filepatches have not arrived yet --- lib/models/patch/multi-file-patch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index b9f7f7572f..ef38185615 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -11,7 +11,7 @@ export default class MultiFilePatch { constructor({patchBuffer, filePatches}) { this.patchBuffer = patchBuffer; - this.filePatches = filePatches; + this.filePatches = filePatches || []; this.filePatchesByMarker = new Map(); this.filePatchesByPath = new Map(); From ecebd4649ed72742a23c59418c17755ea5e67091 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 25 Jan 2019 15:54:35 +0100 Subject: [PATCH 2696/4847] move chevron to the left to match the old design from #1863 --- lib/views/file-patch-header-view.js | 4 ++-- styles/file-patch-view.less | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/views/file-patch-header-view.js b/lib/views/file-patch-header-view.js index 56ba16c466..93c4cdd9cf 100644 --- a/lib/views/file-patch-header-view.js +++ b/lib/views/file-patch-header-view.js @@ -48,8 +48,8 @@ export default class FilePatchHeaderView extends React.Component { return (
    - {this.renderTitle()} {this.renderCollapseButton()} + {this.renderTitle()} {this.renderButtonGroup()}
    @@ -65,7 +65,7 @@ export default class FilePatchHeaderView extends React.Component { } renderCollapseButton() { - const icon = this.props.isCollapsed ? 'chevron-up' : 'chevron-down'; + const icon = this.props.isCollapsed ? 'chevron-right' : 'chevron-down'; return (

    diff --git a/styles/file-patch-view.less b/styles/file-patch-view.less index 58902b4a09..66ce84aac0 100644 --- a/styles/file-patch-view.less +++ b/styles/file-patch-view.less @@ -64,6 +64,22 @@ margin-right: @component-padding; } + &-message { + font-family: @font-family; + text-align: center; + margin-bottom: 0; + } + + &-showDiffButton { + background: transparent; + border: none; + color: @text-color-highlight; + font-size: 18px; + &:hover { + color: @syntax-text-color + } + } + &-collapseButton { background: transparent; border: none; From 80a11009bc789a49850f1c06a4c5d63505a697dd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 28 Jan 2019 15:22:32 -0500 Subject: [PATCH 2718/4847] Rename "layeredBuffer" variables to "patchBuffer" --- lib/models/patch/file-patch.js | 8 ++++---- lib/models/patch/multi-file-patch.js | 26 ++++++++++++------------ lib/models/patch/patch.js | 30 ++++++++++++++-------------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index 468802f633..658bc1ba39 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -198,7 +198,7 @@ export default class FilePatch { return this.patch.getEndingMarkers(); } - buildStagePatchForLines(originalBuffer, nextLayeredBuffer, selectedLineSet) { + buildStagePatchForLines(originalBuffer, nextPatchBuffer, selectedLineSet) { let newFile = this.getNewFile(); if (this.getStatus() === 'deleted') { if ( @@ -215,13 +215,13 @@ export default class FilePatch { const patch = this.patch.buildStagePatchForLines( originalBuffer, - nextLayeredBuffer, + nextPatchBuffer, selectedLineSet, ); return this.clone({newFile, patch}); } - buildUnstagePatchForLines(originalBuffer, nextLayeredBuffer, selectedLineSet) { + buildUnstagePatchForLines(originalBuffer, nextPatchBuffer, selectedLineSet) { const nonNullFile = this.getNewFile().isPresent() ? this.getNewFile() : this.getOldFile(); let oldFile = this.getNewFile(); let newFile = nonNullFile; @@ -249,7 +249,7 @@ export default class FilePatch { const patch = this.patch.buildUnstagePatchForLines( originalBuffer, - nextLayeredBuffer, + nextPatchBuffer, selectedLineSet, ); return this.clone({oldFile, newFile, patch}); diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index ef38185615..e86f75c09c 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -114,11 +114,11 @@ export default class MultiFilePatch { } getStagePatchForLines(selectedLineSet) { - const nextLayeredBuffer = new PatchBuffer(); + const nextPatchBuffer = new PatchBuffer(); const nextFilePatches = this.getFilePatchesContaining(selectedLineSet).map(fp => { - return fp.buildStagePatchForLines(this.getBuffer(), nextLayeredBuffer, selectedLineSet); + return fp.buildStagePatchForLines(this.getBuffer(), nextPatchBuffer, selectedLineSet); }); - return this.clone({patchBuffer: nextLayeredBuffer, filePatches: nextFilePatches}); + return this.clone({patchBuffer: nextPatchBuffer, filePatches: nextFilePatches}); } getStagePatchForHunk(hunk) { @@ -126,11 +126,11 @@ export default class MultiFilePatch { } getUnstagePatchForLines(selectedLineSet) { - const nextLayeredBuffer = new PatchBuffer(); + const nextPatchBuffer = new PatchBuffer(); const nextFilePatches = this.getFilePatchesContaining(selectedLineSet).map(fp => { - return fp.buildUnstagePatchForLines(this.getBuffer(), nextLayeredBuffer, selectedLineSet); + return fp.buildUnstagePatchForLines(this.getBuffer(), nextPatchBuffer, selectedLineSet); }); - return this.clone({patchBuffer: nextLayeredBuffer, filePatches: nextFilePatches}); + return this.clone({patchBuffer: nextPatchBuffer, filePatches: nextFilePatches}); } getUnstagePatchForHunk(hunk) { @@ -213,29 +213,29 @@ export default class MultiFilePatch { } adoptBufferFrom(lastMultiFilePatch) { - const nextLayeredBuffer = lastMultiFilePatch.getLayeredBuffer(); - nextLayeredBuffer.clearAllLayers(); + const nextPatchBuffer = lastMultiFilePatch.getLayeredBuffer(); + nextPatchBuffer.clearAllLayers(); this.filePatchesByMarker.clear(); this.hunksByMarker.clear(); - nextLayeredBuffer.getBuffer().setText(this.getBuffer().getText()); + nextPatchBuffer.getBuffer().setText(this.getBuffer().getText()); for (const filePatch of this.getFilePatches()) { - filePatch.getPatch().reMarkOn(nextLayeredBuffer); + filePatch.getPatch().reMarkOn(nextPatchBuffer); this.filePatchesByMarker.set(filePatch.getMarker(), filePatch); for (const hunk of filePatch.getHunks()) { - hunk.reMarkOn(nextLayeredBuffer); + hunk.reMarkOn(nextPatchBuffer); this.hunksByMarker.set(hunk.getMarker(), hunk); for (const region of hunk.getRegions()) { - region.reMarkOn(nextLayeredBuffer); + region.reMarkOn(nextPatchBuffer); } } } - this.patchBuffer = nextLayeredBuffer; + this.patchBuffer = nextPatchBuffer; } /* diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index 93a6c66a87..4bdb3b754d 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -132,9 +132,9 @@ export default class Patch { return markers; } - buildStagePatchForLines(originalBuffer, nextLayeredBuffer, rowSet) { + buildStagePatchForLines(originalBuffer, nextPatchBuffer, rowSet) { const originalBaseOffset = this.getMarker().getRange().start.row; - const builder = new BufferBuilder(originalBuffer, originalBaseOffset, nextLayeredBuffer); + const builder = new BufferBuilder(originalBuffer, originalBaseOffset, nextPatchBuffer); const hunks = []; let newRowDelta = 0; @@ -211,9 +211,9 @@ export default class Patch { } } - const marker = nextLayeredBuffer.markRange( + const marker = nextPatchBuffer.markRange( this.constructor.layerName, - [[0, 0], [nextLayeredBuffer.getBuffer().getLastRow() - 1, Infinity]], + [[0, 0], [nextPatchBuffer.getBuffer().getLastRow() - 1, Infinity]], {invalidate: 'never', exclusive: false}, ); @@ -222,9 +222,9 @@ export default class Patch { return this.clone({hunks, status, marker}); } - buildUnstagePatchForLines(originalBuffer, nextLayeredBuffer, rowSet) { + buildUnstagePatchForLines(originalBuffer, nextPatchBuffer, rowSet) { const originalBaseOffset = this.getMarker().getRange().start.row; - const builder = new BufferBuilder(originalBuffer, originalBaseOffset, nextLayeredBuffer); + const builder = new BufferBuilder(originalBuffer, originalBaseOffset, nextPatchBuffer); const hunks = []; let newRowDelta = 0; @@ -308,9 +308,9 @@ export default class Patch { status = 'added'; } - const marker = nextLayeredBuffer.markRange( + const marker = nextPatchBuffer.markRange( this.constructor.layerName, - [[0, 0], [nextLayeredBuffer.getBuffer().getLastRow(), Infinity]], + [[0, 0], [nextPatchBuffer.getBuffer().getLastRow(), Infinity]], {invalidate: 'never', exclusive: false}, ); @@ -512,14 +512,14 @@ class NullPatch { } class BufferBuilder { - constructor(original, originalBaseOffset, nextLayeredBuffer) { + constructor(original, originalBaseOffset, nextPatchBuffer) { this.originalBuffer = original; - this.nextLayeredBuffer = nextLayeredBuffer; + this.nextPatchBuffer = nextPatchBuffer; // The ranges provided to builder methods are expected to be valid within the original buffer. Account for // the position of the Patch within its original TextBuffer, and any existing content already on the next // TextBuffer. - this.offset = this.nextLayeredBuffer.getBuffer().getLastRow() - originalBaseOffset; + this.offset = this.nextPatchBuffer.getBuffer().getLastRow() - originalBaseOffset; this.hunkBufferText = ''; this.hunkRowCount = 0; @@ -562,13 +562,13 @@ class BufferBuilder { } latestHunkWasIncluded() { - this.nextLayeredBuffer.buffer.append(this.hunkBufferText, {normalizeLineEndings: false}); + this.nextPatchBuffer.buffer.append(this.hunkBufferText, {normalizeLineEndings: false}); const regions = this.hunkRegions.map(({RegionKind, range}) => { - return new RegionKind(this.nextLayeredBuffer.layers[RegionKind.layerName]); + return new RegionKind(this.nextPatchBuffer.layers[RegionKind.layerName]); }); - const marker = this.nextLayeredBuffer.markRange('hunk', this.hunkRange, {invalidate: 'never', exclusive: false}); + const marker = this.nextPatchBuffer.markRange('hunk', this.hunkRange, {invalidate: 'never', exclusive: false}); this.hunkBufferText = ''; this.hunkRowCount = 0; @@ -592,6 +592,6 @@ class BufferBuilder { } getLayeredBuffer() { - return this.nextLayeredBuffer; + return this.nextPatchBuffer; } } From d7755798801c725e4b984e47062ccd7bf6bd9984 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 28 Jan 2019 15:34:42 -0500 Subject: [PATCH 2719/4847] Create Regions with a Marker instead of a MarkerLayer --- lib/models/patch/patch.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index 4bdb3b754d..5f4612d383 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -565,7 +565,12 @@ class BufferBuilder { this.nextPatchBuffer.buffer.append(this.hunkBufferText, {normalizeLineEndings: false}); const regions = this.hunkRegions.map(({RegionKind, range}) => { - return new RegionKind(this.nextPatchBuffer.layers[RegionKind.layerName]); + const regionMarker = this.nextPatchBuffer.markRange( + RegionKind.layerName, + range, + {invalidate: 'never', exclusive: false}, + ); + return new RegionKind(regionMarker); }); const marker = this.nextPatchBuffer.markRange('hunk', this.hunkRange, {invalidate: 'never', exclusive: false}); From 3f6672a06f72755f9c2f1015d58086bbae33870d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 28 Jan 2019 15:35:00 -0500 Subject: [PATCH 2720/4847] Query the correct MarkerLayers in tests --- test/models/patch/patch.test.js | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/test/models/patch/patch.test.js b/test/models/patch/patch.test.js index 8307d832b7..09648d39a2 100644 --- a/test/models/patch/patch.test.js +++ b/test/models/patch/patch.test.js @@ -268,13 +268,9 @@ describe('Patch', function() { patch.buildStagePatchForLines(originalBuffer, stageLayeredBuffer, new Set([1, 5, 15, 16, 17, 25])); const layerRanges = [ - ['hunk', stageLayeredBuffer.layers.hunk], - ['unchanged', stageLayeredBuffer.layers.unchanged], - ['addition', stageLayeredBuffer.layers.addition], - ['deletion', stageLayeredBuffer.layers.deletion], - ['noNewline', stageLayeredBuffer.layers.noNewline], - ].reduce((obj, [key, layer]) => { - obj[key] = layer.getMarkers().map(marker => marker.getRange().serialize()); + Hunk.layerName, Unchanged.layerName, Addition.layerName, Deletion.layerName, NoNewline.layerName, + ].reduce((obj, layerName) => { + obj[layerName] = stageLayeredBuffer.findMarkers(layerName, {}).map(marker => marker.getRange().serialize()); return obj; }, {}); @@ -301,7 +297,7 @@ describe('Patch', function() { [[1, 0], [1, 4]], [[11, 0], [12, 4]], ], - noNewline: [ + nonewline: [ [[17, 0], [17, 26]], ], }); @@ -463,13 +459,9 @@ describe('Patch', function() { const {patch, buffer: originalBuffer} = buildPatchFixture(); patch.buildUnstagePatchForLines(originalBuffer, unstageLayeredBuffer, new Set([1, 4, 5, 16, 17, 20, 25])); const layerRanges = [ - ['hunk', unstageLayeredBuffer.layers.hunk], - ['unchanged', unstageLayeredBuffer.layers.unchanged], - ['addition', unstageLayeredBuffer.layers.addition], - ['deletion', unstageLayeredBuffer.layers.deletion], - ['noNewline', unstageLayeredBuffer.layers.noNewline], - ].reduce((obj, [key, layer]) => { - obj[key] = layer.getMarkers().map(marker => marker.getRange().serialize()); + Hunk.layerName, Unchanged.layerName, Addition.layerName, Deletion.layerName, NoNewline.layerName, + ].reduce((obj, layerName) => { + obj[layerName] = unstageLayeredBuffer.findMarkers(layerName, {}).map(marker => marker.getRange().serialize()); return obj; }, {}); @@ -500,7 +492,7 @@ describe('Patch', function() { [[15, 0], [15, 4]], [[18, 0], [18, 4]], ], - noNewline: [ + nonewline: [ [[19, 0], [19, 26]], ], }); From 691c4757fa9768085552283f069570bdc15e1d1a Mon Sep 17 00:00:00 2001 From: annthurium Date: Mon, 28 Jan 2019 13:27:50 -0800 Subject: [PATCH 2721/4847] don't show collapse / expand buttons for `ChangedFileItem` --- lib/views/file-patch-header-view.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/views/file-patch-header-view.js b/lib/views/file-patch-header-view.js index 93c4cdd9cf..8aa1e7ec4e 100644 --- a/lib/views/file-patch-header-view.js +++ b/lib/views/file-patch-header-view.js @@ -65,6 +65,9 @@ export default class FilePatchHeaderView extends React.Component { } renderCollapseButton() { + if (this.props.itemType === ChangedFileItem) { + return null; + } const icon = this.props.isCollapsed ? 'chevron-right' : 'chevron-down'; return (
    @@ -55,13 +59,13 @@ export default class GithubLoginView extends React.Component { renderTokenInput() { return (
    -

    - Step 1: Visit github.atom.io/login to generate - an authentication token. -

    -

    - Step 2: Enter the token below: -

    +
    +
      +
    1. Visit github.atom.io/login to generate + an authentication token.
    2. +
    3. Enter the token below:
    4. +
    + -
    - - -
    +
      +
    • + +
    • +
    • + +
    • +
    ); } diff --git a/styles/github-login-view.less b/styles/github-login-view.less index 974ff37e4f..1124fc4971 100644 --- a/styles/github-login-view.less +++ b/styles/github-login-view.less @@ -1,40 +1,43 @@ -.github-GithubLoginView-Container { - height: 100%; - display: flex; -} - .github-GithubLoginView { - height: 100%; + flex: 1; display: flex; + flex-direction: column; + font-size: 1.25em; .github-GithubLoginView-Subview { flex: 1; display: flex; flex-direction: column; - align-self: center; - align-items: center; - padding: 20px; + justify-content: center; + text-align: center; + padding: @component-padding * 3; - > button, > input { - margin: @component-padding; + > * { + margin: @component-padding 0; } - } - p { - text-align: center; - font-size: @font-size * 1.25; - margin: 0; - - &:first-child { - margin-bottom: 20px; + button { + width: 100%; + overflow: hidden; + text-overflow: ellipsis; } - a { - color: @text-color-info; + ol { + text-align: left; + padding: @component-padding 0; + + a { + color: @text-color-info; + } } - } - input[type=text] { - width: 100%; + ul { + list-style: none; + padding-left: 0; + + li:not(:last-child) { + margin-bottom: @component-padding; + } + } } } diff --git a/styles/github-tab.less b/styles/github-tab.less index 507de3e3d7..91bd36b2f3 100644 --- a/styles/github-tab.less +++ b/styles/github-tab.less @@ -43,10 +43,13 @@ button { width: 100%; - margin-bottom: 10px; overflow: hidden; text-overflow: ellipsis; } + + :not(:last-child) { + margin-bottom: 10px; + } } &-LargeIcon:before { From 890f08ed273ce7e27ce1abdd0b6c4d30dac944a6 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Thu, 31 Jan 2019 14:15:53 +0100 Subject: [PATCH 2782/4847] Align all modals with button controls to the pane's bottom --- lib/views/git-tab-view.js | 4 ++-- styles/git-tab.less | 10 ++++++++-- styles/github-login-view.less | 2 +- styles/github-tab.less | 2 ++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/views/git-tab-view.js b/lib/views/git-tab-view.js index 514aa080a9..f055ea52d3 100644 --- a/lib/views/git-tab-view.js +++ b/lib/views/git-tab-view.js @@ -88,7 +88,7 @@ export default class GitTabView extends React.Component { if (this.props.repository.isTooLarge()) { return (
    -
    +

    Too many changes

    @@ -102,7 +102,7 @@ export default class GitTabView extends React.Component { !isValidWorkdir(this.props.repository.getWorkingDirectoryPath())) { return (
    -
    +

    Unsupported directory

    diff --git a/styles/git-tab.less b/styles/git-tab.less index 4ac04a96d5..db02accbe0 100644 --- a/styles/git-tab.less +++ b/styles/git-tab.less @@ -21,7 +21,9 @@ color: @text-color-subtle; } - &.no-repository { + &.no-repository, + &.too-many-changes, + &.unsupported-directory { display: flex; justify-content: center; font-size: 1.25em; @@ -32,12 +34,16 @@ margin: @component-padding 0; } - .btn.btn-primary { + button { overflow: hidden; text-overflow: ellipsis; } } + &.no-repository { + justify-content: flex-end; + } + &-LargeIcon:before { margin-right: 0; margin-bottom: 30px; diff --git a/styles/github-login-view.less b/styles/github-login-view.less index 1124fc4971..a1378dd7c5 100644 --- a/styles/github-login-view.less +++ b/styles/github-login-view.less @@ -8,7 +8,7 @@ flex: 1; display: flex; flex-direction: column; - justify-content: center; + justify-content: flex-end; text-align: center; padding: @component-padding * 3; diff --git a/styles/github-tab.less b/styles/github-tab.less index 91bd36b2f3..abee88c90e 100644 --- a/styles/github-tab.less +++ b/styles/github-tab.less @@ -36,6 +36,8 @@ } .github-RemoteSelector { + justify-content: flex-end; + ul { list-style: none; padding-left: 0; From 926d377d590c860f8cf13e89b792be746884c62e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 Jan 2019 09:55:55 -0500 Subject: [PATCH 2783/4847] Test case that expands trailing patches --- test/models/patch/multi-file-patch.test.js | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index 363e431b01..79f65b7ab9 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -1024,6 +1024,33 @@ describe('MultiFilePatch', function() { assertInFilePatch(fp3, multiFilePatch.getBuffer()).hunks(hunk({index: 3, start: 12, last: true})); }); + it('collapses and expands the final two file patches', function() { + multiFilePatch.collapseFilePatch(fp3); + multiFilePatch.collapseFilePatch(fp2); + + assert.strictEqual(multiFilePatch.getBuffer().getText(), patchTextForIndexes([0, 1])); + assertInFilePatch(fp0, multiFilePatch.getBuffer()).hunks(hunk({index: 0, start: 0})); + assertInFilePatch(fp1, multiFilePatch.getBuffer()).hunks(hunk({index: 1, start: 4, last: true})); + assertInFilePatch(fp2, multiFilePatch.getBuffer()).hunks(); + assertInFilePatch(fp3, multiFilePatch.getBuffer()).hunks(); + + multiFilePatch.expandFilePatch(fp3); + + assert.strictEqual(multiFilePatch.getBuffer().getText(), patchTextForIndexes([0, 1, 3])); + assertInFilePatch(fp0, multiFilePatch.getBuffer()).hunks(hunk({index: 0, start: 0})); + assertInFilePatch(fp1, multiFilePatch.getBuffer()).hunks(hunk({index: 1, start: 4})); + assertInFilePatch(fp2, multiFilePatch.getBuffer()).hunks(); + assertInFilePatch(fp3, multiFilePatch.getBuffer()).hunks(hunk({index: 3, start: 8, last: true})); + + multiFilePatch.expandFilePatch(fp2); + + assert.strictEqual(multiFilePatch.getBuffer().getText(), patchTextForIndexes([0, 1, 2, 3])); + assertInFilePatch(fp0, multiFilePatch.getBuffer()).hunks(hunk({index: 0, start: 0})); + assertInFilePatch(fp1, multiFilePatch.getBuffer()).hunks(hunk({index: 1, start: 4})); + assertInFilePatch(fp2, multiFilePatch.getBuffer()).hunks(hunk({index: 2, start: 8})); + assertInFilePatch(fp3, multiFilePatch.getBuffer()).hunks(hunk({index: 3, start: 12, last: true})); + }); + describe('when all patches are collapsed', function() { beforeEach(function() { multiFilePatch.collapseFilePatch(fp0); From 569189cc12f90c270e2241dbddcfcb3ce48ab972 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 Jan 2019 13:46:17 -0500 Subject: [PATCH 2784/4847] {exclusive: true} changes the way edits move a marker's head/tail --- test/models/patch/patch-buffer.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index 1d553b11bc..ca4ea294f6 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -258,9 +258,9 @@ describe('PatchBuffer', function() { }); it('preserves markers that should be before or after the modification region', function() { - const before0 = patchBuffer.markRange('patch', [[1, 0], [4, 0]]); - const before1 = patchBuffer.markPosition('hunk', [4, 0]); - const after0 = patchBuffer.markPosition('patch', [4, 0]); + const before0 = patchBuffer.markRange('patch', [[1, 0], [4, 0]], {exclusive: true}); + const before1 = patchBuffer.markRange('hunk', [[4, 0], [4, 0]], {exclusive: true}); + const after0 = patchBuffer.markPosition('patch', [4, 0], {exclusive: true}); const inserter = patchBuffer.createInserterAt([4, 0]); inserter.keepBefore([before0, before1]); From 9777d298ef912ca2f76296fc54f6828d2fade41a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 Jan 2019 13:47:01 -0500 Subject: [PATCH 2785/4847] Fix up both head and tail of zero-length markers at Inserter boundaries --- lib/models/patch/patch-buffer.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 284c93cd55..87990e93b4 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -248,18 +248,34 @@ class Inserter { } for (const beforeMarker of this.markersBefore) { + const isEmpty = beforeMarker.getRange().isEmpty(); + if (!beforeMarker.isReversed()) { beforeMarker.setHeadPosition(this.startPoint); + if (isEmpty) { + beforeMarker.setTailPosition(this.startPoint); + } } else { beforeMarker.setTailPosition(this.startPoint); + if (isEmpty) { + beforeMarker.setHeadPosition(this.startPoint); + } } } for (const afterMarker of this.markersAfter) { + const isEmpty = afterMarker.getRange().isEmpty(); + if (!afterMarker.isReversed()) { afterMarker.setTailPosition(this.insertionPoint); + if (isEmpty) { + afterMarker.setHeadPosition(this.insertionPoint); + } } else { afterMarker.setHeadPosition(this.insertionPoint); + if (isEmpty) { + afterMarker.setTailPosition(this.insertionPoint); + } } } } From 06f5080dc705eb9f9bae1c37e69b9d5c67c4d90f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 Jan 2019 13:47:43 -0500 Subject: [PATCH 2786/4847] Position zero-length markers after an inserted separator newline --- lib/models/patch/file-patch.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index c0fb9b76da..b474fa1a00 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -173,11 +173,31 @@ export default class FilePatch { // (so it isn't also the end of the buffer). Insert a newline *after* the expanding patch when inserting anywhere // but the buffer's end. + if (atEnd && !atStart) { + const beforeNewline = []; + const afterNewline = after.slice(); + + for (const marker of before) { + if (marker.getRange().isEmpty()) { + afterNewline.push(marker); + } else { + beforeNewline.push(marker); + } + } + + patchBuffer + .createInserterAt(this.patch.getInsertionPoint()) + .keepBefore(beforeNewline) + .keepAfter(afterNewline) + .insert('\n') + .apply(); + } + + patchBuffer .createInserterAt(this.patch.getInsertionPoint()) .keepBefore(before) .keepAfter(after) - .insert(atEnd && !atStart ? '\n' : '') .insertPatchBuffer(subPatchBuffer, {callback: map => nextPatch.updateMarkers(map)}) .insert(!atEnd ? '\n' : '') .apply(); From aad548a09c9fd1ea7f4fbb258af815d6b4b57822 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 Jan 2019 14:50:37 -0500 Subject: [PATCH 2787/4847] Use a hideEmptiness prop to prevent TextEditors from displaying a blank line --- lib/atom/atom-text-editor.js | 23 +++++++++++++++++++- styles/atom-text-editor.less | 5 +++++ test/atom/atom-text-editor.test.js | 35 ++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/lib/atom/atom-text-editor.js b/lib/atom/atom-text-editor.js index 8d180480ac..f3333e64db 100644 --- a/lib/atom/atom-text-editor.js +++ b/lib/atom/atom-text-editor.js @@ -22,6 +22,8 @@ const editorCreationProps = { ...editorUpdateProps, }; +const EMPTY_CLASS = 'github-AtomTextEditor-empty'; + export const TextEditorContext = React.createContext(); export default class AtomTextEditor extends React.Component { @@ -34,7 +36,8 @@ export default class AtomTextEditor extends React.Component { didAddSelection: PropTypes.func, didChangeSelectionRange: PropTypes.func, didDestroySelection: PropTypes.func, - observeSelections: PropTypes.func, + + hideEmptiness: PropTypes.bool, refModel: RefHolderPropType, @@ -46,6 +49,8 @@ export default class AtomTextEditor extends React.Component { didAddSelection: () => {}, didChangeSelectionRange: () => {}, didDestroySelection: () => {}, + + hideEmptiness: false, } constructor(props) { @@ -81,8 +86,13 @@ export default class AtomTextEditor extends React.Component { this.subs.add( editor.onDidChangeCursorPosition(this.props.didChangeCursorPosition), editor.observeSelections(this.observeSelections), + editor.onDidChange(this.observeEmptiness), ); + if (editor.isEmpty() && this.props.hideEmptiness) { + editor.getElement().classList.add(EMPTY_CLASS); + } + return null; }); } @@ -90,6 +100,7 @@ export default class AtomTextEditor extends React.Component { componentDidUpdate(prevProps) { const modelProps = extractProps(this.props, editorUpdateProps); this.getRefModel().map(editor => editor.update(modelProps)); + this.observeEmptiness(); } componentWillUnmount() { @@ -110,6 +121,16 @@ export default class AtomTextEditor extends React.Component { this.props.didAddSelection(selection); } + observeEmptiness = () => { + this.getRefModel().map(editor => { + if (editor.isEmpty() && this.props.hideEmptiness) { + this.refElement.map(element => element.classList.add(EMPTY_CLASS)); + } else { + this.refElement.map(element => element.classList.remove(EMPTY_CLASS)); + } + }); + } + contains(element) { return this.refElement.map(e => e.contains(element)).getOr(false); } diff --git a/styles/atom-text-editor.less b/styles/atom-text-editor.less index 3fe58fecf7..8bd338ad98 100644 --- a/styles/atom-text-editor.less +++ b/styles/atom-text-editor.less @@ -3,3 +3,8 @@ width: 100%; height: 100%; } + +// Conceal the automatically added blank line element within TextEditors that we want to actually be empty +.github-AtomTextEditor-empty .line { + display: none; +} diff --git a/test/atom/atom-text-editor.test.js b/test/atom/atom-text-editor.test.js index a2d8cb7e78..194cd5d9b0 100644 --- a/test/atom/atom-text-editor.test.js +++ b/test/atom/atom-text-editor.test.js @@ -221,6 +221,41 @@ describe('AtomTextEditor', function() { }); }); + describe('hideEmptiness', function() { + it('adds the github-AtomTextEditor-empty class when constructed with an empty TextBuffer', function() { + const emptyBuffer = new TextBuffer(); + + const wrapper = mount(); + const element = wrapper.instance().refElement.get(); + + assert.isTrue(element.classList.contains('github-AtomTextEditor-empty')); + }); + + it('removes the github-AtomTextEditor-empty class when constructed with a non-empty TextBuffer', function() { + const nonEmptyBuffer = new TextBuffer({text: 'nonempty\n'}); + + const wrapper = mount(); + const element = wrapper.instance().refElement.get(); + + assert.isFalse(element.classList.contains('github-AtomTextEditor-empty')); + }); + + it('adds and removes the github-AtomTextEditor-empty class as its TextBuffer becomes empty and non-empty', function() { + const buffer = new TextBuffer({text: 'nonempty\n...to start with\n'}); + + const wrapper = mount(); + const element = wrapper.instance().refElement.get(); + + assert.isFalse(element.classList.contains('github-AtomTextEditor-empty')); + + buffer.setText(''); + assert.isTrue(element.classList.contains('github-AtomTextEditor-empty')); + + buffer.setText('asdf\n'); + assert.isFalse(element.classList.contains('github-AtomTextEditor-empty')); + }); + }); + it('detects DOM node membership', function() { const wrapper = mount( , From 3d601cb5bff947aa6a4db98a1bbc5bba169a2056 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 31 Jan 2019 14:50:54 -0500 Subject: [PATCH 2788/4847] Set hideEmptiness on the TextEditor in the MFP view --- lib/views/multi-file-patch-view.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 1e13c76487..9b9380bf1b 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -279,7 +279,8 @@ export default class MultiFilePatchView extends React.Component { didAddSelection={this.didAddSelection} didChangeSelectionRange={this.didChangeSelectionRange} didDestroySelection={this.didDestroySelection} - refModel={this.refEditor}> + refModel={this.refEditor} + hideEmptiness={true}> Date: Thu, 31 Jan 2019 16:17:54 -0500 Subject: [PATCH 2789/4847] Test all permutations of collapsing and expanding on an MFP PatchBuffer --- test/models/patch/multi-file-patch.test.js | 83 +++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index 79f65b7ab9..db6502f846 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -1155,7 +1155,88 @@ describe('MultiFilePatch', function() { }); }); - it('is deterministic regardless of the order in which collapse and expand operations are performed'); + it('is deterministic regardless of the order in which collapse and expand operations are performed', function() { + this.timeout(60000); + + const patches = multiFilePatch.getFilePatches(); + + function expectVisibleAfter(ops, i) { + return ops.reduce((visible, op) => (op.index === i ? op.visibleAfter : visible), true); + } + + const operations = []; + for (let i = 0; i < patches.length; i++) { + operations.push({ + index: i, + visibleAfter: false, + name: `collapse fp${i}`, + canHappenAfter: ops => expectVisibleAfter(ops, i), + action: () => multiFilePatch.collapseFilePatch(patches[i]), + }); + + operations.push({ + index: i, + visibleAfter: true, + name: `expand fp${i}`, + canHappenAfter: ops => !expectVisibleAfter(ops, i), + action: () => multiFilePatch.expandFilePatch(patches[i]), + }); + } + + const operationSequences = []; + + function generateSequencesAfter(prefix) { + const possible = operations + .filter(op => !prefix.includes(op)) + .filter(op => op.canHappenAfter(prefix)); + if (possible.length === 0) { + operationSequences.push(prefix); + } else { + for (const next of possible) { + generateSequencesAfter([...prefix, next]); + } + } + } + generateSequencesAfter([]); + + for (const sequence of operationSequences) { + // Uncomment to see which sequence is causing problems + // console.log(sequence.map(op => op.name).join(' -> ')); + + // Reset to the all-expanded state + multiFilePatch.expandFilePatch(fp0); + multiFilePatch.expandFilePatch(fp1); + multiFilePatch.expandFilePatch(fp2); + multiFilePatch.expandFilePatch(fp3); + + // Perform the operations + for (const operation of sequence) { + operation.action(); + } + + // Ensure the TextBuffer and Markers are in the expected states + const visibleIndexes = []; + for (let i = 0; i < patches.length; i++) { + if (patches[i].getRenderStatus().isVisible()) { + visibleIndexes.push(i); + } + } + const lastVisibleIndex = Math.max(...visibleIndexes); + + assert.strictEqual(multiFilePatch.getBuffer().getText(), patchTextForIndexes(visibleIndexes)); + + let start = 0; + for (let i = 0; i < patches.length; i++) { + const patchAssertions = assertInFilePatch(patches[i], multiFilePatch.getBuffer()); + if (patches[i].getRenderStatus().isVisible()) { + patchAssertions.hunks(hunk({index: i, start, last: lastVisibleIndex === i})); + start += 4; + } else { + patchAssertions.hunks(); + } + } + } + }); }); }); }); From 723fd446e12ceec5b473c8a2ce653b15cb3fc383 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Fri, 1 Feb 2019 10:20:25 +0100 Subject: [PATCH 2790/4847] Be more specific about margins on buttons on Remote Selector view --- styles/github-tab.less | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/styles/github-tab.less b/styles/github-tab.less index abee88c90e..4b81b2977a 100644 --- a/styles/github-tab.less +++ b/styles/github-tab.less @@ -41,6 +41,10 @@ ul { list-style: none; padding-left: 0; + + li:not(:last-child) { + margin-bottom: @component-padding; + } } button { @@ -48,10 +52,6 @@ overflow: hidden; text-overflow: ellipsis; } - - :not(:last-child) { - margin-bottom: 10px; - } } &-LargeIcon:before { From de16f7d69707f926bfb7b319132cc9f95ca4600c Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Fri, 1 Feb 2019 10:28:33 +0100 Subject: [PATCH 2791/4847] Add headings to all informational & dialog views --- lib/views/git-tab-view.js | 5 +++-- lib/views/github-login-view.js | 2 ++ lib/views/github-tab-view.js | 1 + lib/views/remote-selector-view.js | 1 + styles/git-tab.less | 4 ++++ styles/github-login-view.less | 4 ++++ styles/github-tab.less | 4 ++++ 7 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/views/git-tab-view.js b/lib/views/git-tab-view.js index f055ea52d3..20e54b9164 100644 --- a/lib/views/git-tab-view.js +++ b/lib/views/git-tab-view.js @@ -90,7 +90,7 @@ export default class GitTabView extends React.Component {
    -

    Too many changes

    +

    Too many changes

    The repository at {this.props.workingDirectoryPath} has too many changed files to display in Atom. Ensure that you have set up an appropriate .gitignore file. @@ -104,7 +104,7 @@ export default class GitTabView extends React.Component {
    -

    Unsupported directory

    +

    Unsupported directory

    Atom does not support managing Git repositories in your home or root directories.
    @@ -125,6 +125,7 @@ export default class GitTabView extends React.Component {
    +

    Create Repository

    {message}

    + ); @@ -539,7 +545,7 @@ export default class MultiFilePatchView extends React.Component { ); } - renderHunkHeaders(filePatch) { + renderHunkHeaders(filePatch, orderOffset) { const toggleVerb = this.props.stagingStatus === 'unstaged' ? 'Stage' : 'Unstage'; const selectedHunks = new Set( Array.from(this.props.selectedRows, row => this.props.multiFilePatch.getHunkAt(row)), @@ -573,7 +579,7 @@ export default class MultiFilePatchView extends React.Component { return ( - + Date: Thu, 21 Feb 2019 09:15:12 -0500 Subject: [PATCH 2854/4847] hasHunks is never legitimately used... ? --- lib/views/file-patch-header-view.js | 3 +-- lib/views/multi-file-patch-view.js | 1 - test/views/file-patch-header-view.test.js | 8 -------- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/views/file-patch-header-view.js b/lib/views/file-patch-header-view.js index 500718993c..a41b0fef7b 100644 --- a/lib/views/file-patch-header-view.js +++ b/lib/views/file-patch-header-view.js @@ -18,7 +18,6 @@ export default class FilePatchHeaderView extends React.Component { newPath: PropTypes.string, stagingStatus: PropTypes.oneOf(['staged', 'unstaged']), isPartiallyStaged: PropTypes.bool, - hasHunks: PropTypes.bool.isRequired, hasUndoHistory: PropTypes.bool, hasMultipleFileSelections: PropTypes.bool.isRequired, @@ -146,7 +145,7 @@ export default class FilePatchHeaderView extends React.Component { } renderMirrorPatchButton() { - if (!this.props.isPartiallyStaged && this.props.hasHunks) { + if (!this.props.isPartiallyStaged) { return null; } diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 88ffb3d71d..d5c4639e69 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -378,7 +378,6 @@ export default class MultiFilePatchView extends React.Component { newPath={filePatch.getStatus() === 'renamed' ? filePatch.getNewPath() : null} stagingStatus={this.props.stagingStatus} isPartiallyStaged={this.props.isPartiallyStaged} - hasHunks={filePatch.getHunks().length > 0} hasUndoHistory={this.props.hasUndoHistory} hasMultipleFileSelections={this.props.hasMultipleFileSelections} diff --git a/test/views/file-patch-header-view.test.js b/test/views/file-patch-header-view.test.js index 9cff2dc22f..4daeec1027 100644 --- a/test/views/file-patch-header-view.test.js +++ b/test/views/file-patch-header-view.test.js @@ -193,14 +193,6 @@ describe('FilePatchHeaderView', function() { it('includes a toggle to unstaged button when staged', createStagedPatchToggleTest(props)); }); - describe('when the patch contains no hunks', function() { - const props = {hasHunks: false}; - - it('includes a toggle to staged button when unstaged', createUnstagedPatchToggleTest(props)); - - it('includes a toggle to unstaged button when staged', createStagedPatchToggleTest(props)); - }); - describe('the jump-to-file button', function() { it('calls the jump to file file action prop', function() { const openFile = sinon.stub(); From 3fb4c1e68f9d4c7def5b205b726041b7a3cf5941 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 09:31:02 -0500 Subject: [PATCH 2855/4847] Rename isPatchTooLargeOrCollapsed to isPatchVisible --- lib/controllers/pr-reviews-controller.js | 2 +- lib/models/patch/multi-file-patch.js | 7 +++-- lib/views/multi-file-patch-view.js | 6 ++--- lib/views/pr-review-comments-view.js | 5 ++-- .../controllers/pr-reviews-controller.test.js | 2 +- test/models/patch/multi-file-patch.test.js | 26 +++++++++---------- test/views/pr-comments-view.test.js | 4 +-- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index f2a836fc32..fdaf09c434 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -19,7 +19,7 @@ export default class PullRequestReviewsController extends React.Component { ), }), getBufferRowForDiffPosition: PropTypes.func.isRequired, - isPatchTooLargeOrCollapsed: PropTypes.func.isRequired, + isPatchVisible: PropTypes.func.isRequired, } constructor(props) { diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index d0762a16cc..d91e029eb8 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -354,13 +354,12 @@ export default class MultiFilePatch { } } - isPatchTooLargeOrCollapsed = filePatchPath => { + isPatchVisible = filePatchPath => { const patch = this.filePatchesByPath.get(filePatchPath); if (!patch) { - return null; + return false; } - const renderStatus = patch.getRenderStatus(); - return renderStatus === TOO_LARGE || renderStatus === COLLAPSED; + return patch.getRenderStatus().isVisible(); } getBufferRowForDiffPosition = (fileName, diffRow) => { diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index d5c4639e69..2de9e6d03f 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -355,7 +355,7 @@ export default class MultiFilePatchView extends React.Component { ); } else { @@ -392,8 +392,8 @@ export default class MultiFilePatchView extends React.Component { triggerCollapse={() => this.props.multiFilePatch.collapseFilePatch(filePatch)} triggerExpand={() => this.props.multiFilePatch.expandFilePatch(filePatch)} /> - {this.renderSymlinkChangeMeta(filePatch)} - {this.renderExecutableModeChangeMeta(filePatch)} + {!isCollapsed && this.renderSymlinkChangeMeta(filePatch)} + {!isCollapsed && this.renderExecutableModeChangeMeta(filePatch)} diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index f31a9fe36b..dfdefff8df 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -24,7 +24,7 @@ export default class PullRequestCommentsView extends React.Component { })), getBufferRowForDiffPosition: PropTypes.func.isRequired, switchToIssueish: PropTypes.func.isRequired, - isPatchTooLargeOrCollapsed: PropTypes.func.isRequired, + isPatchVisible: PropTypes.func.isRequired, } render() { @@ -35,9 +35,10 @@ export default class PullRequestCommentsView extends React.Component { } // if file patch is collapsed or too large, do not render the comments - if (this.props.isPatchTooLargeOrCollapsed(rootComment.path)) { + if (!this.props.isPatchVisible(rootComment.path)) { return null; } + const nativePath = toNativePathSep(rootComment.path); const row = this.props.getBufferRowForDiffPosition(nativePath, rootComment.position); const point = new Point(row, 0); diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index fcd44eacc8..60e2dbf2be 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -43,7 +43,7 @@ describe('PullRequestReviewsController', function() { switchToIssueish: () => {}, getBufferRowForDiffPosition: () => {}, - isPatchTooLargeOrCollapsed: () => {}, + isPatchVisible: () => true, pullRequest: {reviews}, ...overrideProps, }; diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index db6502f846..8532bea250 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -703,8 +703,8 @@ describe('MultiFilePatch', function() { }); }); - describe('isPatchTooLargeOrCollapsed', function() { - it('returns true if patch exceeds large diff threshold', function() { + describe('isPatchVisible', function() { + it('returns false if patch exceeds large diff threshold', function() { const multiFilePatch = multiFilePatchBuilder() .addFilePatch(fp => { fp.setOldFile(f => f.path('file-0')); @@ -712,20 +712,20 @@ describe('MultiFilePatch', function() { }) .build() .multiFilePatch; - assert.isTrue(multiFilePatch.isPatchTooLargeOrCollapsed('file-0')); + assert.isFalse(multiFilePatch.isPatchVisible('file-0')); }); - it('returns true if patch is collapsed', function() { + it('returns false if patch is collapsed', function() { const multiFilePatch = multiFilePatchBuilder() .addFilePatch(fp => { fp.setOldFile(f => f.path('file-0')); fp.renderStatus(COLLAPSED); }).build().multiFilePatch; - assert.isTrue(multiFilePatch.isPatchTooLargeOrCollapsed('file-0')); + assert.isFalse(multiFilePatch.isPatchVisible('file-0')); }); - it('returns false if patch is expanded', function() { + it('returns true if patch is expanded', function() { const multiFilePatch = multiFilePatchBuilder() .addFilePatch(fp => { fp.setOldFile(f => f.path('file-0')); @@ -734,8 +734,9 @@ describe('MultiFilePatch', function() { .build() .multiFilePatch; - assert.isFalse(multiFilePatch.isPatchTooLargeOrCollapsed('file-0')); + assert.isTrue(multiFilePatch.isPatchVisible('file-0')); }); + it('multiFilePatch with multiple hunks returns correct values', function() { const multiFilePatch = multiFilePatchBuilder() .addFilePatch(fp => { @@ -753,12 +754,12 @@ describe('MultiFilePatch', function() { .build() .multiFilePatch; - assert.isFalse(multiFilePatch.isPatchTooLargeOrCollapsed('expanded-file')); - assert.isTrue(multiFilePatch.isPatchTooLargeOrCollapsed('too-large-file')); - assert.isTrue(multiFilePatch.isPatchTooLargeOrCollapsed('collapsed-file')); + assert.isTrue(multiFilePatch.isPatchVisible('expanded-file')); + assert.isFalse(multiFilePatch.isPatchVisible('too-large-file')); + assert.isFalse(multiFilePatch.isPatchVisible('collapsed-file')); }); - it('returns null if patch does not exist', function() { + it('returns false if patch does not exist', function() { const multiFilePatch = multiFilePatchBuilder() .addFilePatch(fp => { fp.setOldFile(f => f.path('file-0')); @@ -766,11 +767,10 @@ describe('MultiFilePatch', function() { }) .build() .multiFilePatch; - assert.isNull(multiFilePatch.isPatchTooLargeOrCollapsed('invalid-file-path')); + assert.isFalse(multiFilePatch.isPatchVisible('invalid-file-path')); }); }); - describe('diff position translation', function() { it('offsets rows in the first hunk by the first hunk header', function() { const {multiFilePatch} = multiFilePatchBuilder() diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-comments-view.test.js index 53b7ef0eba..ff563441fc 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-comments-view.test.js @@ -14,7 +14,7 @@ describe('PullRequestCommentsView', function() { }; return shallow( { return true; }}); + const wrapper = buildApp(multiFilePatch, pr, {isPatchVisible: () => { return false; }}); const comments = wrapper.find('PullRequestCommentView'); assert.lengthOf(comments, 0); }); From fad1e9158dc1a1b9b4251f4c979a241f11d08676 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 10:05:50 -0500 Subject: [PATCH 2856/4847] Force PullRequestsReviewsContainer to re-render --- lib/views/multi-file-patch-view.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 2de9e6d03f..4edd6ca52f 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -351,13 +351,17 @@ export default class MultiFilePatchView extends React.Component { renderPullRequestReviews() { if (this.props.itemType === IssueishDetailItem) { + // "forceRerender" ensures that the PullRequestCommentsView re-renders each time that the MultiFilePatchView does. + // It doesn't re-query for reviews, but it does re-check patch visibility. return ( ); + forceRerender={{}} + /> + ); } else { return null; } From ab347f93f74e4a49165e799f56ad949cc070533d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 10:25:50 -0500 Subject: [PATCH 2857/4847] ChangedFileContainer tests: :white_check_mark: + :100: --- lib/containers/changed-file-container.js | 1 + .../containers/changed-file-container.test.js | 29 +++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/containers/changed-file-container.js b/lib/containers/changed-file-container.js index b7955a33e1..e97e8ffd2e 100644 --- a/lib/containers/changed-file-container.js +++ b/lib/containers/changed-file-container.js @@ -79,6 +79,7 @@ export default class ChangedFileContainer extends React.Component { const currentMultiFilePatch = data && data.multiFilePatch; if (currentMultiFilePatch !== this.lastMultiFilePatch) { this.sub.dispose(); + /* istanbul ignore else */ if (currentMultiFilePatch) { // Keep this component's renderStatusOverride synchronized with the FilePatch we're rendering this.sub = new CompositeDisposable( diff --git a/test/containers/changed-file-container.test.js b/test/containers/changed-file-container.test.js index e06d2fb520..a9612146a0 100644 --- a/test/containers/changed-file-container.test.js +++ b/test/containers/changed-file-container.test.js @@ -65,7 +65,7 @@ describe('ChangedFileContainer', function() { await assert.async.isTrue(wrapper.update().find('ChangedFileController').exists()); }); - it('adopts the buffer from the previous FilePatch when a new one arrives', async function() { + it('uses a consistent TextBuffer', async function() { const wrapper = mount(buildApp({relPath: 'a.txt', stagingStatus: 'unstaged'})); await assert.async.isTrue(wrapper.update().find('ChangedFileController').exists()); @@ -81,21 +81,6 @@ describe('ChangedFileContainer', function() { assert.strictEqual(nextBuffer, prevBuffer); }); - it('does not adopt a buffer from an unchanged patch', async function() { - const wrapper = mount(buildApp({relPath: 'a.txt', stagingStatus: 'unstaged'})); - await assert.async.isTrue(wrapper.update().find('ChangedFileController').exists()); - - const prevPatch = wrapper.find('ChangedFileController').prop('multiFilePatch'); - sinon.spy(prevPatch, 'adoptBufferFrom'); - - wrapper.setProps({}); - - assert.isFalse(prevPatch.adoptBufferFrom.called); - - const nextPatch = wrapper.find('ChangedFileController').prop('multiFilePatch'); - assert.strictEqual(nextPatch, prevPatch); - }); - it('passes unrecognized props to the FilePatchView', async function() { const extra = Symbol('extra'); const wrapper = mount(buildApp({relPath: 'a.txt', stagingStatus: 'unstaged', extra})); @@ -119,4 +104,16 @@ describe('ChangedFileContainer', function() { assert.notStrictEqual(after, before); assert.strictEqual(after.getFilePatches()[0].getRenderStatus(), EXPANDED); }); + + it('disposes its FilePatch subscription on unmount', async function() { + const wrapper = mount(buildApp({})); + await assert.async.isTrue(wrapper.update().exists('ChangedFileController')); + + const patch = wrapper.find('ChangedFileController').prop('multiFilePatch'); + const [fp] = patch.getFilePatches(); + assert.strictEqual(fp.emitter.listenerCountForEventName('change-render-status'), 1); + + wrapper.unmount(); + assert.strictEqual(fp.emitter.listenerCountForEventName('change-render-status'), 0); + }); }); From fb07191163049b4e3bed017a88ac9126ddbbe205 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 10:33:35 -0500 Subject: [PATCH 2858/4847] FilePatch integration tests :white_check_mark: --- test/integration/file-patch.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/file-patch.test.js b/test/integration/file-patch.test.js index 9b8c5fc59d..63d3746cfc 100644 --- a/test/integration/file-patch.test.js +++ b/test/integration/file-patch.test.js @@ -513,8 +513,8 @@ describe('integration: file patches', function() { await patchContent( 'unstaged', 'sample.js', - [repoPath('target.txt'), 'selected'], - [' No newline at end of file'], + [repoPath('target.txt'), 'added', 'selected'], + [' No newline at end of file', 'nonewline', 'selected'], ); assert.isTrue(getPatchItem('unstaged', 'sample.js').find('.github-FilePatchView-metaTitle').exists()); From c87a28026496362daf02c36fcee2ca924980cbdc Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 10:44:01 -0500 Subject: [PATCH 2859/4847] builder tests :white_check_mark: + :100: --- test/models/patch/builder.test.js | 85 ++++++++++++++----------------- 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 0106c2d451..9ecf093c78 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -2,7 +2,6 @@ import dedent from 'dedent-js'; import {buildFilePatch, buildMultiFilePatch} from '../../../lib/models/patch'; import {TOO_LARGE, EXPANDED} from '../../../lib/models/patch/patch'; -import PatchBuffer from '../../../lib/models/patch/patch-buffer'; import {multiFilePatchBuilder} from '../../builder/patch'; import {assertInPatch, assertInFilePatch} from '../../helpers'; @@ -926,7 +925,7 @@ describe('buildFilePatch', function() { ); }); - it('re-parse a HiddenPatch as a Patch', function() { + it('re-parses a HiddenPatch as a Patch', function() { const mfp = buildMultiFilePatch([ { oldPath: 'first', oldMode: '100644', newPath: 'first', newMode: '100644', status: 'modified', @@ -964,6 +963,44 @@ describe('buildFilePatch', function() { ); }); + it('re-parses a HiddenPatch from a paired symlink diff as a Patch', function() { + const {raw} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.status('deleted'); + fp.setOldFile(f => f.path('big').symlinkTo('/somewhere')); + fp.nullNewFile(); + }) + .addFilePatch(fp => { + fp.status('added'); + fp.nullOldFile(); + fp.setNewFile(f => f.path('big')); + fp.addHunk(h => h.oldRow(1).added('0', '1', '2', '3', '4', '5')); + }) + .build(); + const mfp = buildMultiFilePatch(raw, {largeDiffThreshold: 3}); + + assert.lengthOf(mfp.getFilePatches(), 1); + const [fp] = mfp.getFilePatches(); + + assert.strictEqual(fp.getRenderStatus(), TOO_LARGE); + assert.strictEqual(fp.getOldPath(), 'big'); + assert.strictEqual(fp.getNewPath(), 'big'); + assert.deepEqual(fp.getStartRange().serialize(), [[0, 0], [0, 0]]); + assertInFilePatch(fp).hunks(); + + mfp.expandFilePatch(fp); + + assert.strictEqual(fp.getRenderStatus(), EXPANDED); + assert.deepEqual(fp.getMarker().getRange().serialize(), [[0, 0], [5, 1]]); + assertInFilePatch(fp, mfp.getBuffer()).hunks( + { + startRow: 0, endRow: 5, header: '@@ -1,0 +1,6 @@', regions: [ + {kind: 'addition', string: '+0\n+1\n+2\n+3\n+4\n+5', range: [[0, 0], [5, 1]]}, + ], + }, + ); + }); + it('does not interfere with markers from surrounding visible patches when expanded', function() { const mfp = buildMultiFilePatch([ { @@ -1141,50 +1178,6 @@ describe('buildFilePatch', function() { }); }); - it('uses an existing PatchBuffer if one is provided', function() { - const existing = new PatchBuffer(); - existing - .createInserterAtEnd() - .insert('aaa\n') - .insertMarked('bbb\n', 'patch', {}) - .insertMarked('ccc\n', 'addition', {}) - .insert('ddd\n') - .apply(); - - const {raw} = multiFilePatchBuilder() - .addFilePatch(fp => { - fp.setOldFile(f => f.path('file.txt')); - fp.addHunk(h => h.oldRow(10).unchanged('000').added('111', '222').unchanged('333')); - }) - .build(); - - buildFilePatch(raw, {patchBuffer: existing}); - - assert.strictEqual(existing.getBuffer().getText(), dedent` - 000 - 111 - 222 - 333 - `); - - assert.deepEqual( - existing.findMarkers('patch', {}).map(m => m.getRange().serialize()), - [[[0, 0], [3, 3]]], - ); - assert.deepEqual( - existing.findMarkers('hunk', {}).map(m => m.getRange().serialize()), - [[[0, 0], [3, 3]]], - ); - assert.deepEqual( - existing.findMarkers('unchanged', {}).map(m => m.getRange().serialize()), - [[[0, 0], [0, 3]], [[3, 0], [3, 3]]], - ); - assert.deepEqual( - existing.findMarkers('addition', {}).map(m => m.getRange().serialize()), - [[[1, 0], [2, 3]]], - ); - }); - it('throws an error with an unexpected number of diffs', function() { assert.throws(() => buildFilePatch([1, 2, 3]), /Unexpected number of diffs: 3/); }); From 4b0b676c0b9afb757121667792bebf7b19e766fe Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 10:48:42 -0500 Subject: [PATCH 2860/4847] reMarkOn() is no more --- lib/models/patch/hunk.js | 8 -------- lib/models/patch/patch.js | 12 ------------ lib/models/patch/region.js | 8 -------- test/models/patch/hunk.test.js | 15 --------------- test/models/patch/region.test.js | 11 ----------- 5 files changed, 54 deletions(-) diff --git a/lib/models/patch/hunk.js b/lib/models/patch/hunk.js index 8bff265dd4..65c7ebe4bc 100644 --- a/lib/models/patch/hunk.js +++ b/lib/models/patch/hunk.js @@ -137,14 +137,6 @@ export default class Hunk { .reduce((count, change) => count + change.bufferRowCount(), 0); } - reMarkOn(markable) { - this.marker = markable.markRange( - this.constructor.layerName, - this.getRange(), - {invalidate: 'never', exclusive: false}, - ); - } - updateMarkers(map) { this.marker = map.get(this.marker) || this.marker; for (const region of this.regions) { diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index 4124726bef..ae07554b32 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -69,14 +69,6 @@ export default class Patch { return this.marker.getRange().intersectsRow(row); } - reMarkOn(patchBuffer) { - this.marker = patchBuffer.markRange( - this.constructor.layerName, - this.getRange(), - {invalidate: 'never', exclusive: false}, - ); - } - destroyMarkers() { this.marker.destroy(); for (const hunk of this.hunks) { @@ -436,10 +428,6 @@ class NullPatch { return false; } - reMarkOn(markable) { - this.marker = markable.markRange(Patch.layerName, this.getRange(), {invalidate: 'never', exclusive: false}); - } - getMaxLineNumberWidth() { return 0; } diff --git a/lib/models/patch/region.js b/lib/models/patch/region.js index c4835d4e83..85e05dbeef 100644 --- a/lib/models/patch/region.js +++ b/lib/models/patch/region.js @@ -107,14 +107,6 @@ class Region { return callback(); } - reMarkOn(markable) { - this.marker = markable.markRange( - this.constructor.layerName, - this.getRange(), - {invalidate: 'never', exclusive: false}, - ); - } - updateMarkers(map) { this.marker = map.get(this.marker) || this.marker; } diff --git a/test/models/patch/hunk.test.js b/test/models/patch/hunk.test.js index 4080f261fc..ae6ba01fab 100644 --- a/test/models/patch/hunk.test.js +++ b/test/models/patch/hunk.test.js @@ -193,21 +193,6 @@ describe('Hunk', function() { assert.strictEqual(h1.getMaxLineNumberWidth(), 5); }); - it('creates a new marker on a different markable target', function() { - const h = new Hunk({ - ...attrs, - marker: buffer.markRange([[1, 0], [4, 4]]), - }); - - assert.strictEqual(h.getMarker().layer, buffer.getDefaultMarkerLayer()); - - const nextBuffer = new TextBuffer({text: buffer.getText()}); - h.reMarkOn(nextBuffer); - - assert.deepEqual(h.getRange().serialize(), [[1, 0], [4, 4]]); - assert.strictEqual(h.getMarker().layer, nextBuffer.getDefaultMarkerLayer()); - }); - describe('toStringIn()', function() { it('prints its header', function() { const h = new Hunk({ diff --git a/test/models/patch/region.test.js b/test/models/patch/region.test.js index 9a879c0776..105a8746b5 100644 --- a/test/models/patch/region.test.js +++ b/test/models/patch/region.test.js @@ -29,17 +29,6 @@ describe('Regions', function() { assert.isTrue(addition.includesBufferRow(2)); }); - it('can be re-marked on a new markable target', function() { - assert.strictEqual(addition.getMarker().layer, buffer.getDefaultMarkerLayer()); - - const nextBuffer = new TextBuffer({text: buffer.getText()}); - const nextLayer = nextBuffer.addMarkerLayer(); - addition.reMarkOn(nextLayer); - - assert.strictEqual(addition.getMarker().layer, nextLayer); - assert.deepEqual(addition.getRange().serialize(), [[1, 0], [3, 4]]); - }); - it('can be recognized by the isAddition predicate', function() { assert.isTrue(addition.isAddition()); assert.isFalse(addition.isDeletion()); From 662a1ddb259aee79cbd34d670d3fc6823a79f7d8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 11:01:05 -0500 Subject: [PATCH 2861/4847] Hunk tests :white_check_mark: + :100: --- lib/models/patch/hunk.js | 1 + test/models/patch/hunk.test.js | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/lib/models/patch/hunk.js b/lib/models/patch/hunk.js index 65c7ebe4bc..c4da9a48a8 100644 --- a/lib/models/patch/hunk.js +++ b/lib/models/patch/hunk.js @@ -158,6 +158,7 @@ export default class Hunk { /* * Construct a String containing internal diagnostic information. */ + /* istanbul ignore next */ inspect(opts = {}) { const options = { indent: 0, diff --git a/test/models/patch/hunk.test.js b/test/models/patch/hunk.test.js index ae6ba01fab..b0915e390f 100644 --- a/test/models/patch/hunk.test.js +++ b/test/models/patch/hunk.test.js @@ -193,6 +193,63 @@ describe('Hunk', function() { assert.strictEqual(h1.getMaxLineNumberWidth(), 5); }); + it('updates markers from a marker map', function() { + const oMarker = buffer.markRange([[0, 0], [10, 4]]); + + const h = new Hunk({ + oldStartRow: 0, + newStartRow: 1, + oldRowCount: 2, + newRowCount: 3, + sectionHeading: 'sectionHeading', + marker: oMarker, + regions: [ + new Addition(buffer.markRange([[1, 0], [2, 4]])), + new Deletion(buffer.markRange([[3, 0], [4, 4]])), + new Deletion(buffer.markRange([[5, 0], [6, 4]])), + new Unchanged(buffer.markRange([[7, 0], [10, 4]])), + ], + }); + + h.updateMarkers(new Map()); + assert.strictEqual(h.getMarker(), oMarker); + + const regionUpdateMaps = h.getRegions().map(r => sinon.spy(r, 'updateMarkers')); + + const layer = buffer.addMarkerLayer(); + const nMarker = layer.markRange([[0, 0], [10, 4]]); + const map = new Map([[oMarker, nMarker]]); + + h.updateMarkers(map); + + assert.strictEqual(h.getMarker(), nMarker); + assert.isTrue(regionUpdateMaps.every(spy => spy.calledWith(map))); + }); + + it('destroys all of its markers', function() { + const h = new Hunk({ + oldStartRow: 0, + newStartRow: 1, + oldRowCount: 2, + newRowCount: 3, + sectionHeading: 'sectionHeading', + marker: buffer.markRange([[0, 0], [10, 4]]), + regions: [ + new Addition(buffer.markRange([[1, 0], [2, 4]])), + new Deletion(buffer.markRange([[3, 0], [4, 4]])), + new Deletion(buffer.markRange([[5, 0], [6, 4]])), + new Unchanged(buffer.markRange([[7, 0], [10, 4]])), + ], + }); + + const allMarkers = [h.getMarker(), ...h.getRegions().map(r => r.getMarker())]; + assert.isFalse(allMarkers.some(m => m.isDestroyed())); + + h.destroyMarkers(); + + assert.isTrue(allMarkers.every(m => m.isDestroyed())); + }); + describe('toStringIn()', function() { it('prints its header', function() { const h = new Hunk({ From f85ec22011eea178fc008f2417861f3875210027 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 11:22:24 -0500 Subject: [PATCH 2862/4847] Repository tests :white_check_mark: --- lib/models/patch/multi-file-patch.js | 2 +- test/models/repository.test.js | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index d91e029eb8..bb66638fd8 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -372,7 +372,7 @@ export default class MultiFilePatch { * Construct an apply-able patch String. */ toString() { - return this.filePatches.map(fp => fp.toStringIn(this.getBuffer())).join(''); + return this.filePatches.map(fp => fp.toStringIn(this.getBuffer())).join('') + '\n'; } /* diff --git a/test/models/repository.test.js b/test/models/repository.test.js index 9570d61065..a0e68c9eb1 100644 --- a/test/models/repository.test.js +++ b/test/models/repository.test.js @@ -393,8 +393,7 @@ describe('Repository', function() { @@ -0,0 +1,3 @@ +qux +foo - +bar - + +bar\n `); // Unstage symlink change, leaving deleted file staged @@ -415,8 +414,7 @@ describe('Repository', function() { -foo -bar -baz - - - + -\n `); }); From c4a7294609f46aef39d5a5a381042177fd2365d8 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Thu, 21 Feb 2019 19:32:39 +0000 Subject: [PATCH 2863/4847] fix(package): update react to version 16.8.3 Closes #1971 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ac2a5101f8..50e367e98d 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "moment": "2.23.0", "node-emoji": "^1.8.1", "prop-types": "15.7.2", - "react": "16.8.2", + "react": "16.8.3", "react-dom": "16.8.2", "react-relay": "1.7.0", "react-select": "1.2.1", From fb1b1f9911bab15b7b554b4c795e0c9f6267e879 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Thu, 21 Feb 2019 19:32:43 +0000 Subject: [PATCH 2864/4847] fix(package): update react-dom to version 16.8.3 Closes #1971 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 50e367e98d..dba7fd1726 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "node-emoji": "^1.8.1", "prop-types": "15.7.2", "react": "16.8.3", - "react-dom": "16.8.2", + "react-dom": "16.8.3", "react-relay": "1.7.0", "react-select": "1.2.1", "react-tabs": "^3.0.0", From 201955a8964842d1474c9cc1ba5fdcca293fd6f5 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Thu, 21 Feb 2019 19:32:47 +0000 Subject: [PATCH 2865/4847] chore(package): update lockfile package-lock.json --- package-lock.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 73d92d8248..b50b213f9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7106,20 +7106,20 @@ } }, "react": { - "version": "16.8.2", - "resolved": "https://registry.npmjs.org/react/-/react-16.8.2.tgz", - "integrity": "sha512-aB2ctx9uQ9vo09HVknqv3DGRpI7OIGJhCx3Bt0QqoRluEjHSaObJl+nG12GDdYH6sTgE7YiPJ6ZUyMx9kICdXw==", + "version": "16.8.3", + "resolved": "https://registry.npmjs.org/react/-/react-16.8.3.tgz", + "integrity": "sha512-3UoSIsEq8yTJuSu0luO1QQWYbgGEILm+eJl2QN/VLDi7hL+EN18M3q3oVZwmVzzBJ3DkM7RMdRwBmZZ+b4IzSA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "scheduler": "^0.13.2" + "scheduler": "^0.13.3" }, "dependencies": { "scheduler": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.2.tgz", - "integrity": "sha512-qK5P8tHS7vdEMCW5IPyt8v9MJOHqTrOUgPXib7tqm9vh834ibBX5BNhwkplX/0iOzHW5sXyluehYfS9yrkz9+w==", + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.3.tgz", + "integrity": "sha512-UxN5QRYWtpR1egNWzJcVLk8jlegxAugswQc984lD3kU7NuobsO37/sRfbpTdBjtnD5TBNFA2Q2oLV5+UmPSmEQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -7128,20 +7128,20 @@ } }, "react-dom": { - "version": "16.8.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.2.tgz", - "integrity": "sha512-cPGfgFfwi+VCZjk73buu14pYkYBR1b/SRMSYqkLDdhSEHnSwcuYTPu6/Bh6ZphJFIk80XLvbSe2azfcRzNF+Xg==", + "version": "16.8.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.3.tgz", + "integrity": "sha512-ttMem9yJL4/lpItZAQ2NTFAbV7frotHk5DZEHXUOws2rMmrsvh1Na7ThGT0dTzUIl6pqTOi5tYREfL8AEna3lA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "scheduler": "^0.13.2" + "scheduler": "^0.13.3" }, "dependencies": { "scheduler": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.2.tgz", - "integrity": "sha512-qK5P8tHS7vdEMCW5IPyt8v9MJOHqTrOUgPXib7tqm9vh834ibBX5BNhwkplX/0iOzHW5sXyluehYfS9yrkz9+w==", + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.3.tgz", + "integrity": "sha512-UxN5QRYWtpR1egNWzJcVLk8jlegxAugswQc984lD3kU7NuobsO37/sRfbpTdBjtnD5TBNFA2Q2oLV5+UmPSmEQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" From 6f42f45c3c64abd74da8a2559e82a61c95605ddf Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 15:13:36 -0500 Subject: [PATCH 2866/4847] Remove unused imports --- lib/models/patch/multi-file-patch.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index bb66638fd8..5b28a5f97f 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -2,7 +2,6 @@ import {Range} from 'atom'; import {RBTree} from 'bintrees'; import PatchBuffer from './patch-buffer'; -import {TOO_LARGE, COLLAPSED} from './patch'; export default class MultiFilePatch { static createNull() { From 9e9eed80bb515ba7c149aeb12e7b9680721d18bc Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 15:13:57 -0500 Subject: [PATCH 2867/4847] Consistently use MultiFilePatch.createNull() --- lib/models/repository-states/state.js | 4 ++-- test/controllers/commit-preview-controller.test.js | 2 +- test/controllers/multi-file-patch-controller.test.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/models/repository-states/state.js b/lib/models/repository-states/state.js index 747b7b3ac5..d76548c6fb 100644 --- a/lib/models/repository-states/state.js +++ b/lib/models/repository-states/state.js @@ -281,11 +281,11 @@ export default class State { } getFilePatchForPath(filePath, options = {}) { - return Promise.resolve(new MultiFilePatch({})); + return Promise.resolve(MultiFilePatch.createNull()); } getStagedChangesPatch() { - return Promise.resolve(new MultiFilePatch({})); + return Promise.resolve(MultiFilePatch.createNull()); } readFileFromIndex(filePath) { diff --git a/test/controllers/commit-preview-controller.test.js b/test/controllers/commit-preview-controller.test.js index f4c6944bae..e5d7eac130 100644 --- a/test/controllers/commit-preview-controller.test.js +++ b/test/controllers/commit-preview-controller.test.js @@ -21,7 +21,7 @@ describe('CommitPreviewController', function() { const props = { repository, stagingStatus: 'unstaged', - multiFilePatch: new MultiFilePatch({}), + multiFilePatch: MultiFilePatch.createNull(), workspace: atomEnv.workspace, commands: atomEnv.commands, diff --git a/test/controllers/multi-file-patch-controller.test.js b/test/controllers/multi-file-patch-controller.test.js index aed313dd76..1b3a2cd74b 100644 --- a/test/controllers/multi-file-patch-controller.test.js +++ b/test/controllers/multi-file-patch-controller.test.js @@ -160,7 +160,7 @@ describe('MultiFilePatchController', function() { // Simulate updated patch arrival const promise = wrapper.instance().patchChangePromise; - wrapper.setProps({multiFilePatch: new MultiFilePatch({})}); + wrapper.setProps({multiFilePatch: MultiFilePatch.createNull()}); await promise; // Performs an operation again From 84a91eaeb8b2c2dd79802ef3c904dbe76d7bebcd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 15:15:36 -0500 Subject: [PATCH 2868/4847] Patches end with a newline --- test/models/patch/multi-file-patch.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index 8532bea250..f3abeee01f 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -269,7 +269,7 @@ describe('MultiFilePatch', function() { 1;1;0 +1;1;1 -1;1;2 - 1;1;3 + 1;1;3\n `); }); From 7b0d11f578db4b3b12b00261dc58310d4f835469 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 15:16:43 -0500 Subject: [PATCH 2869/4847] Change MultiFilePatch buffer adoption tests --- test/models/patch/multi-file-patch.test.js | 101 +++++++++------------ 1 file changed, 42 insertions(+), 59 deletions(-) diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index f3abeee01f..f2d8f34c4a 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -4,6 +4,7 @@ import {multiFilePatchBuilder, filePatchBuilder} from '../../builder/patch'; import {TOO_LARGE, COLLAPSED, EXPANDED} from '../../../lib/models/patch/patch'; import MultiFilePatch from '../../../lib/models/patch/multi-file-patch'; +import PatchBuffer from '../../../lib/models/patch/patch-buffer'; import {assertInFilePatch} from '../../helpers'; @@ -273,8 +274,8 @@ describe('MultiFilePatch', function() { `); }); - it('adopts a buffer from a previous patch', function() { - const {multiFilePatch: lastMultiPatch} = multiFilePatchBuilder() + it('adopts a new buffer', function() { + const {multiFilePatch} = multiFilePatchBuilder() .addFilePatch(fp => { fp.setOldFile(f => f.path('A0.txt')); fp.addHunk(h => h.unchanged('a0').added('a1').deleted('a2').unchanged('a3')); @@ -286,52 +287,34 @@ describe('MultiFilePatch', function() { }) .addFilePatch(fp => { fp.setOldFile(f => f.path('A2.txt')); - fp.addHunk(h => h.oldRow(99).deleted('7').noNewline()); - }) - .build(); - - const {multiFilePatch: nextMultiPatch} = multiFilePatchBuilder() - .addFilePatch(fp => { - fp.setOldFile(f => f.path('B0.txt')); - fp.addHunk(h => h.unchanged('b0', 'b1').added('b2').unchanged('b3', 'b4')); - }) - .addFilePatch(fp => { - fp.setOldFile(f => f.path('B1.txt')); - fp.addHunk(h => h.unchanged('b5', 'b6').added('b7')); - }) - .addFilePatch(fp => { - fp.setOldFile(f => f.path('B2.txt')); - fp.addHunk(h => h.unchanged('b8', 'b9').deleted('b10').unchanged('b11')); - fp.addHunk(h => h.oldRow(99).deleted('b12').noNewline()); + fp.addHunk(h => h.oldRow(99).deleted('a10').noNewline()); }) .build(); - assert.notStrictEqual(nextMultiPatch.getBuffer(), lastMultiPatch.getBuffer()); - - nextMultiPatch.adoptBufferFrom(lastMultiPatch); - - assert.strictEqual(nextMultiPatch.getBuffer(), lastMultiPatch.getBuffer()); - assert.strictEqual(nextMultiPatch.getPatchLayer(), lastMultiPatch.getPatchLayer()); - assert.strictEqual(nextMultiPatch.getHunkLayer(), lastMultiPatch.getHunkLayer()); - assert.strictEqual(nextMultiPatch.getUnchangedLayer(), lastMultiPatch.getUnchangedLayer()); - assert.strictEqual(nextMultiPatch.getAdditionLayer(), lastMultiPatch.getAdditionLayer()); - assert.strictEqual(nextMultiPatch.getDeletionLayer(), lastMultiPatch.getDeletionLayer()); - assert.strictEqual(nextMultiPatch.getNoNewlineLayer(), lastMultiPatch.getNoNewlineLayer()); - - assert.deepEqual(nextMultiPatch.getBuffer().getText(), dedent` - b0 - b1 - b2 - b3 - b4 - b5 - b6 - b7 - b8 - b9 - b10 - b11 - b12 + const nextBuffer = new PatchBuffer(); + + multiFilePatch.adoptBuffer(nextBuffer); + + assert.strictEqual(nextBuffer.getBuffer(), multiFilePatch.getBuffer()); + assert.strictEqual(nextBuffer.getLayer('patch'), multiFilePatch.getPatchLayer()); + assert.strictEqual(nextBuffer.getLayer('hunk'), multiFilePatch.getHunkLayer()); + assert.strictEqual(nextBuffer.getLayer('unchanged'), multiFilePatch.getUnchangedLayer()); + assert.strictEqual(nextBuffer.getLayer('addition'), multiFilePatch.getAdditionLayer()); + assert.strictEqual(nextBuffer.getLayer('deletion'), multiFilePatch.getDeletionLayer()); + assert.strictEqual(nextBuffer.getLayer('nonewline'), multiFilePatch.getNoNewlineLayer()); + + assert.deepEqual(nextBuffer.getBuffer().getText(), dedent` + a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 No newline at end of file `); @@ -339,27 +322,27 @@ describe('MultiFilePatch', function() { assert.deepEqual(layer.getMarkers().map(m => m.getRange().serialize()), ranges); }; - assertMarkedLayerRanges(nextMultiPatch.getPatchLayer(), [ - [[0, 0], [4, 2]], [[5, 0], [7, 2]], [[8, 0], [13, 26]], + assertMarkedLayerRanges(nextBuffer.getLayer('patch'), [ + [[0, 0], [3, 2]], [[4, 0], [9, 2]], [[10, 0], [11, 26]], ]); - assertMarkedLayerRanges(nextMultiPatch.getHunkLayer(), [ - [[0, 0], [4, 2]], [[5, 0], [7, 2]], [[8, 0], [11, 3]], [[12, 0], [13, 26]], + assertMarkedLayerRanges(nextBuffer.getLayer('hunk'), [ + [[0, 0], [3, 2]], [[4, 0], [6, 2]], [[7, 0], [9, 2]], [[10, 0], [11, 26]], ]); - assertMarkedLayerRanges(nextMultiPatch.getUnchangedLayer(), [ - [[0, 0], [1, 2]], [[3, 0], [4, 2]], [[5, 0], [6, 2]], [[8, 0], [9, 2]], [[11, 0], [11, 3]], + assertMarkedLayerRanges(nextBuffer.getLayer('unchanged'), [ + [[0, 0], [0, 2]], [[3, 0], [3, 2]], [[4, 0], [4, 2]], [[6, 0], [6, 2]], [[7, 0], [7, 2]], [[9, 0], [9, 2]], ]); - assertMarkedLayerRanges(nextMultiPatch.getAdditionLayer(), [ - [[2, 0], [2, 2]], [[7, 0], [7, 2]], + assertMarkedLayerRanges(nextBuffer.getLayer('addition'), [ + [[1, 0], [1, 2]], [[8, 0], [8, 2]], ]); - assertMarkedLayerRanges(nextMultiPatch.getDeletionLayer(), [ - [[10, 0], [10, 3]], [[12, 0], [12, 3]], + assertMarkedLayerRanges(nextBuffer.getLayer('deletion'), [ + [[2, 0], [2, 2]], [[5, 0], [5, 2]], [[10, 0], [10, 3]], ]); - assertMarkedLayerRanges(nextMultiPatch.getNoNewlineLayer(), [ - [[13, 0], [13, 26]], + assertMarkedLayerRanges(nextBuffer.getLayer('nonewline'), [ + [[11, 0], [11, 26]], ]); - assert.strictEqual(nextMultiPatch.getBufferRowForDiffPosition('B0.txt', 1), 0); - assert.strictEqual(nextMultiPatch.getBufferRowForDiffPosition('B2.txt', 5), 12); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('A0.txt', 1), 0); + assert.strictEqual(multiFilePatch.getBufferRowForDiffPosition('A1.txt', 5), 7); }); describe('derived patch generation', function() { From e043d08a31a83942c8e7bb3e6bf626844c11a51a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 15:17:55 -0500 Subject: [PATCH 2870/4847] getNextSelectionRange => getMaxSelectionIndex+getSelectionRangeForIndex --- test/models/patch/multi-file-patch.test.js | 113 +++++++-------------- 1 file changed, 34 insertions(+), 79 deletions(-) diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index f2d8f34c4a..0917a6e0e4 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -551,24 +551,14 @@ describe('MultiFilePatch', function() { }); }); - describe('next selection range derivation', function() { - it('selects the origin if the new patch is empty', function() { - const {multiFilePatch: lastMultiPatch} = multiFilePatchBuilder().addFilePatch().build(); - const {multiFilePatch: nextMultiPatch} = multiFilePatchBuilder().build(); - - const nextSelectionRange = nextMultiPatch.getNextSelectionRange(lastMultiPatch, new Set()); - assert.deepEqual(nextSelectionRange.serialize(), [[0, 0], [0, 0]]); - }); - - it('selects the first change row if there was no prior selection', function() { - const {multiFilePatch: lastMultiPatch} = multiFilePatchBuilder().build(); - const {multiFilePatch: nextMultiPatch} = multiFilePatchBuilder().addFilePatch().build(); - const nextSelectionRange = nextMultiPatch.getNextSelectionRange(lastMultiPatch, new Set()); - assert.deepEqual(nextSelectionRange.serialize(), [[1, 0], [1, Infinity]]); + describe('maximum selection index', function() { + it('returns zero if there are no selections', function() { + const {multiFilePatch} = multiFilePatchBuilder().addFilePatch().build(); + assert.strictEqual(multiFilePatch.getMaxSelectionIndex(new Set()), 0); }); - it('preserves the numeric index of the highest selected change row', function() { - const {multiFilePatch: lastMultiPatch} = multiFilePatchBuilder() + it('returns the ordinal index of the highest selected change row', function() { + const {multiFilePatch} = multiFilePatchBuilder() .addFilePatch(fp => { fp.addHunk(h => h.unchanged('.').added('0', '1', 'x *').unchanged('.')); fp.addHunk(h => h.unchanged('.').deleted('2').added('3').unchanged('.')); @@ -579,83 +569,48 @@ describe('MultiFilePatch', function() { }) .build(); - const {multiFilePatch: nextMultiPatch} = multiFilePatchBuilder() - .addFilePatch(fp => { - fp.addHunk(h => h.unchanged('.').added('0', '1').unchanged('x', '.')); - fp.addHunk(h => h.unchanged('.').deleted('2').added('3').unchanged('.')); - }) - .addFilePatch(fp => { - fp.addHunk(h => h.unchanged('.').deleted('4', '6 *').unchanged('.')); - fp.addHunk(h => h.unchanged('.').added('7').unchanged('.')); - }) - .build(); - - const nextSelectionRange = nextMultiPatch.getNextSelectionRange(lastMultiPatch, new Set([3, 11])); - assert.deepEqual(nextSelectionRange.serialize(), [[11, 0], [11, Infinity]]); - }); - - describe('when the bottom-most changed row is selected', function() { - it('selects the bottom-most changed row of the new patch', function() { - const {multiFilePatch: lastMultiPatch} = multiFilePatchBuilder() - .addFilePatch(fp => { - fp.addHunk(h => h.unchanged('.').added('0', '1', 'x').unchanged('.')); - fp.addHunk(h => h.unchanged('.').deleted('2').added('3').unchanged('.')); - }) - .addFilePatch(fp => { - fp.addHunk(h => h.unchanged('.').deleted('4', '5', '6').unchanged('.')); - fp.addHunk(h => h.unchanged('.').added('7', '8 *').unchanged('.')); - }) - .build(); - - const {multiFilePatch: nextMultiPatch} = multiFilePatchBuilder() - .addFilePatch(fp => { - fp.addHunk(h => h.unchanged('.').added('0', '1', 'x').unchanged('.')); - fp.addHunk(h => h.unchanged('.').deleted('2').added('3').unchanged('.')); - }) - .addFilePatch(fp => { - fp.addHunk(h => h.unchanged('.').deleted('4', '5', '6').unchanged('.')); - fp.addHunk(h => h.unchanged('.').added('7').unchanged('.')); - }) - .build(); - - const nextSelectionRange = nextMultiPatch.getNextSelectionRange(lastMultiPatch, new Set([16])); - assert.deepEqual(nextSelectionRange.serialize(), [[15, 0], [15, Infinity]]); - }); + assert.strictEqual(multiFilePatch.getMaxSelectionIndex(new Set([3])), 2); + assert.strictEqual(multiFilePatch.getMaxSelectionIndex(new Set([3, 11])), 5); }); + }); - it('skips hunks that were completely selected', function() { - const {multiFilePatch: lastMultiPatch} = multiFilePatchBuilder() - .addFilePatch(fp => { - fp.addHunk(h => h.unchanged('.').added('0').unchanged('.')); - fp.addHunk(h => h.unchanged('.').added('x *', 'x *').unchanged('.')); - }) + describe('selection range by change index', function() { + it('selects the last change row if no longer present', function() { + const {multiFilePatch} = multiFilePatchBuilder() .addFilePatch(fp => { - fp.addHunk(h => h.unchanged('.').deleted('x *').unchanged('.')); + fp.addHunk(h => h.unchanged('.').added('0', '1', '2').unchanged('.')); + fp.addHunk(h => h.unchanged('.').deleted('3').added('4').unchanged('.')); }) .addFilePatch(fp => { - fp.addHunk(h => h.unchanged('.').added('x *', '1').deleted('2').unchanged('.')); - fp.addHunk(h => h.unchanged('.').deleted('x *').unchanged('.')); - fp.addHunk(h => h.unchanged('.', '.').deleted('4', '5 *', '6').unchanged('.')); - fp.addHunk(h => h.unchanged('.').deleted('7', '8').unchanged('.', '.')); + fp.addHunk(h => h.unchanged('.').deleted('5', '6', '7').unchanged('.')); + fp.addHunk(h => h.unchanged('.').added('8').unchanged('.')); }) .build(); - const {multiFilePatch: nextMultiPatch} = multiFilePatchBuilder() + assert.deepEqual(multiFilePatch.getSelectionRangeForIndex(9).serialize(), [[15, 0], [15, Infinity]]); + }); + + it('returns the range of the change row by ordinal', function() { + const {multiFilePatch} = multiFilePatchBuilder() .addFilePatch(fp => { - fp.addHunk(h => h.unchanged('.').added('0').unchanged('.')); + fp.addHunk(h => h.unchanged('.').added('0', '1', '2').unchanged('.')); + fp.addHunk(h => h.unchanged('.').deleted('3').added('4').unchanged('.')); }) .addFilePatch(fp => { - fp.addHunk(h => h.unchanged('.', 'x').added('1').deleted('2').unchanged('.')); - fp.addHunk(h => h.unchanged('.', '.').deleted('4', '6 +').unchanged('.')); - fp.addHunk(h => h.unchanged('.').deleted('7', '8').unchanged('.', '.')); + fp.addHunk(h => h.unchanged('.').deleted('5', '6', '7').unchanged('.')); + fp.addHunk(h => h.unchanged('.').added('8').unchanged('.')); }) .build(); - const nextSelectionRange = nextMultiPatch.getNextSelectionRange( - lastMultiPatch, - new Set([4, 5, 8, 11, 16, 21]), - ); - assert.deepEqual(nextSelectionRange.serialize(), [[11, 0], [11, Infinity]]); + assert.deepEqual(multiFilePatch.getSelectionRangeForIndex(0).serialize(), [[1, 0], [1, Infinity]]); + assert.deepEqual(multiFilePatch.getSelectionRangeForIndex(1).serialize(), [[2, 0], [2, Infinity]]); + assert.deepEqual(multiFilePatch.getSelectionRangeForIndex(2).serialize(), [[3, 0], [3, Infinity]]); + assert.deepEqual(multiFilePatch.getSelectionRangeForIndex(3).serialize(), [[6, 0], [6, Infinity]]); + assert.deepEqual(multiFilePatch.getSelectionRangeForIndex(4).serialize(), [[7, 0], [7, Infinity]]); + assert.deepEqual(multiFilePatch.getSelectionRangeForIndex(5).serialize(), [[10, 0], [10, Infinity]]); + assert.deepEqual(multiFilePatch.getSelectionRangeForIndex(6).serialize(), [[11, 0], [11, Infinity]]); + assert.deepEqual(multiFilePatch.getSelectionRangeForIndex(7).serialize(), [[12, 0], [12, Infinity]]); + assert.deepEqual(multiFilePatch.getSelectionRangeForIndex(8).serialize(), [[15, 0], [15, Infinity]]); }); }); From 5a20cf2f6f88de29fbf26ca79c107f16bd85767e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 15:18:06 -0500 Subject: [PATCH 2871/4847] MultiFilePatch tests: :white_check_mark: + :100: --- lib/models/patch/multi-file-patch.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 5b28a5f97f..72fb5f937b 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -10,7 +10,7 @@ export default class MultiFilePatch { constructor({patchBuffer, filePatches}) { this.patchBuffer = patchBuffer; - this.filePatches = filePatches || []; + this.filePatches = filePatches; this.filePatchesByMarker = new Map(); this.filePatchesByPath = new Map(); @@ -138,12 +138,7 @@ export default class MultiFilePatch { getMaxSelectionIndex(selectedRows) { if (selectedRows.size === 0) { - const [firstPatch] = this.getFilePatches(); - if (!firstPatch) { - return Range.fromObject([[0, 0], [0, 0]]); - } - - return firstPatch.getFirstChangeRange(); + return 0; } const lastMax = Math.max(...selectedRows); @@ -188,7 +183,7 @@ export default class MultiFilePatch { let remainingChangedLines = selectionIndex; let foundRow = false; - let lastChangedRow; + let lastChangedRow = 0; patchLoop: for (const filePatch of this.getFilePatches()) { for (const hunk of filePatch.getHunks()) { @@ -307,7 +302,9 @@ export default class MultiFilePatch { filePatch.triggerCollapseIn(this.patchBuffer); this.filePatchesByMarker.set(filePatch.getMarker(), filePatch); + // This hunk collection should be empty, but let's iterate anyway just in case filePatch was already collapsed + /* istanbul ignore next */ for (const hunk of filePatch.getHunks()) { this.hunksByMarker.set(hunk.getMarker(), hunk); } @@ -377,6 +374,7 @@ export default class MultiFilePatch { /* * Construct a string of diagnostic information useful for debugging. */ + /* istanbul ignore next */ inspect() { let inspectString = '(MultiFilePatch'; inspectString += ` filePatchesByMarker=(${Array.from(this.filePatchesByMarker.keys(), m => m.id).join(', ')})`; @@ -388,6 +386,7 @@ export default class MultiFilePatch { return inspectString; } + /* istanbul ignore next */ isEqual(other) { return this.toString() === other.toString(); } From cc5cba8d285c893a4d12aeea8aed8e30c30814a1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 21 Feb 2019 15:24:17 -0500 Subject: [PATCH 2872/4847] :shirt: --- lib/atom/atom-text-editor.js | 1 + lib/views/multi-file-patch-view.js | 2 ++ test/models/patch/builder.test.js | 2 -- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/atom/atom-text-editor.js b/lib/atom/atom-text-editor.js index f3333e64db..3e4425c0d3 100644 --- a/lib/atom/atom-text-editor.js +++ b/lib/atom/atom-text-editor.js @@ -128,6 +128,7 @@ export default class AtomTextEditor extends React.Component { } else { this.refElement.map(element => element.classList.remove(EMPTY_CLASS)); } + return null; }); } diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 90751c3dae..515c72a1de 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -115,6 +115,7 @@ export default class MultiFilePatchView extends React.Component { lastSelectionIndex = this.props.multiFilePatch.getMaxSelectionIndex(this.props.selectedRows); lastScrollTop = editor.getElement().getScrollTop(); lastScrollLeft = editor.getElement().getScrollLeft(); + return null; }); }), this.props.onDidUpdatePatch(nextPatch => { @@ -141,6 +142,7 @@ export default class MultiFilePatchView extends React.Component { } if (lastScrollTop !== null) { editor.getElement().setScrollTop(lastScrollTop); } if (lastScrollLeft !== null) { editor.getElement().setScrollLeft(lastScrollLeft); } + return null; }); }), ); diff --git a/test/models/patch/builder.test.js b/test/models/patch/builder.test.js index 9ecf093c78..83816454c3 100644 --- a/test/models/patch/builder.test.js +++ b/test/models/patch/builder.test.js @@ -1,5 +1,3 @@ -import dedent from 'dedent-js'; - import {buildFilePatch, buildMultiFilePatch} from '../../../lib/models/patch'; import {TOO_LARGE, EXPANDED} from '../../../lib/models/patch/patch'; import {multiFilePatchBuilder} from '../../builder/patch'; From 6634a4b7ae81ff07bd97a880aa913cec81451836 Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 21 Feb 2019 14:07:10 -0800 Subject: [PATCH 2873/4847] fix mfpView test for preserving the selection index Now we have these functions for willUpdate and didUpdate, which need to be passed in as props and then manually called in the test in order for the component to be in the state we want. Co-Authored-By: Katrina Uychaco --- test/views/multi-file-patch-view.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/views/multi-file-patch-view.test.js b/test/views/multi-file-patch-view.test.js index 9862be3d50..b2c32563d5 100644 --- a/test/views/multi-file-patch-view.test.js +++ b/test/views/multi-file-patch-view.test.js @@ -229,10 +229,23 @@ describe('MultiFilePatchView', function() { it('preserves the selection index when a new file patch arrives in line selection mode', function() { const selectedRowsChanged = sinon.spy(); + + let willUpdate, didUpdate; + const onWillUpdatePatch = cb => { + willUpdate = cb; + return {dispose: () => {}} + } + const onDidUpdatePatch = cb => { + didUpdate = cb; + return {dispose: () => {}} + } + const wrapper = mount(buildApp({ selectedRows: new Set([2]), selectionMode: 'line', selectedRowsChanged, + onWillUpdatePatch, + onDidUpdatePatch })); const {multiFilePatch} = multiFilePatchBuilder() @@ -244,7 +257,9 @@ describe('MultiFilePatchView', function() { }); }).build(); + willUpdate(); wrapper.setProps({multiFilePatch}); + didUpdate(multiFilePatch); assert.sameMembers(Array.from(selectedRowsChanged.lastCall.args[0]), [3]); assert.strictEqual(selectedRowsChanged.lastCall.args[1], 'line'); From ae41e10f2cca6d9c85bf5e3f2490f23c48a7a2e1 Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 21 Feb 2019 14:11:59 -0800 Subject: [PATCH 2874/4847] fix mfpView test for hunk selection mode --- test/views/multi-file-patch-view.test.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/views/multi-file-patch-view.test.js b/test/views/multi-file-patch-view.test.js index b2c32563d5..e995833316 100644 --- a/test/views/multi-file-patch-view.test.js +++ b/test/views/multi-file-patch-view.test.js @@ -295,12 +295,24 @@ describe('MultiFilePatchView', function() { }); }).build(); + let willUpdate, didUpdate; + const onWillUpdatePatch = cb => { + willUpdate = cb; + return {dispose: () => {}} + } + const onDidUpdatePatch = cb => { + didUpdate = cb; + return {dispose: () => {}} + } + const selectedRowsChanged = sinon.spy(); const wrapper = mount(buildApp({ multiFilePatch, selectedRows: new Set([6, 7, 8]), selectionMode: 'hunk', selectedRowsChanged, + onWillUpdatePatch, + onDidUpdatePatch })); const {multiFilePatch: nextMfp} = multiFilePatchBuilder() @@ -320,7 +332,9 @@ describe('MultiFilePatchView', function() { }); }).build(); + willUpdate(); wrapper.setProps({multiFilePatch: nextMfp}); + didUpdate(nextMfp); assert.sameMembers(Array.from(selectedRowsChanged.lastCall.args[0]), [6, 7]); assert.strictEqual(selectedRowsChanged.lastCall.args[1], 'hunk'); From e41ca56fde1390f8acef2f0410e451d5fde28a13 Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 21 Feb 2019 14:28:23 -0800 Subject: [PATCH 2875/4847] :shirt: --- test/views/multi-file-patch-view.test.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/views/multi-file-patch-view.test.js b/test/views/multi-file-patch-view.test.js index e995833316..c222a430c3 100644 --- a/test/views/multi-file-patch-view.test.js +++ b/test/views/multi-file-patch-view.test.js @@ -233,19 +233,19 @@ describe('MultiFilePatchView', function() { let willUpdate, didUpdate; const onWillUpdatePatch = cb => { willUpdate = cb; - return {dispose: () => {}} - } + return {dispose: () => {}}; + }; const onDidUpdatePatch = cb => { didUpdate = cb; - return {dispose: () => {}} - } + return {dispose: () => {}}; + }; const wrapper = mount(buildApp({ selectedRows: new Set([2]), selectionMode: 'line', selectedRowsChanged, onWillUpdatePatch, - onDidUpdatePatch + onDidUpdatePatch, })); const {multiFilePatch} = multiFilePatchBuilder() @@ -298,12 +298,12 @@ describe('MultiFilePatchView', function() { let willUpdate, didUpdate; const onWillUpdatePatch = cb => { willUpdate = cb; - return {dispose: () => {}} - } + return {dispose: () => {}}; + }; const onDidUpdatePatch = cb => { didUpdate = cb; - return {dispose: () => {}} - } + return {dispose: () => {}}; + }; const selectedRowsChanged = sinon.spy(); const wrapper = mount(buildApp({ @@ -312,7 +312,7 @@ describe('MultiFilePatchView', function() { selectionMode: 'hunk', selectedRowsChanged, onWillUpdatePatch, - onDidUpdatePatch + onDidUpdatePatch, })); const {multiFilePatch: nextMfp} = multiFilePatchBuilder() From fbf56e62ef98176d993346fde6dbec3a8a7adf43 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 21 Feb 2019 16:58:42 -0800 Subject: [PATCH 2876/4847] In onDidUpdatePatch callback, let parent component know that we updated the selected row Fixes https://github.com/atom/github/projects/18#card-17958157. Consider reverting https://github.com/atom/github/pull/1913/commits/2dad315efc313518df98613f1103b087330c0aaf as it may be obsoleted by this change. Check with @smashwilson first. Co-Authored-By: Tilde Ann Thurium --- lib/views/multi-file-patch-view.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 515c72a1de..d992239375 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -144,6 +144,7 @@ export default class MultiFilePatchView extends React.Component { if (lastScrollLeft !== null) { editor.getElement().setScrollLeft(lastScrollLeft); } return null; }); + this.didChangeSelectedRows(); }), ); } From 93750c99afb2053e84f119edd5336785531480bf Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 21 Feb 2019 17:20:09 -0800 Subject: [PATCH 2877/4847] fiddle with large diff gate styles - make the hover color brighter because the color I originally picked doesn't look very noticeable on certain themes - add some top and bottom margin so it doesn't look so cramped if the large diff gate exists inthe middle of other patches Co-Authored-By: Katrina Uychaco --- styles/file-patch-view.less | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/styles/file-patch-view.less b/styles/file-patch-view.less index 678eee782c..fa2aa29b3e 100644 --- a/styles/file-patch-view.less +++ b/styles/file-patch-view.less @@ -77,7 +77,7 @@ &-message { font-family: @font-family; text-align: center; - margin-bottom: 0; + margin: 15px 0 0 0; } &-showDiffButton { @@ -85,8 +85,10 @@ border: none; color: @text-color-highlight; font-size: 18px; + margin-bottom: 15px; + &:hover { - color: @syntax-text-color + color: @gh-background-color-blue; } } From 6c83111967dbef06a7a22cc4cb542e1b0400fa6c Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 22 Feb 2019 14:05:07 +0800 Subject: [PATCH 2878/4847] threshold 800 lines! --- lib/models/patch/builder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index bc3ef888a7..f378c3f838 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -9,7 +9,7 @@ import MultiFilePatch from './multi-file-patch'; export const DEFAULT_OPTIONS = { // Number of lines after which we consider the diff "large" // TODO: Set this based on performance measurements - largeDiffThreshold: 100, + largeDiffThreshold: 800, // Map of file path (relative to repository root) to Patch render status (EXPANDED, COLLAPSED, TOO_LARGE) renderStatusOverrides: {}, From 0838f73681fb6123c50be49e13267e6d599c6422 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 22 Feb 2019 15:52:54 +0800 Subject: [PATCH 2879/4847] add MFP view performance metrics --- lib/views/multi-file-patch-view.js | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index d992239375..f7ff96ae27 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -87,6 +87,7 @@ export default class MultiFilePatchView extends React.Component { this.refRoot = new RefHolder(); this.refEditor = new RefHolder(); this.refEditorElement = new RefHolder(); + this.mounted = false; this.subs = new CompositeDisposable(); @@ -151,6 +152,9 @@ export default class MultiFilePatchView extends React.Component { } componentDidMount() { + this.mounted = true; + this.measurePerformance('mount'); + window.addEventListener('mouseup', this.didMouseUp); this.refEditor.map(editor => { // this.props.multiFilePatch is guaranteed to contain at least one FilePatch if is rendered. @@ -171,6 +175,8 @@ export default class MultiFilePatchView extends React.Component { } componentDidUpdate(prevProps, prevState) { + this.measurePerformance('update'); + if (prevProps.refInitialFocus !== this.props.refInitialFocus) { prevProps.refInitialFocus && prevProps.refInitialFocus.setter(null); this.props.refInitialFocus && this.refEditorElement.map(this.props.refInitialFocus.setter); @@ -194,6 +200,12 @@ export default class MultiFilePatchView extends React.Component { {'github-FilePatchView--hunkMode': this.props.selectionMode === 'hunk'}, ); + if (this.mounted) { + performance.mark('MultiFilePatchView-update-start'); + } else { + performance.mark('MultiFilePatchView-mount-start'); + } + return (
    {this.renderCommands()} @@ -1187,4 +1199,23 @@ export default class MultiFilePatchView extends React.Component { return NBSP_CHARACTER.repeat(maxDigits - num.toString().length) + num.toString(); } } + + measurePerformance(action) { + if (action === 'update' || action === 'mount') { + performance.mark(`MultiFilePatchView-${action}-end`); + performance.measure( + `MultiFilePatchView-${action}`, + `MultiFilePatchView-${action}-start`, + `MultiFilePatchView-${action}-end`); + const perf = performance.getEntriesByName(`MultiFilePatchView-${action}`)[0]; + performance.clearMarks(`MultiFilePatchView-${action}-start`); + performance.clearMarks(`MultiFilePatchView-${action}-end`); + performance.clearMeasures(`MultiFilePatchView-${action}`); + addEvent(`MultiFilePatchView-${action}`, { + package: 'github', + filePatchesLineCount: [], + duration: perf.duration, + }); + } + } } From 3f2f592ef7cf0e01bcc9c4f7afdd7f4d73cad00c Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 22 Feb 2019 16:00:29 +0800 Subject: [PATCH 2880/4847] add linecounts --- lib/views/multi-file-patch-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index f7ff96ae27..819a3ddd9a 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -1213,7 +1213,7 @@ export default class MultiFilePatchView extends React.Component { performance.clearMeasures(`MultiFilePatchView-${action}`); addEvent(`MultiFilePatchView-${action}`, { package: 'github', - filePatchesLineCount: [], + filePatchesLineCounts: this.props.multiFilePatch.getFilePatches().map(fp => fp.getPatch().getChangedLineCount()), duration: perf.duration, }); } From fef2d67b40f0adeac934ee2ca2af857218981721 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 22 Feb 2019 16:01:11 +0800 Subject: [PATCH 2881/4847] lint --- lib/views/multi-file-patch-view.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 819a3ddd9a..21c39ff4de 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -1213,7 +1213,9 @@ export default class MultiFilePatchView extends React.Component { performance.clearMeasures(`MultiFilePatchView-${action}`); addEvent(`MultiFilePatchView-${action}`, { package: 'github', - filePatchesLineCounts: this.props.multiFilePatch.getFilePatches().map(fp => fp.getPatch().getChangedLineCount()), + filePatchesLineCounts: this.props.multiFilePatch.getFilePatches().map( + fp => fp.getPatch().getChangedLineCount(), + ), duration: perf.duration, }); } From 5873d143864a9907eacda1e1be53b88fe7d94d7f Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 22 Feb 2019 16:04:59 +0800 Subject: [PATCH 2882/4847] clear all perf markers and measurements unpon unmount --- lib/views/multi-file-patch-view.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 21c39ff4de..a73dc9373b 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -190,6 +190,8 @@ export default class MultiFilePatchView extends React.Component { componentWillUnmount() { window.removeEventListener('mouseup', this.didMouseUp); this.subs.dispose(); + performance.clearMarks(); + performance.clearMeasures(); } render() { From c7158423dc0ac6c920264aef42435fdb2ad59d92 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 22 Feb 2019 17:52:56 +0800 Subject: [PATCH 2883/4847] dispose subscriptions upon commit preview unmount --- lib/containers/commit-preview-container.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/containers/commit-preview-container.js b/lib/containers/commit-preview-container.js index 9abba725dc..388c98be61 100644 --- a/lib/containers/commit-preview-container.js +++ b/lib/containers/commit-preview-container.js @@ -91,6 +91,10 @@ export default class CommitPreviewContainer extends React.Component { ); } + componentWillUnmount() { + this.sub.dispose(); + } + onWillUpdatePatch = cb => this.emitter.on('will-update-patch', cb); onDidUpdatePatch = cb => this.emitter.on('did-update-patch', cb); From b018d22744cf457c3a2fb144dbf37dea316958d7 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 22 Feb 2019 17:53:51 +0800 Subject: [PATCH 2884/4847] dispose subscriptions upon component unmount --- lib/containers/commit-detail-container.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/containers/commit-detail-container.js b/lib/containers/commit-detail-container.js index eedf3370be..c5debebe78 100644 --- a/lib/containers/commit-detail-container.js +++ b/lib/containers/commit-detail-container.js @@ -63,4 +63,8 @@ export default class CommitDetailContainer extends React.Component { /> ); } + + componentWillUnmount() { + this.sub.dispose(); + } } From 7d1acf1c01a57a5abb0a645ba19df0af9b97c0f0 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Fri, 22 Feb 2019 23:19:31 +0800 Subject: [PATCH 2885/4847] set unmount --- lib/views/multi-file-patch-view.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index a73dc9373b..e25097aa82 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -190,6 +190,7 @@ export default class MultiFilePatchView extends React.Component { componentWillUnmount() { window.removeEventListener('mouseup', this.didMouseUp); this.subs.dispose(); + this.mounted = false; performance.clearMarks(); performance.clearMeasures(); } From 35286718f025c48c5673d20cf1bc4dcfef06898e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Feb 2019 11:48:32 -0500 Subject: [PATCH 2886/4847] Hide .cursor-line instead of .line If we apply .line.dummy by mistake, we break the TextEditor's ability to measure line height and get overlapping text --- styles/atom-text-editor.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styles/atom-text-editor.less b/styles/atom-text-editor.less index 8bd338ad98..a5c61779d4 100644 --- a/styles/atom-text-editor.less +++ b/styles/atom-text-editor.less @@ -5,6 +5,6 @@ } // Conceal the automatically added blank line element within TextEditors that we want to actually be empty -.github-AtomTextEditor-empty .line { +.github-AtomTextEditor-empty .cursor-line { display: none; } From 9d6034052d281d06f5d6dd734bedd72c97c76c3c Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Sat, 23 Feb 2019 01:12:01 +0800 Subject: [PATCH 2887/4847] better conditionals --- lib/views/multi-file-patch-view.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index e25097aa82..4e350ef7eb 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -1204,7 +1204,8 @@ export default class MultiFilePatchView extends React.Component { } measurePerformance(action) { - if (action === 'update' || action === 'mount') { + if ((action === 'update' || action === 'mount') + && performance.getEntriesByName(`MultiFilePatchView-${action}-start`).length > 0) { performance.mark(`MultiFilePatchView-${action}-end`); performance.measure( `MultiFilePatchView-${action}`, From 0da4f6020961d3a9ddc0f43737ce740531482a60 Mon Sep 17 00:00:00 2001 From: annthurium Date: Fri, 22 Feb 2019 11:45:09 -0800 Subject: [PATCH 2888/4847] bump version of Atom engine the newer version of atom contains an update to how markers are ordered. We need this marker ordering update in order for patches to be ordered consistently in the large diff gate pull request. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ac2a5101f8..fe9d2f7588 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "relay": "relay-compiler --src ./lib --schema graphql/schema.graphql" }, "engines": { - "atom": ">=1.32.0" + "atom": ">=1.37.0" }, "atomTestRunner": "./test/runner", "atomTranspilers": [ From 14bfc276fbe673d7560ebed450ed99b41fef05fe Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 22 Feb 2019 12:51:34 -0800 Subject: [PATCH 2889/4847] Revert 2dad315efc313518df98613f1103b087330c0aaf I think it is obsoleted by fbf56e62ef98176d993346fde6dbec3a8a7adf43 @smashwilson will verify by testing Co-Authored-By: Ash Wilson --- lib/views/multi-file-patch-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 4e350ef7eb..989ccf14e7 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -121,7 +121,6 @@ export default class MultiFilePatchView extends React.Component { }), this.props.onDidUpdatePatch(nextPatch => { this.refEditor.map(editor => { - this.suppressChanges = false; if (lastSelectionIndex !== null) { const nextSelectionRange = nextPatch.getSelectionRangeForIndex(lastSelectionIndex); if (this.props.selectionMode === 'line') { @@ -145,6 +144,7 @@ export default class MultiFilePatchView extends React.Component { if (lastScrollLeft !== null) { editor.getElement().setScrollLeft(lastScrollLeft); } return null; }); + this.suppressChanges = false; this.didChangeSelectedRows(); }), ); From 7e6609305cef3efc37319658846343521f27f91c Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 22 Feb 2019 13:25:02 -0800 Subject: [PATCH 2890/4847] Add test to verify that `selectedRowsChanged` gets called with the new editor selection index This is crucially importent when staging the last line in a non-last file patch because the selected row has changed. Whereas when staging a non-last line the selection index typically stays the same. --- test/views/multi-file-patch-view.test.js | 73 ++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/test/views/multi-file-patch-view.test.js b/test/views/multi-file-patch-view.test.js index c222a430c3..e96c3df4bc 100644 --- a/test/views/multi-file-patch-view.test.js +++ b/test/views/multi-file-patch-view.test.js @@ -344,6 +344,79 @@ describe('MultiFilePatchView', function() { ]); }); + describe('when the last line in a non-last file patch is staged', function() { + it('updates the selected row to be the first changed line in the next file patch', function() { + const selectedRowsChanged = sinon.spy(); + + let willUpdate, didUpdate; + const onWillUpdatePatch = cb => { + willUpdate = cb; + return {dispose: () => {}}; + }; + const onDidUpdatePatch = cb => { + didUpdate = cb; + return {dispose: () => {}}; + }; + + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('path.txt')); + fp.addHunk(h => { + h.oldRow(5); + h.unchanged('0000').added('0001').unchanged('0002').deleted('0003').unchanged('0004'); + }); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('another-path.txt')); + fp.addHunk(h => { + h.oldRow(5); + h.unchanged('0000').added('0001').unchanged('0002').deleted('0003').unchanged('0004'); + }); + }).build(); + + const wrapper = mount(buildApp({ + selectedRows: new Set([3]), + selectionMode: 'line', + selectedRowsChanged, + onWillUpdatePatch, + onDidUpdatePatch, + multiFilePatch, + })); + + assert.deepEqual([...wrapper.prop('selectedRows')], [3]); + + const {multiFilePatch: multiFilePatch2} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('path.txt')); + fp.addHunk(h => { + h.oldRow(5); + h.unchanged('0000').added('0001').unchanged('0002').unchanged('0003').unchanged('0004'); + }); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('another-path.txt')); + fp.addHunk(h => { + h.oldRow(5); + h.unchanged('0000').added('0001').unchanged('0002').deleted('0003').unchanged('0004'); + }); + }).build(); + + selectedRowsChanged.resetHistory(); + willUpdate(); + wrapper.setProps({multiFilePatch: multiFilePatch2}); + didUpdate(multiFilePatch2); + + assert.strictEqual(selectedRowsChanged.callCount, 1); + assert.sameMembers(Array.from(selectedRowsChanged.lastCall.args[0]), [6]); + assert.strictEqual(selectedRowsChanged.lastCall.args[1], 'line'); + + const editor = wrapper.find('AtomTextEditor').instance().getModel(); + assert.deepEqual(editor.getSelectedBufferRanges().map(r => r.serialize()), [ + [[6, 0], [6, 4]], + ]); + }); + }); + it('unregisters the mouseup handler on unmount', function() { sinon.spy(window, 'addEventListener'); sinon.spy(window, 'removeEventListener'); From 26e6cf3bcd2504b8d269eff5de92275568f39df9 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 25 Feb 2019 17:34:38 +0800 Subject: [PATCH 2891/4847] draft of mfp atlas --- docs/react-component-atlas.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/react-component-atlas.md b/docs/react-component-atlas.md index 596b3acbb4..3234d2a053 100644 --- a/docs/react-component-atlas.md +++ b/docs/react-component-atlas.md @@ -178,3 +178,29 @@ This is a high-level overview of the structure of the React component tree that > > > [``](/lib/views/changed-files-count-view.js) > > > > > > Displays the GitHub logo. Clicking it opens the GitHub tab. + + +## `MultiFilePatchView` Atlas + +> [``](/lib/views/multi-file-patch-view.js) +> > [``](lib/atom/atom-text-editor.js) +> > +> > React implementation of an [Atom TextEditor](https://atom.io/docs/api/latest/TextEditor). Each `MultiFilePatchView` contains one `AtomTextEditor`, regardless of the number of file patch. +> > +> > > [``](lib/atom/gutter.js) +> > > +> > > gutter explanation +> > +> > > [``](lib/atom/marker-layer.js) +> > > > +> > > > [``](lib/atom/marker.js) +> > > > +> > > > marker explanation +> > > > +> > > > > [``](lib/atom/decoration.js) +> > > > > +> > > > > decoration explanation +> > > > > +> > > > > > [``](lib/views/file-patch-header-view.js) +> > > > > +> > > > > > [``](lib/views/hunk-header-view.js) From ea0003be56f9f783fa2867b5c833a9be8bfa955e Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 25 Feb 2019 19:41:38 +0800 Subject: [PATCH 2892/4847] more descirption --- docs/react-component-atlas.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/react-component-atlas.md b/docs/react-component-atlas.md index 3234d2a053..ae52537a23 100644 --- a/docs/react-component-atlas.md +++ b/docs/react-component-atlas.md @@ -185,21 +185,23 @@ This is a high-level overview of the structure of the React component tree that > [``](/lib/views/multi-file-patch-view.js) > > [``](lib/atom/atom-text-editor.js) > > -> > React implementation of an [Atom TextEditor](https://atom.io/docs/api/latest/TextEditor). Each `MultiFilePatchView` contains one `AtomTextEditor`, regardless of the number of file patch. +> > React wrapper of an [Atom TextEditor](https://atom.io/docs/api/latest/TextEditor). Each `MultiFilePatchView` contains one `AtomTextEditor`, regardless of the number of file patch. > > > > > [``](lib/atom/gutter.js) > > > -> > > gutter explanation +> > > React wrapper of Atom's [Gutter](https://atom.io/docs/api/latest/Gutter) class. > > > > > [``](lib/atom/marker-layer.js) > > > > +> > > > React wrapper of Atom's [MarkerLayer](https://atom.io/docs/api/latest/MarkerLayer) class. +> > > > > > > > [``](lib/atom/marker.js) > > > > -> > > > marker explanation +> > > > React wrapper of Atom's [DisplayMarker](https://atom.io/docs/api/latest/DisplayMarker) class. > > > > > > > > > [``](lib/atom/decoration.js) > > > > > -> > > > > decoration explanation +> > > > > React wrapper of Atom's [Decoration](https://atom.io/docs/api/latest/Decoration) class. > > > > > > > > > > > [``](lib/views/file-patch-header-view.js) > > > > > From b2cf51e2e59cd3830815be8334361649f4785aa6 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 25 Feb 2019 19:41:50 +0800 Subject: [PATCH 2893/4847] headers description --- docs/react-component-atlas.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/react-component-atlas.md b/docs/react-component-atlas.md index ae52537a23..5b9fc13d01 100644 --- a/docs/react-component-atlas.md +++ b/docs/react-component-atlas.md @@ -204,5 +204,9 @@ This is a high-level overview of the structure of the React component tree that > > > > > React wrapper of Atom's [Decoration](https://atom.io/docs/api/latest/Decoration) class. > > > > > > > > > > > [``](lib/views/file-patch-header-view.js) +> > > > > > +> > > > > > Header above each file patch. Handles file patch level operations (e.g. discard change, stage/unstage, jump to file, expand/collapse file patch, etc.) > > > > > > > > > > > [``](lib/views/hunk-header-view.js) +> > > > > > +> > > > > > Header above each hunk. Handles more granular stage/unstage operation (per hunk or per line). From 0c3d099abbc29596bcdcd418c0aba82ca5dcaa15 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 25 Feb 2019 19:46:30 +0800 Subject: [PATCH 2894/4847] link to the new section --- docs/react-component-atlas.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/react-component-atlas.md b/docs/react-component-atlas.md index 5b9fc13d01..8ddd9fc97e 100644 --- a/docs/react-component-atlas.md +++ b/docs/react-component-atlas.md @@ -74,8 +74,8 @@ This is a high-level overview of the structure of the React component tree that > > > [``](/lib/controllers/multi-file-patch-controller.js) > > > [``](/lib/views/multi-file-patch-view.js) > > > -> > > Render a sequence of git-generated file patches within a TextEditor, using decorations to include contextually -> > > relevant controls. +> > > Render a sequence of git-generated file patches within a TextEditor, using decorations to include contextually relevant controls. +> > > See [`MultiFilePatchView` atlas](#multifilepatchview-atlas) below for a more detailed breakdown. > > > [``](/lig/items/commit-preview-item.js) > > [``](/lib/containers/commit-preview-container.js) @@ -180,6 +180,7 @@ This is a high-level overview of the structure of the React component tree that > > > Displays the GitHub logo. Clicking it opens the GitHub tab. + ## `MultiFilePatchView` Atlas > [``](/lib/views/multi-file-patch-view.js) From b5f3c256729f6d033f9f5633af9919047741d79d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Feb 2019 15:01:22 -0500 Subject: [PATCH 2895/4847] Upgrade Babel to Babel 6 Relay 3 needs Babel 7, so it's time for us to upgrade our transpilation pipeline. --- package.json | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index fae6334e0d..18d3a4eee7 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "atomTranspilers": [ { "glob": "{lib,test}/**/*.js", - "transpiler": "atom-babel6-transpiler", + "transpiler": "@atom/babel7-transpiler", "options": { "cacheKeyFiles": [ "package.json", @@ -39,14 +39,13 @@ } ], "dependencies": { - "atom-babel6-transpiler": "1.2.0", - "babel-generator": "6.26.1", + "@atom/babel7-transpiler": "1.0.0-1", + "@babel/generator": "7.3.4", + "@babel/plugin-proposal-class-properties": "7.3.4", + "@babel/preset-env": "7.3.4", + "@babel/preset-react": "7.0.0", "babel-plugin-chai-assert-async": "0.1.0", "babel-plugin-relay": "1.7.0", - "babel-plugin-transform-class-properties": "6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", - "babel-plugin-transform-object-rest-spread": "6.26.0", - "babel-preset-react": "6.24.1", "bintrees": "1.0.2", "bytes": "^3.0.0", "classnames": "2.2.6", From e2f8e077e07e569ae466bbfa0a79a65307d02d36 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Feb 2019 15:02:29 -0500 Subject: [PATCH 2896/4847] Use a .babelrc.js file instead of a .babelrc This lets us use `process.versions.electron` to magically transpile source appropriate to the actual Electron version we're running under. --- .babelrc | 20 -------------------- .babelrc.js | 20 ++++++++++++++++++++ package.json | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) delete mode 100644 .babelrc create mode 100644 .babelrc.js diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 4421da864b..0000000000 --- a/.babelrc +++ /dev/null @@ -1,20 +0,0 @@ -{ - "sourceMaps": "inline", - "babelrc": false, - "plugins": [ - "relay", - "./assert-messages-plugin.js", - "chai-assert-async", - "transform-object-rest-spread", - "transform-es2015-modules-commonjs", - "transform-class-properties", - ], - "presets": [ - "react", - ], - "env": { - "coverage": { - "plugins": ["istanbul"] - } - } -} diff --git a/.babelrc.js b/.babelrc.js new file mode 100644 index 0000000000..c3189debec --- /dev/null +++ b/.babelrc.js @@ -0,0 +1,20 @@ +module.exports = { + sourceMaps: "inline", + plugins: [ + "relay", + "./assert-messages-plugin.js", + "babel-plugin-chai-assert-async", + "@babel/plugin-proposal-class-properties", + ], + presets: [ + ["@babel/preset-env", { + "targets": {"electron": process.versions.electron} + }], + "@babel/preset-react" + ], + env: { + coverage: { + plugins: ["babel-plugin-istanbul"] + } + } +} diff --git a/package.json b/package.json index 18d3a4eee7..3a9b08d1c9 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "options": { "cacheKeyFiles": [ "package.json", - ".babelrc", + ".babelrc.js", "assert-messages-plugin.js", "graphql/schema.graphql", ".nycrc.json" From 262d33c3a30232ead302588123f4e12594889bba Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Feb 2019 15:02:51 -0500 Subject: [PATCH 2897/4847] Update Babel package imports to use "@babel/..." scope --- assert-messages-plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assert-messages-plugin.js b/assert-messages-plugin.js index bed581e1e6..6387d36ca6 100644 --- a/assert-messages-plugin.js +++ b/assert-messages-plugin.js @@ -1,4 +1,4 @@ -const generate = require('babel-generator').default; +const generate = require('@babel/generator').default; module.exports = function({types: t}) { return { From ac1d1b0e409e1e27f4e4373baade9ee9a4c6e17b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Feb 2019 15:03:15 -0500 Subject: [PATCH 2898/4847] Update Relay two major versions at once because fuck it, that's why --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3a9b08d1c9..1b09706fbe 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "@babel/preset-env": "7.3.4", "@babel/preset-react": "7.0.0", "babel-plugin-chai-assert-async": "0.1.0", - "babel-plugin-relay": "1.7.0", + "babel-plugin-relay": "3.0.0", "bintrees": "1.0.2", "bytes": "^3.0.0", "classnames": "2.2.6", @@ -53,7 +53,7 @@ "dugite": "^1.81.0", "event-kit": "2.5.3", "fs-extra": "4.0.3", - "graphql": "0.13.2", + "graphql": "14.1.1", "keytar": "4.4.0", "lodash.memoize": "4.1.2", "moment": "2.23.0", @@ -61,10 +61,10 @@ "prop-types": "15.7.2", "react": "16.8.2", "react-dom": "16.8.2", - "react-relay": "1.7.0", + "react-relay": "3.0.0", "react-select": "1.2.1", "react-tabs": "^3.0.0", - "relay-runtime": "1.7.0", + "relay-runtime": "3.0.0", "temp": "0.9.0", "tinycolor2": "1.4.1", "tree-kill": "1.2.1", @@ -100,7 +100,7 @@ "mocha-stress": "1.0.0", "node-fetch": "2.3.0", "nyc": "13.3.0", - "relay-compiler": "1.7.0", + "relay-compiler": "3.0.0", "semver": "5.6.0", "sinon": "7.2.4", "test-until": "1.1.1" From 2fb26cafe14807b4b813dfb45279843fed32ccb4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Feb 2019 15:03:29 -0500 Subject: [PATCH 2899/4847] :lock: Bring package-lock.json up to date --- package-lock.json | 3087 ++++++++++++++++++++++++--------------------- 1 file changed, 1644 insertions(+), 1443 deletions(-) diff --git a/package-lock.json b/package-lock.json index fe14a40a37..22b705408d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,47 +10,291 @@ "integrity": "sha1-nK+xca+CMpSQNTtIFvAzR6oVCjA=", "dev": true }, + "@atom/babel7-transpiler": { + "version": "1.0.0-1", + "resolved": "https://registry.npmjs.org/@atom/babel7-transpiler/-/babel7-transpiler-1.0.0-1.tgz", + "integrity": "sha512-9M11+CLgifczOlh/j7R9VyOx7YVMeAPexAnxQJAhjqeg4XYgmFoAdBGIyZNuDq5nK4XWi3E11mJgdkF+u6gy2w==", + "requires": { + "@babel/core": "7.x" + } + }, "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, "requires": { "@babel/highlight": "^7.0.0" } }, + "@babel/core": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.3.4.tgz", + "integrity": "sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helpers": "^7.2.0", + "@babel/parser": "^7.3.4", + "@babel/template": "^7.2.2", + "@babel/traverse": "^7.3.4", + "@babel/types": "^7.3.4", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/parser": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", + "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==" + }, + "@babel/traverse": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + } + }, + "@babel/types": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==" + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "@babel/generator": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.2.2.tgz", - "integrity": "sha512-I4o675J/iS8k+P38dvJ3IBGqObLXyQLTxtrR4u9cSUJOURvafeEWb/pFMOTwtNrmq73mJzyF6ueTbO1BtN0Zeg==", - "dev": true, + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", "requires": { - "@babel/types": "^7.2.2", + "@babel/types": "^7.3.4", "jsesc": "^2.5.1", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" }, "dependencies": { - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "@babel/types": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "requires": { + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-react-jsx": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz", + "integrity": "sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw==", + "requires": { + "@babel/types": "^7.3.0", + "esutils": "^2.0.0" + }, + "dependencies": { + "@babel/types": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.3.tgz", + "integrity": "sha512-2tACZ80Wg09UnPg5uGAOUvvInaqLk3l/IAhQzlxLQOIXacr6bMsra5SH6AWw/hIDRCSbCdHP2KzSOD+cT7TzMQ==", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + } + } + }, + "@babel/helper-call-delegate": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz", + "integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==", + "requires": { + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.4.tgz", + "integrity": "sha512-uFpzw6L2omjibjxa8VGZsJUPL5wJH0zzGKpoz0ccBkzIa6C8kWNUbiBmQ0rgOKWlHJ6qzmfa6lTiGchiV8SC+g==", + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.3.4", + "@babel/helper-split-export-declaration": "^7.0.0" + }, + "dependencies": { + "@babel/helper-replace-supers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz", + "integrity": "sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A==", + "requires": { + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.3.4", + "@babel/types": "^7.3.4" + } + }, + "@babel/parser": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", + "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==" + }, + "@babel/traverse": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + } + }, + "@babel/types": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==" + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "@babel/helper-define-map": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz", + "integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==", + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" + }, + "dependencies": { + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" } } }, + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, "@babel/helper-function-name": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.0.0", "@babel/template": "^7.1.0", @@ -61,25 +305,164 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, "requires": { "@babel/types": "^7.0.0" } }, + "@babel/helper-hoist-variables": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz", + "integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", + "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz", + "integrity": "sha512-YRD7I6Wsv+IHuTPkAmAS4HhY0dkPobgLftHp0cRGZSdrRvmZY8rFvae/GVu3bD00qscuvK3WPHB3YdNpBXUqrA==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/template": "^7.2.2", + "@babel/types": "^7.2.2", + "lodash": "^4.17.10" + }, + "dependencies": { + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + } + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==" + }, + "@babel/helper-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz", + "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", + "requires": { + "lodash": "^4.17.10" + }, + "dependencies": { + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + } + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz", + "integrity": "sha512-GyieIznGUfPXPWu0yLS6U55Mz67AZD9cUk0BfirOWlPrXlBcan9Gz+vHGz+cPfuoweZSnPzPIm67VtQM0OWZbA==", + "requires": { + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.2.3", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, "@babel/helper-split-export-declaration": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", - "dev": true, "requires": { "@babel/types": "^7.0.0" } }, + "@babel/helper-wrap-function": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", + "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.2.0" + } + }, + "@babel/helpers": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.3.1.tgz", + "integrity": "sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA==", + "requires": { + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.5", + "@babel/types": "^7.3.0" + }, + "dependencies": { + "@babel/types": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + } + } + }, "@babel/highlight": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", - "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", @@ -90,7 +473,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -99,7 +481,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -109,14 +490,12 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -126,158 +505,157 @@ "@babel/parser": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.2.3.tgz", - "integrity": "sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA==", - "dev": true + "integrity": "sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA==" }, - "@babel/template": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", - "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", - "dev": true, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", + "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.2.2", - "@babel/types": "^7.2.2" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.2.0" } }, - "@babel/traverse": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", - "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", + "@babel/plugin-proposal-class-properties": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.4.tgz", + "integrity": "sha512-lUf8D3HLs4yYlAo8zjuneLvfxN7qfKv1Yzbj5vjqaqMJxgJA3Ipwp4VUJ+OrOdz53Wbww6ahwB8UhB2HQyLotA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.3.4", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", + "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.2.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz", + "integrity": "sha512-DjeMS+J2+lpANkYLLO+m6GjoTMygYglKmRe6cDTbFv3L9i6mmiE8fe6B8MtCSLZpVXscD5kn7s6SgtHrDoBWoA==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.2", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.2.3", - "@babel/types": "^7.2.2", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.10" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "globals": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", - "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==", - "dev": true - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" } }, - "@babel/types": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.2.2.tgz", - "integrity": "sha512-fKCuD6UFUMkR541eDWL+2ih/xFZBXPOg/7EQFeTluMDebfqR4jrpaCjLhkWlQS4hT6nRa2PMEgXKbRB5/H2fpg==", + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.2.0.tgz", + "integrity": "sha512-LvRVYb7kikuOtIoUeWTkOxQEV1kYvL5B6U3iWEGCzPNRus1MzJweFqORTj+0jkxozkTSYNJozPOddxmqdqsRpw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.2.0" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", + "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.2.0.tgz", + "integrity": "sha512-UxYaGXYQ7rrKJS/PxIKRkv3exi05oH7rokBAsmCSsCxz1sVPZ7Fu6FzKoGgUvmY+0YgSkYHgUoCh5R5bCNBQlw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.10", - "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.0.0" } }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "@babel/plugin-syntax-flow": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz", + "integrity": "sha512-r6YMuZDWLtLlu0kqIim5o/3TNRAlWb073HwT3e2nKf9I8IIvOggPrnILYPsrrKilmn/mYEMCf/Z07w3yQJF6dg==", "dev": true, "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, - "@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", - "dev": true + "@babel/plugin-syntax-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", + "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } }, - "@shiftkey/prebuild-install": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/@shiftkey/prebuild-install/-/prebuild-install-5.2.4.tgz", - "integrity": "sha512-42L/pSGD/+diCg8SwhZaXjDlkAWV10u42UozyG7rqDdyPW7HDp2/j/RYRZ3x0sXFf7hAUtLYvI9HdACWdjyfVw==", + "@babel/plugin-syntax-jsx": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz", + "integrity": "sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==", "requires": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.2.0", - "noop-logger": "^0.1.1", - "npmlog": "^4.0.1", - "os-homedir": "^1.0.1", - "pump": "^2.0.1", - "rc": "^1.2.7", - "simple-get": "^2.7.0", - "tar-fs": "^1.13.0", - "tunnel-agent": "^0.6.0", - "which-pm-runs": "^1.0.0" - }, - "dependencies": { - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" - } + "@babel/helper-plugin-utils": "^7.0.0" } }, - "@sinonjs/commons": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.3.0.tgz", - "integrity": "sha512-j4ZwhaHmwsCb4DlDOIWnI5YyKDNMoNThsmwEpfHx6a1EpsGZ9qYLxP++LMlmBRjtGptGHFsGItJ768snllFWpA==", - "dev": true, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", "requires": { - "type-detect": "4.0.8" + "@babel/helper-plugin-utils": "^7.0.0" } }, - "@sinonjs/formatio": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.1.0.tgz", - "integrity": "sha512-ZAR2bPHOl4Xg6eklUGpsdiIJ4+J1SNag1DHHrG/73Uz/nVwXqjgUtRPLoS+aVyieN9cSbc0E4LsU984tWcDyNg==", - "dev": true, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", "requires": { - "@sinonjs/samsam": "^2 || ^3" + "@babel/helper-plugin-utils": "^7.0.0" } }, - "@sinonjs/samsam": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.1.1.tgz", - "integrity": "sha512-ILlwvQUwAiaVBzr3qz8oT1moM7AIUHqUc2UmEjQcH9lLe+E+BZPwUMuc9FFojMswRK4r96x5zDTTrowMLw/vuA==", + "@babel/plugin-transform-arrow-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", + "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.3.4.tgz", + "integrity": "sha512-Y7nCzv2fw/jEZ9f678MuKdMo99MFDJMT/PvD9LisrR5JDFcJH6vYeH6RnjVt3p5tceyGRvTtEN0VOlU+rgHZjA==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", + "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.2.0.tgz", + "integrity": "sha512-vDTgf19ZEV6mx35yiPJe4fS02mPQUUcBNwWQSZFXSzTSbsJFQvHt7DqyS3LK8oOWALFOsJ+8bbqBgkirZteD5Q==", "dev": true, "requires": { - "@sinonjs/commons": "^1.0.2", - "array-from": "^2.1.1", - "lodash": "^4.17.11" + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.10" }, "dependencies": { "lodash": { @@ -288,1306 +666,1109 @@ } } }, - "@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", - "dev": true - }, - "@smashwilson/atom-mocha-test-runner": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@smashwilson/atom-mocha-test-runner/-/atom-mocha-test-runner-1.4.0.tgz", - "integrity": "sha512-Zp50XTy2QZEk53PUxXQ1kLTAkSwEuM2X7JXtMGLRWuU68piFghkXGaopTrjXK3CwgzmmFi26m65sTCrXg3zqbg==", + "@babel/plugin-transform-classes": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.3.tgz", + "integrity": "sha512-n0CLbsg7KOXsMF4tSTLCApNMoXk0wOPb0DYfsOO1e7SfIb9gOyfbpKI2MZ+AXfqvlfzq2qsflJ1nEns48Caf2w==", "dev": true, "requires": { - "diff": "3.5.0", - "etch": "^0.8.0", - "grim": "^2.0.1", - "less": "^3.7.1", - "mocha": "^5.2.0", - "tmp": "0.0.31" + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.1.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "dev": true + } } }, - "@types/node": { - "version": "10.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.12.tgz", - "integrity": "sha512-Pr+6JRiKkfsFvmU/LK68oBRCQeEg36TyAbPhc2xpez24OOZZCuoIhWGTd39VZy6nGafSbxzGouFPTFD/rR1A0A==", - "dev": true + "@babel/plugin-transform-computed-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", + "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } }, - "abstract-leveldown": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-5.0.0.tgz", - "integrity": "sha512-5mU5P1gXtsMIXg65/rsYGsi93+MlogXZ9FA8JnwKurHQg64bfXwGYVdVdijNTVNOlAsuIiOwHdvFFD5JqCJQ7A==", - "dev": true, + "@babel/plugin-transform-destructuring": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.3.2.tgz", + "integrity": "sha512-Lrj/u53Ufqxl/sGxyjsJ2XNtNuEjDyjpqdhMNh5aZ+XFOdThL46KBj27Uem4ggoezSYBxKWAil6Hu8HtwqesYw==", "requires": { - "xtend": "~4.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, - "acorn": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.0.tgz", - "integrity": "sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw==", - "dev": true + "@babel/plugin-transform-dotall-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.2.0.tgz", + "integrity": "sha512-sKxnyHfizweTgKZf7XsXu/CNupKhzijptfTM+bozonIuyVrLWVUvYjE2bhuSBML8VQeMxq4Mm63Q9qvcvUcciQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" + } }, - "acorn-jsx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", - "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", - "dev": true + "@babel/plugin-transform-duplicate-keys": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz", + "integrity": "sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } }, - "agent-base": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", - "dev": true, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", + "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", "requires": { - "es6-promisify": "^5.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "@babel/plugin-transform-flow-strip-types": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.2.3.tgz", + "integrity": "sha512-xnt7UIk9GYZRitqCnsVMjQK1O2eKZwFB3CvvHjf5SGx6K6vr/MScCKQDnf1DxRaj501e3pXjti+inbSXX2ZUoQ==", "dev": true, "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.2.0" } }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true + "@babel/plugin-transform-for-of": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.2.0.tgz", + "integrity": "sha512-Kz7Mt0SsV2tQk6jG5bBv5phVbkd0gd27SgYD4hH1aLMJRchM0dzHaXvrWhVZ+WxAlDoAKZ7Uy3jVTW2mKXQ1WQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "@babel/plugin-transform-function-name": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.2.0.tgz", + "integrity": "sha512-kWgksow9lHdvBC2Z4mxTsvc7YdY7w/V6B2vy9cTIPtLEE9NhwoWivaxdNM/S37elu5bqlLP/qOY906LukO9lkQ==", + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + "@babel/plugin-transform-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", + "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=" + "@babel/plugin-transform-member-expression-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", + "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "@babel/plugin-transform-modules-amd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz", + "integrity": "sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==", "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "@babel/plugin-transform-modules-commonjs": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.2.0.tgz", + "integrity": "sha512-V6y0uaUQrQPXUrmj+hgnks8va2L0zcZymeU7TtWEgdRLNkceafKXEduv7QzgQAE4lT+suwooG9dC7LFhdRAbVQ==", "requires": { - "sprintf-js": "~1.0.2" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" } }, - "argv": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz", - "integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=", - "dev": true + "@babel/plugin-transform-modules-systemjs": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.3.4.tgz", + "integrity": "sha512-VZ4+jlGOF36S7TjKs8g4ojp4MEI+ebCQZdswWb/T9I4X84j8OtFAyjXjt/M16iIm5RIZn0UMQgg/VgIwo/87vw==", + "requires": { + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } }, - "aria-query": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", - "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", - "dev": true, + "@babel/plugin-transform-modules-umd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", + "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", "requires": { - "ast-types-flow": "0.0.7", - "commander": "^2.11.0" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.3.0.tgz", + "integrity": "sha512-NxIoNVhk9ZxS+9lSoAQ/LM0V2UEvARLttEHUrRDGKFaAxOYQcrkN/nLRE+BbbicCAvZPl7wMP0X60HsHE5DtQw==", + "requires": { + "regexp-tree": "^0.1.0" + } }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true - }, - "array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", - "dev": true - }, - "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", - "dev": true, + "@babel/plugin-transform-new-target": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz", + "integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==", "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, + "@babel/plugin-transform-object-super": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz", + "integrity": "sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==", "requires": { - "array-uniq": "^1.0.1" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0" } }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "array.prototype.find": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.0.4.tgz", - "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", - "dev": true, + "@babel/plugin-transform-parameters": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.3.3.tgz", + "integrity": "sha512-IrIP25VvXWu/VlBWTpsjGptpomtIkYrN/3aDp4UKm7xK6UxZY88kcJ1UwETbzHAlwN21MnNfwlar0u8y3KpiXw==", "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" + "@babel/helper-call-delegate": "^7.1.0", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, - "array.prototype.flat": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz", - "integrity": "sha512-rVqIs330nLJvfC7JqYvEWwqVr5QjYF1ib02i3YJtR/fICO6527Tjpc/e4Mvmxh3GIePPreRXMdaGyC99YphWEw==", + "@babel/plugin-transform-property-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", + "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.10.0", - "function-bind": "^1.1.1" + "@babel/helper-plugin-utils": "^7.0.0" } }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "ast-types": { - "version": "0.6.16", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.6.16.tgz", - "integrity": "sha1-BCBbcu3dGVqP6qCB8R0ClKJN7ZM=", - "dev": true + "@babel/plugin-transform-react-display-name": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz", + "integrity": "sha512-Htf/tPa5haZvRMiNSQSFifK12gtr/8vwfr+A9y69uF0QcU77AVu4K7MiHEkTxF7lQoHOL0F9ErqgfNEAKgXj7A==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } }, - "ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", - "dev": true + "@babel/plugin-transform-react-jsx": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz", + "integrity": "sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg==", + "requires": { + "@babel/helper-builder-react-jsx": "^7.3.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0" + } }, - "ast-util": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/ast-util/-/ast-util-0.6.0.tgz", - "integrity": "sha1-DZE9BPDpgx5T+ZkdyZAJ4tp3SBA=", - "dev": true, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.2.0.tgz", + "integrity": "sha512-v6S5L/myicZEy+jr6ielB0OR8h+EH/1QFx/YJ7c7Ua+7lqsjj/vW6fD5FR9hB/6y7mGbfT4vAURn3xqBxsUcdg==", "requires": { - "ast-types": "~0.6.7", - "private": "~0.1.6" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0" } }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true + "@babel/plugin-transform-react-jsx-source": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.2.0.tgz", + "integrity": "sha512-A32OkKTp4i5U6aE88GwwcuV4HAprUgHcTq0sSafLxjr6AW0QahrCRCjxogkbbcdtpbXkuTOlgpjophCxb6sh5g==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0" + } }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "@babel/plugin-transform-regenerator": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.3.4.tgz", + "integrity": "sha512-hvJg8EReQvXT6G9H2MvNPXkv9zK36Vxa1+csAVTpE1J3j0zlHplw76uudEbJxgvqZzAq9Yh45FLD4pk5mKRFQA==", + "requires": { + "regenerator-transform": "^0.13.4" + } }, - "atob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", - "dev": true + "@babel/plugin-transform-shorthand-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", + "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } }, - "atom-babel6-transpiler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/atom-babel6-transpiler/-/atom-babel6-transpiler-1.2.0.tgz", - "integrity": "sha512-lZucrjVyRtPAPPJxvICCEBsAC1qn48wUHaIlieriWCXTXLqtLC2PvkQU7vNvU2w1eZ7tw9m0lojZ8PbpVyWTvg==", + "@babel/plugin-transform-spread": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", + "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", "requires": { - "babel-core": "6.x" + "@babel/helper-plugin-utils": "^7.0.0" } }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "@babel/plugin-transform-sticky-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", + "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } }, - "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha1-1NDpudv8p3vwjusKikcVUP454ok=", - "dev": true + "@babel/plugin-transform-template-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.2.0.tgz", + "integrity": "sha512-FkPix00J9A/XWXv4VoKJBMeSkyY9x/TqIh76wzcdfl57RJJcf8CehQ08uwfhCDNtRQYtHQKBTwKZDEyjE13Lwg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } }, - "axobject-query": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", - "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", - "dev": true, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", + "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", "requires": { - "ast-types-flow": "0.0.7" + "@babel/helper-plugin-utils": "^7.0.0" } }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "@babel/plugin-transform-unicode-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.2.0.tgz", + "integrity": "sha512-m48Y0lMhrbXEJnVUaYly29jRXbQ3ksxPrS1Tg8t+MHqzXhtBYAvI51euOBaoAlZLPHsieY9XPVMf80a5x0cPcA==", "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" } }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha1-suLwnjQtDwyI4vAuBneUEl51wgc=", + "@babel/polyfill": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.2.5.tgz", + "integrity": "sha512-8Y/t3MWThtMLYr0YNC/Q76tqN1w30+b0uQMeFUYauG2UGTR19zyUtFrAzT23zNtBxPp+LbE5E/nwV/q/r3y6ug==", + "dev": true, "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" + "core-js": "^2.5.7", + "regenerator-runtime": "^0.12.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", + "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", + "dev": true + } + } + }, + "@babel/preset-env": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.3.4.tgz", + "integrity": "sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.3.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.2.0", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.3.4", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.3.4", + "@babel/plugin-transform-classes": "^7.3.4", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.2.0", + "@babel/plugin-transform-dotall-regex": "^7.2.0", + "@babel/plugin-transform-duplicate-keys": "^7.2.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.2.0", + "@babel/plugin-transform-function-name": "^7.2.0", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.2.0", + "@babel/plugin-transform-modules-systemjs": "^7.3.4", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.3.0", + "@babel/plugin-transform-new-target": "^7.0.0", + "@babel/plugin-transform-object-super": "^7.2.0", + "@babel/plugin-transform-parameters": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.3.4", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.2.0", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.2.0", + "browserslist": "^4.3.4", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.3.0" }, "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "@babel/helper-replace-supers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz", + "integrity": "sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A==", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.3.4", + "@babel/types": "^7.3.4" } }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "@babel/parser": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", + "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==" + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.4.tgz", + "integrity": "sha512-j7VQmbbkA+qrzNqbKHrBsW3ddFnOeva6wzSe/zB7T+xaxGc+RCpwo44wCmRixAIGRoIpmVgvzFzNJqQcO3/9RA==", "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" } }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "@babel/plugin-transform-block-scoping": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.3.4.tgz", + "integrity": "sha512-blRr2O8IOZLAOJklXLV4WhcEzpYafYQKSGT3+R26lWG41u/FODJuBggehtOwilVAcFu393v3OFj+HmaE6tVjhA==", "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.11" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.4.tgz", + "integrity": "sha512-J9fAvCFBkXEvBimgYxCjvaVDzL6thk0j0dBvCeZmIUDBwyt+nv6HfbImsSrWsYXfDNDivyANgJlFXDUWRTZBuA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.1.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.3.4", + "@babel/helper-split-export-declaration": "^7.0.0", + "globals": "^11.1.0" + } + }, + "@babel/traverse": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" } }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "@babel/types": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "requires": { - "babel-runtime": "^6.26.0", "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" } }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==" }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" } } }, - "babel-eslint": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-7.2.3.tgz", - "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=", - "dev": true, + "@babel/preset-react": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", + "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", "requires": { - "babel-code-frame": "^6.22.0", - "babel-traverse": "^6.23.1", - "babel-types": "^6.23.0", - "babylon": "^6.17.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0" } }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha1-GERAjTuPDTWkBOp6wYDwh6YBvZA=", + "@babel/runtime": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz", + "integrity": "sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==", "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" + "regenerator-runtime": "^0.12.0" }, "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" } } }, - "babel-helper-builder-react-jsx": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", - "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", + "@babel/template": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", + "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "esutils": "^2.0.2" - }, - "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - } + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.2.2", + "@babel/types": "^7.2.2" } }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", - "dev": true, - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "dev": true, + "@babel/traverse": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", + "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.2.2", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.2.3", + "@babel/types": "^7.2.2", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.10" }, "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "ms": "^2.1.1" } }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } + "globals": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", + "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==" }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" } } }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "dev": true, + "@babel/types": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.2.2.tgz", + "integrity": "sha512-fKCuD6UFUMkR541eDWL+2ih/xFZBXPOg/7EQFeTluMDebfqR4jrpaCjLhkWlQS4hT6nRa2PMEgXKbRB5/H2fpg==", "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "esutils": "^2.0.2", + "lodash": "^4.17.10", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + } } }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" } }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", - "dev": true, - "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "@shiftkey/prebuild-install": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@shiftkey/prebuild-install/-/prebuild-install-5.2.4.tgz", + "integrity": "sha512-42L/pSGD/+diCg8SwhZaXjDlkAWV10u42UozyG7rqDdyPW7HDp2/j/RYRZ3x0sXFf7hAUtLYvI9HdACWdjyfVw==", "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.2.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "os-homedir": "^1.0.1", + "pump": "^2.0.1", + "rc": "^1.2.7", + "simple-get": "^2.7.0", + "tar-fs": "^1.13.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + }, + "dependencies": { + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + } } }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "@sinonjs/commons": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.3.0.tgz", + "integrity": "sha512-j4ZwhaHmwsCb4DlDOIWnI5YyKDNMoNThsmwEpfHx6a1EpsGZ9qYLxP++LMlmBRjtGptGHFsGItJ768snllFWpA==", + "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "type-detect": "4.0.8" } }, - "babel-plugin-chai-assert-async": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-chai-assert-async/-/babel-plugin-chai-assert-async-0.1.0.tgz", - "integrity": "sha1-pJMXc79WPcKt3mzXm28ZRknr/SU=" - }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "@sinonjs/formatio": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.1.0.tgz", + "integrity": "sha512-ZAR2bPHOl4Xg6eklUGpsdiIJ4+J1SNag1DHHrG/73Uz/nVwXqjgUtRPLoS+aVyieN9cSbc0E4LsU984tWcDyNg==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "@sinonjs/samsam": "^2 || ^3" } }, - "babel-plugin-istanbul": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz", - "integrity": "sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ==", + "@sinonjs/samsam": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.1.1.tgz", + "integrity": "sha512-ILlwvQUwAiaVBzr3qz8oT1moM7AIUHqUc2UmEjQcH9lLe+E+BZPwUMuc9FFojMswRK4r96x5zDTTrowMLw/vuA==", "dev": true, "requires": { - "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.0.0", - "test-exclude": "^5.0.0" + "@sinonjs/commons": "^1.0.2", + "array-from": "^2.1.1", + "lodash": "^4.17.11" }, "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", - "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true } } }, - "babel-plugin-macros": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.4.5.tgz", - "integrity": "sha512-+/9yteNQw3yuZ3krQUfjAeoT/f4EAdn3ELwhFfDj0rTMIaoHfIdrcLePOfIaL0qmFLpIcgPIL2Lzm58h+CGWaw==", - "requires": { - "cosmiconfig": "^5.0.5", - "resolve": "^1.8.1" - } + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true }, - "babel-plugin-relay": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/babel-plugin-relay/-/babel-plugin-relay-1.7.0.tgz", - "integrity": "sha512-4kDgElsQ3+m1YHGinm2CWu55XzpPqEzf42JuYWUAJWvTBcHkd/VGVftO9C6BjnssUU7fDH9izn3qMtp0XFWGKw==", + "@smashwilson/atom-mocha-test-runner": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@smashwilson/atom-mocha-test-runner/-/atom-mocha-test-runner-1.4.0.tgz", + "integrity": "sha512-Zp50XTy2QZEk53PUxXQ1kLTAkSwEuM2X7JXtMGLRWuU68piFghkXGaopTrjXK3CwgzmmFi26m65sTCrXg3zqbg==", + "dev": true, "requires": { - "babel-plugin-macros": "^2.0.0", - "babel-runtime": "^6.23.0", - "babel-types": "^6.24.1" + "diff": "3.5.0", + "etch": "^0.8.0", + "grim": "^2.0.1", + "less": "^3.7.1", + "mocha": "^5.2.0", + "tmp": "0.0.31" } }, - "babel-plugin-syntax-class-properties": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", - "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=" - }, - "babel-plugin-syntax-flow": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", - "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=" - }, - "babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" - }, - "babel-plugin-syntax-object-rest-spread": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", - "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" - }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "@types/node": { + "version": "10.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.12.tgz", + "integrity": "sha512-Pr+6JRiKkfsFvmU/LK68oBRCQeEg36TyAbPhc2xpez24OOZZCuoIhWGTd39VZy6nGafSbxzGouFPTFD/rR1A0A==", "dev": true }, - "babel-plugin-transform-class-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", - "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-plugin-syntax-class-properties": "^6.8.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "abstract-leveldown": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-5.0.0.tgz", + "integrity": "sha512-5mU5P1gXtsMIXg65/rsYGsi93+MlogXZ9FA8JnwKurHQg64bfXwGYVdVdijNTVNOlAsuIiOwHdvFFD5JqCJQ7A==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "xtend": "~4.0.0" } }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "acorn": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.0.tgz", + "integrity": "sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true + }, + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "es6-promisify": "^5.0.0" } }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - }, - "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - } + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "dev": true, - "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=" }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "dev": true, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", - "dev": true, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "requires": { - "babel-runtime": "^6.22.0" + "sprintf-js": "~1.0.2" } }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", - "integrity": "sha1-WKeThjqefKhwvcWogRF/+sJ9tvM=", - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - }, - "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - } - } + "argv": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz", + "integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=", + "dev": true }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", "dev": true, "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" } }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "dev": true, - "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" } }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "array-uniq": "^1.0.1" } }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "array.prototype.find": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.0.4.tgz", + "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" } }, - "babel-plugin-transform-es3-member-expression-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es3-member-expression-literals/-/babel-plugin-transform-es3-member-expression-literals-6.22.0.tgz", - "integrity": "sha1-cz00RPPsxBvvjtGmpOCWV7iWnrs=", + "array.prototype.flat": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz", + "integrity": "sha512-rVqIs330nLJvfC7JqYvEWwqVr5QjYF1ib02i3YJtR/fICO6527Tjpc/e4Mvmxh3GIePPreRXMdaGyC99YphWEw==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "define-properties": "^1.1.2", + "es-abstract": "^1.10.0", + "function-bind": "^1.1.1" } }, - "babel-plugin-transform-es3-property-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es3-property-literals/-/babel-plugin-transform-es3-property-literals-6.22.0.tgz", - "integrity": "sha1-sgeNWELiKr9A9z6M3pzTcRq9V1g=", + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "ast-types": { + "version": "0.6.16", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.6.16.tgz", + "integrity": "sha1-BCBbcu3dGVqP6qCB8R0ClKJN7ZM=", + "dev": true + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, + "ast-util": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/ast-util/-/ast-util-0.6.0.tgz", + "integrity": "sha1-DZE9BPDpgx5T+ZkdyZAJ4tp3SBA=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "ast-types": "~0.6.7", + "private": "~0.1.6" } }, - "babel-plugin-transform-flow-strip-types": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", - "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", - "requires": { - "babel-plugin-syntax-flow": "^6.18.0", - "babel-runtime": "^6.22.0" - } + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true }, - "babel-plugin-transform-object-rest-spread": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", - "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", - "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" - }, - "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - } - } + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "babel-plugin-transform-react-display-name": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", - "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=", + "atob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", + "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", + "integrity": "sha1-1NDpudv8p3vwjusKikcVUP454ok=", + "dev": true + }, + "axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "ast-types-flow": "0.0.7" } }, - "babel-plugin-transform-react-jsx": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", - "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, "requires": { - "babel-helper-builder-react-jsx": "^6.24.1", - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" } }, - "babel-plugin-transform-react-jsx-self": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz", - "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=", + "babel-eslint": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-7.2.3.tgz", + "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=", + "dev": true, "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" + "babel-code-frame": "^6.22.0", + "babel-traverse": "^6.23.1", + "babel-types": "^6.23.0", + "babylon": "^6.17.0" } }, - "babel-plugin-transform-react-jsx-source": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz", - "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=", + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", "babel-runtime": "^6.22.0" } }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "babel-plugin-chai-assert-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-chai-assert-async/-/babel-plugin-chai-assert-async-0.1.0.tgz", + "integrity": "sha1-pJMXc79WPcKt3mzXm28ZRknr/SU=" }, - "babel-polyfill": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", - "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "babel-plugin-istanbul": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz", + "integrity": "sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ==", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "regenerator-runtime": "^0.10.5" + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.0.0", + "test-exclude": "^5.0.0" }, "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - } + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true } } }, - "babel-preset-fbjs": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-2.2.0.tgz", - "integrity": "sha512-jj0KFJDioYZMtPtZf77dQuU+Ad/1BtN0UnAYlHDa8J8f4tGXr3YrPoJImD5MdueaOPeN/jUdrCgu330EfXr0XQ==", - "dev": true, - "requires": { - "babel-plugin-check-es2015-constants": "^6.8.0", - "babel-plugin-syntax-class-properties": "^6.8.0", - "babel-plugin-syntax-flow": "^6.8.0", - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-plugin-syntax-trailing-function-commas": "^6.8.0", - "babel-plugin-transform-class-properties": "^6.8.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.8.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.8.0", - "babel-plugin-transform-es2015-block-scoping": "^6.8.0", - "babel-plugin-transform-es2015-classes": "^6.8.0", - "babel-plugin-transform-es2015-computed-properties": "^6.8.0", - "babel-plugin-transform-es2015-destructuring": "^6.8.0", - "babel-plugin-transform-es2015-for-of": "^6.8.0", - "babel-plugin-transform-es2015-function-name": "^6.8.0", - "babel-plugin-transform-es2015-literals": "^6.8.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.8.0", - "babel-plugin-transform-es2015-object-super": "^6.8.0", - "babel-plugin-transform-es2015-parameters": "^6.8.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.8.0", - "babel-plugin-transform-es2015-spread": "^6.8.0", - "babel-plugin-transform-es2015-template-literals": "^6.8.0", - "babel-plugin-transform-es3-member-expression-literals": "^6.8.0", - "babel-plugin-transform-es3-property-literals": "^6.8.0", - "babel-plugin-transform-flow-strip-types": "^6.8.0", - "babel-plugin-transform-object-rest-spread": "^6.8.0", - "babel-plugin-transform-react-display-name": "^6.8.0", - "babel-plugin-transform-react-jsx": "^6.8.0" - } - }, - "babel-preset-flow": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", - "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=", + "babel-plugin-macros": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.5.0.tgz", + "integrity": "sha512-BWw0lD0kVZAXRD3Od1kMrdmfudqzDzYv2qrN3l2ISR1HVp1EgLKfbOrYV9xmY5k3qx3RIu5uPAUZZZHpo0o5Iw==", "requires": { - "babel-plugin-transform-flow-strip-types": "^6.22.0" + "cosmiconfig": "^5.0.5", + "resolve": "^1.8.1" } }, - "babel-preset-react": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", - "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", + "babel-plugin-relay": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-relay/-/babel-plugin-relay-3.0.0.tgz", + "integrity": "sha512-lI+PR4/H8XytNVUtz8cYYM7sR2unFMeTsBbnKFvuU/mnxxmDO3JA7OHxtTdctLjlRSYrcCVmvIEL2JDehMxlTg==", "requires": { - "babel-plugin-syntax-jsx": "^6.3.13", - "babel-plugin-transform-react-display-name": "^6.23.0", - "babel-plugin-transform-react-jsx": "^6.24.1", - "babel-plugin-transform-react-jsx-self": "^6.22.0", - "babel-plugin-transform-react-jsx-source": "^6.22.0", - "babel-preset-flow": "^6.23.0" + "babel-plugin-macros": "^2.0.0" } }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - }, - "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - } + "babel-plugin-syntax-trailing-function-commas": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz", + "integrity": "sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==", + "dev": true + }, + "babel-preset-fbjs": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.2.0.tgz", + "integrity": "sha512-5Jo+JeWiVz2wHUUyAlvb/sSYnXNig9r+HqGAOSfh5Fzxp7SnAaR/tEGRJ1ZX7C77kfk82658w6R5Z+uPATTD9g==", + "dev": true, + "requires": { + "@babel/plugin-proposal-class-properties": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-syntax-class-properties": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-block-scoped-functions": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-flow-strip-types": "^7.0.0", + "@babel/plugin-transform-for-of": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-member-expression-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-object-super": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-property-literals": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-template-literals": "^7.0.0", + "babel-plugin-syntax-trailing-function-commas": "^7.0.0-beta.0" } }, "babel-runtime": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.25.0.tgz", "integrity": "sha1-M7mOql1IK7AajRqmtDetKwGuxBw=", + "dev": true, "requires": { "core-js": "^2.4.0", "regenerator-runtime": "^0.10.0" } }, - "babel-template": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", - "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.25.0", - "babel-types": "^6.25.0", - "babylon": "^6.17.2", - "lodash": "^4.2.0" - } - }, "babel-traverse": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", + "dev": true, "requires": { "babel-code-frame": "^6.22.0", "babel-messages": "^6.23.0", @@ -1604,6 +1785,7 @@ "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", + "dev": true, "requires": { "babel-runtime": "^6.22.0", "esutils": "^2.0.2", @@ -1614,14 +1796,16 @@ "to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true } } }, "babylon": { "version": "6.17.4", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz", - "integrity": "sha512-kChlV+0SXkjE0vUn9OZ7pBMWRFd8uq3mZe8x1K6jhuNcAFAtEnjchFAqB+dYEXKyd+JpT6eppRR78QAr5gTsUw==" + "integrity": "sha512-kChlV+0SXkjE0vUn9OZ7pBMWRFd8uq3mZe8x1K6jhuNcAFAtEnjchFAqB+dYEXKyd+JpT6eppRR78QAr5gTsUw==", + "dev": true }, "balanced-match": { "version": "1.0.0", @@ -1797,6 +1981,16 @@ "integrity": "sha1-uqVZ7hTO1zRSIputcyZGfGH6vWA=", "dev": true }, + "browserslist": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.4.2.tgz", + "integrity": "sha512-ISS/AIAiHERJ3d45Fz0AVYKkgcy+F/eJHzKEvv1j0wwKGKD9T3BrwKr/5g45L+Y4XIK5PlTqefHciRFcfE1Jxg==", + "requires": { + "caniuse-lite": "^1.0.30000939", + "electron-to-chromium": "^1.3.113", + "node-releases": "^1.1.8" + } + }, "bser": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", @@ -1924,6 +2118,11 @@ "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=", "dev": true }, + "caniuse-lite": { + "version": "1.0.30000939", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000939.tgz", + "integrity": "sha512-oXB23ImDJOgQpGjRv1tCtzAvJr4/OvrHi5SO2vUgB0g0xpdZZoA/BxfImiWfdwoYdUTtQrPsXsvYU/dmCSM8gg==" + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -1956,6 +2155,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -2120,7 +2320,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -2128,8 +2327,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "colors": { "version": "0.5.1", @@ -2185,9 +2383,12 @@ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "convert-source-map": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=" + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "requires": { + "safe-buffer": "~5.1.1" + } }, "copy-descriptor": { "version": "0.1.1", @@ -2206,13 +2407,14 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cosmiconfig": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.7.tgz", - "integrity": "sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.1.0.tgz", + "integrity": "sha512-kCNPvthka8gvLtzAxQXvWo4FxqRB+ftRZyPZNuab5ngvM9Y7yw7hbEysglptLgpkGX9nAOKTBVkHUAe8xtYR6Q==", "requires": { "import-fresh": "^2.0.0", "is-directory": "^0.3.1", "js-yaml": "^3.9.0", + "lodash.get": "^4.4.2", "parse-json": "^4.0.0" }, "dependencies": { @@ -2275,12 +2477,6 @@ "lru-cache": "^4.0.1", "shebang-command": "^1.2.0", "which": "^1.2.9" - }, - "dependencies": { - "yallist": { - "version": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } } }, "cross-unzip": { @@ -2340,6 +2536,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, "requires": { "ms": "2.0.0" } @@ -2467,14 +2664,6 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "requires": { - "repeating": "^2.0.0" - } - }, "detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -2812,6 +3001,11 @@ "extract-zip": "^1.6.5" } }, + "electron-to-chromium": { + "version": "1.3.113", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz", + "integrity": "sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g==" + }, "emoji-regex": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz", @@ -3589,26 +3783,25 @@ } }, "fbjs": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", - "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-1.0.0.tgz", + "integrity": "sha512-MUgcMEJaFhCaF1QtWGnmq9ZDRAzECTCRAF7O6UZIlAlkTs1SasiX9aP0Iw7wfD2mJ7wDTNfg2w7u5fSCwJk1OA==", "requires": { - "core-js": "^1.0.0", + "core-js": "^2.4.1", + "fbjs-css-vars": "^1.0.0", "isomorphic-fetch": "^2.1.1", "loose-envify": "^1.0.0", "object-assign": "^4.1.0", "promise": "^7.1.1", "setimmediate": "^1.0.5", "ua-parser-js": "^0.7.18" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" - } } }, + "fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + }, "fbjs-eslint-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fbjs-eslint-utils/-/fbjs-eslint-utils-1.0.0.tgz", @@ -3831,9 +4024,9 @@ } }, "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, "get-func-name": { @@ -3926,7 +4119,8 @@ "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=" + "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=", + "dev": true }, "globby": { "version": "8.0.2", @@ -3963,22 +4157,11 @@ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, "graphql": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.13.2.tgz", - "integrity": "sha1-THQK48Iigj5wBAlvgy57k7IQgnA=", - "requires": { - "iterall": "^1.2.1" - } - }, - "graphql-compiler": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/graphql-compiler/-/graphql-compiler-1.7.0.tgz", - "integrity": "sha512-jC4PBo1ikFRiA2CLclNxMMFJTwhxPam1HxzIxJgWWHm26AXw0ZsN41a2t6vGfw7NxXCfnef4JCIHWFMgIm8iOQ==", - "dev": true, + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.1.1.tgz", + "integrity": "sha512-C5zDzLqvfPAgTtP8AUPIt9keDabrdRAqSWjj2OPRKrKxI9Fb65I36s1uCs1UUBFnSWTdO7hyHi7z1ZbwKMKF6Q==", "requires": { - "chalk": "^1.1.1", - "fb-watchman": "^2.0.0", - "immutable": "~3.7.6" + "iterall": "^1.2.2" } }, "grim": { @@ -4024,6 +4207,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4031,8 +4215,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { "version": "1.0.0", @@ -4093,15 +4276,6 @@ "url-equal": "0.1.2-1" } }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, "hosted-git-info": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", @@ -4182,9 +4356,12 @@ } }, "iconv-lite": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } }, "ignore": { "version": "4.0.6", @@ -4469,6 +4646,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4668,7 +4846,12 @@ "iterall": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", - "integrity": "sha1-ktcN64Ao4MOf8xZP2/TYsIgTDNc=" + "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==" }, "js-tokens": { "version": "3.0.2", @@ -4691,9 +4874,9 @@ "optional": true }, "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, "json-parse-better-errors": { "version": "1.0.2", @@ -4723,9 +4906,12 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "requires": { + "minimist": "^1.2.0" + } }, "jsonfile": { "version": "4.0.0", @@ -4925,7 +5111,8 @@ "lodash": { "version": "4.17.5", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha1-maktZcAnLevoyWtgV7yPv6O+1RE=" + "integrity": "sha1-maktZcAnLevoyWtgV7yPv6O+1RE=", + "dev": true }, "lodash.escape": { "version": "4.0.1", @@ -4939,6 +5126,11 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -4986,9 +5178,9 @@ } }, "lru-cache": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", - "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { "pseudomap": "^1.0.2", @@ -5387,7 +5579,8 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true }, "mute-stream": { "version": "0.0.7", @@ -5515,6 +5708,14 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, + "node-releases": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.8.tgz", + "integrity": "sha512-gQm+K9mGCiT/NXHy+V/ZZS1N/LOaGGqRAAJJs3X9Ah1g+CIbRcBgNyoNYQ+SEtcyAtB9KqDruu+fF7nWjsqRaA==", + "requires": { + "semver": "^5.3.0" + } + }, "nomnom": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz", @@ -5586,6 +5787,11 @@ "throttleit": "0.0.2" } }, + "nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" + }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -6809,7 +7015,7 @@ "os-locale": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha1-QrwpAKa1uL0XN2yOiCtlr8zyS/I=", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { "execa": "^0.7.0", @@ -6820,7 +7026,8 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true }, "p-finally": { "version": "1.0.0", @@ -6829,9 +7036,9 @@ "dev": true }, "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha1-DpK2vty1nwIsE9DxlJ3ILRWQnxw=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { "p-try": "^1.0.0" @@ -7210,14 +7417,15 @@ "dev": true }, "react-relay": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/react-relay/-/react-relay-1.7.0.tgz", - "integrity": "sha512-vZOs1iK6LxqeaAelwSuD5eVXnQux5eVIrik/kxKt6Y3j6ylrjrdTadmgO6sapGc0TG61VtFK5CKPOtW+XSNotg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-relay/-/react-relay-3.0.0.tgz", + "integrity": "sha512-HZQ1CXhF2EBt6f5XG2nWoT5FZIn9zdoHeo8+u5rqQ3fCRBr4qmvLihfehWlCcYCcx57pnAiqsjUdJmwxGUmbsg==", "requires": { - "babel-runtime": "^6.23.0", - "fbjs": "0.8.17", + "@babel/runtime": "^7.0.0", + "fbjs": "^1.0.0", + "nullthrows": "^1.1.0", "prop-types": "^15.5.8", - "relay-runtime": "1.7.0" + "relay-runtime": "3.0.0" } }, "react-select": { @@ -7351,10 +7559,32 @@ "strip-indent": "^1.0.1" } }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" + }, + "regenerate-unicode-properties": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz", + "integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==", + "requires": { + "regenerate": "^1.4.0" + } + }, "regenerator-runtime": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w==" + "integrity": "sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w==", + "dev": true + }, + "regenerator-transform": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.4.tgz", + "integrity": "sha512-T0QMBjK3J0MtxjPmdIMXm72Wvj2Abb0Bd4HADdfijwMdoIsyQZ6fWC7kDFhk2YinBBEMZDL7Y7wh0J1sGx3S4A==", + "requires": { + "private": "^0.1.6" + } }, "regex-not": { "version": "1.0.2", @@ -7376,158 +7606,112 @@ } } }, + "regexp-tree": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.5.tgz", + "integrity": "sha512-nUmxvfJyAODw+0B13hj8CFVAxhe7fDEAgJgaotBu3nnR+IgGgZq59YedJP5VYTlkEfqjuK6TuRpnymKdatLZfQ==" + }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, + "regexpu-core": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.4.0.tgz", + "integrity": "sha512-eDDWElbwwI3K0Lo6CqbQbA6FwgtCz4kYTarrri1okfkRLZAqstU+B3voZBCjg8Fl6iq0gXrJG6MvRgLthfvgOA==", + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^7.0.0", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.0.2" + } + }, + "regjsgen": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", + "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==" + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + } + } + }, "relay-compiler": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/relay-compiler/-/relay-compiler-1.7.0.tgz", - "integrity": "sha512-vCsgj52Up8BmYKcsjxhnXFb8sQL2iE7rZouImPk05ZpRk0uhjkizEncWHiIHSAwq8BehEK1p0G9Hfv2IhLDgMQ==", - "dev": true, - "requires": { - "@babel/generator": "7.0.0-beta.56", - "@babel/parser": "7.0.0-beta.56", - "@babel/types": "7.0.0-beta.56", - "babel-polyfill": "^6.20.0", - "babel-preset-fbjs": "2.2.0", - "babel-runtime": "^6.23.0", - "babel-traverse": "^6.26.0", - "chalk": "^1.1.1", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/relay-compiler/-/relay-compiler-3.0.0.tgz", + "integrity": "sha512-wCD1FV4IKCfeNZdNrdeRjAWl23C3hcInmBbR+rOE/w345+IoXwh1W4o152opRfwHMqPIC5YjyrWh2O73vJYGLw==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/polyfill": "^7.0.0", + "@babel/runtime": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "babel-preset-fbjs": "^3.1.2", + "chalk": "^2.4.1", "fast-glob": "^2.2.2", "fb-watchman": "^2.0.0", - "fbjs": "0.8.17", - "graphql-compiler": "1.7.0", + "fbjs": "^1.0.0", "immutable": "~3.7.6", - "relay-runtime": "1.7.0", + "nullthrows": "^1.1.0", + "relay-runtime": "3.0.0", "signedsource": "^1.0.0", "yargs": "^9.0.0" }, "dependencies": { - "@babel/generator": { - "version": "7.0.0-beta.56", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.56.tgz", - "integrity": "sha512-d+Ls/Vr5OU5FBDYQToXSqAluI3r2UaSoNZ41zD3sxdoVoaT8K5Bdh4So4eG4o//INGM7actValXGfb+5J1+r8w==", - "dev": true, - "requires": { - "@babel/types": "7.0.0-beta.56", - "jsesc": "^2.5.1", - "lodash": "^4.17.10", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" - } - }, - "@babel/parser": { - "version": "7.0.0-beta.56", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.0.0-beta.56.tgz", - "integrity": "sha512-JM0ughhbo+sPXw2Z+SUyowfYrAOhjanzjMshcLswBdXVelJCOeEKe/FqMqPWGVPQr7wByongXIn+MKdCpY7DBw==", - "dev": true - }, - "@babel/types": { - "version": "7.0.0-beta.56", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.56.tgz", - "integrity": "sha512-fRIBeHtKxAD3D1E7hYSpG4MnLt0AfzHHs5gfVclOB0NlfLu3qiWU/IqdbK2ixTK61424iEkV1P/VAzndx6ungA==", + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.10", - "to-fast-properties": "^2.0.0" + "color-convert": "^1.9.0" } }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - } + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - }, - "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - } + "has-flag": "^3.0.0" } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true } } }, "relay-runtime": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/relay-runtime/-/relay-runtime-1.7.0.tgz", - "integrity": "sha512-gvx01aRoLHdIMQoIjMQ79js4BR9JZVfF/SoSiLXvWOgDWEnD7RKb80zmCZTByCpka0GwFzkVwBWUy1gW6g0zlQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/relay-runtime/-/relay-runtime-3.0.0.tgz", + "integrity": "sha512-P9pDoAaqku9m5MTMjampwo+0vsNd2Nv8x78GpWuxPxvqJusqz8MBpu0RVBViIpLzCn77Pegw2ihtXgQSBdvs0w==", "requires": { - "babel-runtime": "^6.23.0", - "fbjs": "0.8.17" + "@babel/runtime": "^7.0.0", + "fbjs": "^1.0.0" } }, "repeat-element": { @@ -7546,6 +7730,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, "requires": { "is-finite": "^1.0.0" } @@ -7696,8 +7881,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "scheduler": { "version": "0.11.3", @@ -7839,7 +8023,8 @@ "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true }, "slice-ansi": { "version": "2.1.0", @@ -7994,14 +8179,6 @@ "urix": "^0.1.0" } }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8=", - "requires": { - "source-map": "^0.5.6" - } - }, "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", @@ -8214,7 +8391,8 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true }, "table": { "version": "5.2.3", @@ -8592,8 +8770,7 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, "to-object-path": { "version": "0.3.0", @@ -8739,6 +8916,30 @@ } } }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz", + "integrity": "sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ==" + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz", + "integrity": "sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg==" + }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -8939,9 +9140,9 @@ } }, "whatwg-fetch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", - "integrity": "sha1-3eal3zFfnTmZGqF2IYU9cguFVm8=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" }, "which": { "version": "1.3.0", From 316a02c0b3b22b4d165fd5c09e3d055d1fa13d12 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Feb 2019 15:06:11 -0500 Subject: [PATCH 2900/4847] Recompile generated Relay files --- ...urrentPullRequestContainerQuery.graphql.js | 52 +-- .../issueishDetailContainerQuery.graphql.js | 344 +++++++++--------- .../issueishSearchContainerQuery.graphql.js | 44 +-- ...sueishTooltipContainer_resource.graphql.js | 12 +- .../prReviewCommentsContainerQuery.graphql.js | 40 +- ...rReviewCommentsContainer_review.graphql.js | 10 +- .../prReviewsContainerQuery.graphql.js | 78 ++-- .../prReviewsContainer_pullRequest.graphql.js | 4 +- .../remoteContainerQuery.graphql.js | 36 +- ...ooltipContainer_repositoryOwner.graphql.js | 8 +- .../issueTimelineControllerQuery.graphql.js | 96 ++--- .../issueTimelineController_issue.graphql.js | 4 +- ...eishDetailController_repository.graphql.js | 36 +- .../issueishListController_results.graphql.js | 4 +- .../prTimelineControllerQuery.graphql.js | 146 ++++---- ...rTimelineController_pullRequest.graphql.js | 4 +- .../issueishTooltipItemQuery.graphql.js | 44 +-- .../userMentionTooltipItemQuery.graphql.js | 26 +- .../issueDetailViewRefetchQuery.graphql.js | 138 +++---- .../issueDetailView_issue.graphql.js | 12 +- .../issueDetailView_repository.graphql.js | 4 +- .../prCommitView_item.graphql.js | 4 +- .../prCommitsViewQuery.graphql.js | 40 +- .../prCommitsView_pullRequest.graphql.js | 4 +- .../prDetailViewRefetchQuery.graphql.js | 302 +++++++-------- .../prDetailView_pullRequest.graphql.js | 16 +- .../prDetailView_repository.graphql.js | 4 +- .../prStatusContextView_context.graphql.js | 4 +- .../prStatusesViewRefetchQuery.graphql.js | 36 +- .../prStatusesView_pullRequest.graphql.js | 12 +- .../commitCommentThreadView_item.graphql.js | 4 +- .../commitCommentView_item.graphql.js | 4 +- .../commitView_commit.graphql.js | 8 +- .../commitsView_nodes.graphql.js | 4 +- .../crossReferencedEventView_item.graphql.js | 16 +- ...crossReferencedEventsView_nodes.graphql.js | 8 +- ...efForcePushedEventView_issueish.graphql.js | 8 +- ...eadRefForcePushedEventView_item.graphql.js | 8 +- .../issueCommentView_item.graphql.js | 4 +- .../mergedEventView_item.graphql.js | 4 +- 40 files changed, 830 insertions(+), 802 deletions(-) diff --git a/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js b/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js index a284aa3c5f..1d731a4e22 100644 --- a/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js +++ b/lib/containers/__generated__/currentPullRequestContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 5821e0667d3f593dc75d2c4ac34985ca + * @relayHash 613bbee977dd8377c2b61e1755aca140 */ /* eslint-disable */ @@ -173,24 +173,19 @@ v5 = { }; return { "kind": "Request", - "operationKind": "query", - "name": "currentPullRequestContainerQuery", - "id": null, - "text": "query currentPullRequestContainerQuery(\n $headOwner: String!\n $headName: String!\n $headRef: String!\n $first: Int!\n) {\n repository(owner: $headOwner, name: $headName) {\n ref(qualifiedName: $headRef) {\n associatedPullRequests(first: $first, states: [OPEN]) {\n totalCount\n nodes {\n ...issueishListController_results\n id\n }\n }\n id\n }\n id\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n repository {\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "currentPullRequestContainerQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "repository", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": "Repository", "plural": false, "selections": [ @@ -199,7 +194,7 @@ return { "alias": null, "name": "ref", "storageKey": null, - "args": v2, + "args": (v2/*: any*/), "concreteType": "Ref", "plural": false, "selections": [ @@ -208,11 +203,11 @@ return { "alias": null, "name": "associatedPullRequests", "storageKey": null, - "args": v3, + "args": (v3/*: any*/), "concreteType": "PullRequestConnection", "plural": false, "selections": [ - v4, + (v4/*: any*/), { "kind": "LinkedField", "alias": null, @@ -240,14 +235,14 @@ return { "operation": { "kind": "Operation", "name": "currentPullRequestContainerQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "repository", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": "Repository", "plural": false, "selections": [ @@ -256,7 +251,7 @@ return { "alias": null, "name": "ref", "storageKey": null, - "args": v2, + "args": (v2/*: any*/), "concreteType": "Ref", "plural": false, "selections": [ @@ -265,11 +260,11 @@ return { "alias": null, "name": "associatedPullRequests", "storageKey": null, - "args": v3, + "args": (v3/*: any*/), "concreteType": "PullRequestConnection", "plural": false, "selections": [ - v4, + (v4/*: any*/), { "kind": "LinkedField", "alias": null, @@ -330,7 +325,7 @@ return { "args": null, "storageKey": null }, - v5 + (v5/*: any*/) ] }, { @@ -356,7 +351,7 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v5 + (v5/*: any*/) ] }, { @@ -418,32 +413,39 @@ return { "args": null, "storageKey": null }, - v5 + (v5/*: any*/) ] }, - v5 + (v5/*: any*/) ] }, - v5 + (v5/*: any*/) ] }, - v5 + (v5/*: any*/) ] } ] }, - v5 + (v5/*: any*/) ] } ] }, - v5 + (v5/*: any*/) ] }, - v5 + (v5/*: any*/) ] } ] + }, + "params": { + "operationKind": "query", + "name": "currentPullRequestContainerQuery", + "id": null, + "text": "query currentPullRequestContainerQuery(\n $headOwner: String!\n $headName: String!\n $headRef: String!\n $first: Int!\n) {\n repository(owner: $headOwner, name: $headName) {\n ref(qualifiedName: $headRef) {\n associatedPullRequests(first: $first, states: [OPEN]) {\n totalCount\n nodes {\n ...issueishListController_results\n id\n }\n }\n id\n }\n id\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n repository {\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", + "metadata": {} } }; })(); diff --git a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js index 2ec6a9595d..d374175432 100644 --- a/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishDetailContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash aa9982b03c50cc4fd52b07a4206b1eb0 + * @relayHash 0d4fc026130019bf15eb5f964be2efcf */ /* eslint-disable */ @@ -708,9 +708,9 @@ v5 = { "storageKey": null }, v6 = [ - v4, - v5, - v2 + (v4/*: any*/), + (v5/*: any*/), + (v2/*: any*/) ], v7 = { "kind": "LinkedField", @@ -720,7 +720,7 @@ v7 = { "args": null, "concreteType": null, "plural": false, - "selections": v6 + "selections": (v6/*: any*/) }, v8 = [ { @@ -773,7 +773,7 @@ v14 = { "storageKey": null }, v15 = [ - v14 + (v14/*: any*/) ], v16 = { "kind": "LinkedField", @@ -784,19 +784,19 @@ v16 = { "concreteType": null, "plural": false, "selections": [ - v4, - v5, - v13, - v2, + (v4/*: any*/), + (v5/*: any*/), + (v13/*: any*/), + (v2/*: any*/), { "kind": "InlineFragment", "type": "Bot", - "selections": v15 + "selections": (v15/*: any*/) }, { "kind": "InlineFragment", "type": "User", - "selections": v15 + "selections": (v15/*: any*/) } ] }, @@ -837,8 +837,8 @@ v20 = { "concreteType": "PageInfo", "plural": false, "selections": [ - v18, - v19 + (v18/*: any*/), + (v19/*: any*/) ] }, v21 = { @@ -856,10 +856,10 @@ v22 = { "storageKey": null }, v23 = [ - v4, - v5, - v13, - v2 + (v4/*: any*/), + (v5/*: any*/), + (v13/*: any*/), + (v2/*: any*/) ], v24 = { "kind": "InlineFragment", @@ -872,7 +872,7 @@ v24 = { "args": null, "storageKey": null }, - v22, + (v22/*: any*/), { "kind": "LinkedField", "alias": null, @@ -881,7 +881,7 @@ v24 = { "args": null, "concreteType": null, "plural": false, - "selections": v23 + "selections": (v23/*: any*/) }, { "kind": "LinkedField", @@ -892,7 +892,7 @@ v24 = { "concreteType": null, "plural": false, "selections": [ - v4, + (v4/*: any*/), { "kind": "LinkedField", "alias": null, @@ -902,9 +902,9 @@ v24 = { "concreteType": "Repository", "plural": false, "selections": [ - v3, - v7, - v2, + (v3/*: any*/), + (v7/*: any*/), + (v2/*: any*/), { "kind": "ScalarField", "alias": null, @@ -914,14 +914,14 @@ v24 = { } ] }, - v2, + (v2/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v10, - v9, - v14, + (v10/*: any*/), + (v9/*: any*/), + (v14/*: any*/), { "kind": "ScalarField", "alias": "prState", @@ -935,9 +935,9 @@ v24 = { "kind": "InlineFragment", "type": "Issue", "selections": [ - v10, - v9, - v14, + (v10/*: any*/), + (v9/*: any*/), + (v14/*: any*/), { "kind": "ScalarField", "alias": "issueState", @@ -952,10 +952,10 @@ v24 = { ] }, v25 = [ - v4, - v13, - v5, - v2 + (v4/*: any*/), + (v13/*: any*/), + (v5/*: any*/), + (v2/*: any*/) ], v26 = { "kind": "LinkedField", @@ -965,7 +965,7 @@ v26 = { "args": null, "concreteType": null, "plural": false, - "selections": v25 + "selections": (v25/*: any*/) }, v27 = { "kind": "ScalarField", @@ -978,10 +978,10 @@ v28 = { "kind": "InlineFragment", "type": "IssueComment", "selections": [ - v26, - v12, - v27, - v14 + (v26/*: any*/), + (v12/*: any*/), + (v27/*: any*/), + (v14/*: any*/) ] }, v29 = { @@ -993,8 +993,8 @@ v29 = { "concreteType": "User", "plural": false, "selections": [ - v5, - v2 + (v5/*: any*/), + (v2/*: any*/) ] }, v30 = { @@ -1017,9 +1017,9 @@ v31 = { "concreteType": "GitActor", "plural": false, "selections": [ - v3, - v29, - v13 + (v3/*: any*/), + (v29/*: any*/), + (v13/*: any*/) ] }, { @@ -1031,9 +1031,9 @@ v31 = { "concreteType": "GitActor", "plural": false, "selections": [ - v3, - v13, - v29 + (v3/*: any*/), + (v13/*: any*/), + (v29/*: any*/) ] }, { @@ -1043,7 +1043,7 @@ v31 = { "args": null, "storageKey": null }, - v30, + (v30/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1100,7 +1100,7 @@ v33 = { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v32 + "selections": (v32/*: any*/) } ] }, @@ -1141,8 +1141,8 @@ v36 = { "concreteType": "PageInfo", "plural": false, "selections": [ - v19, - v18 + (v19/*: any*/), + (v18/*: any*/) ] }, v37 = [ @@ -1153,7 +1153,7 @@ v37 = [ "args": null, "storageKey": null }, - v2 + (v2/*: any*/) ], v38 = [ { @@ -1191,7 +1191,7 @@ v41 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": (v37/*: any*/) }, v42 = { "kind": "LinkedField", @@ -1201,28 +1201,23 @@ v42 = { "args": null, "concreteType": null, "plural": false, - "selections": v25 + "selections": (v25/*: any*/) }; return { "kind": "Request", - "operationKind": "query", - "name": "issueishDetailContainerQuery", - "id": null, - "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_3D8CP9 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "issueishDetailContainerQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "repository", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": "Repository", "plural": false, "selections": [ @@ -1293,51 +1288,51 @@ return { "operation": { "kind": "Operation", "name": "issueishDetailContainerQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "repository", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": "Repository", "plural": false, "selections": [ - v2, - v3, - v7, + (v2/*: any*/), + (v3/*: any*/), + (v7/*: any*/), { "kind": "LinkedField", "alias": "issue", "name": "issueOrPullRequest", "storageKey": null, - "args": v8, + "args": (v8/*: any*/), "concreteType": null, "plural": false, "selections": [ - v4, - v2, + (v4/*: any*/), + (v2/*: any*/), { "kind": "InlineFragment", "type": "Issue", "selections": [ - v9, - v10, - v11, - v12, - v16, - v14, + (v9/*: any*/), + (v10/*: any*/), + (v11/*: any*/), + (v12/*: any*/), + (v16/*: any*/), + (v14/*: any*/), { "kind": "LinkedField", "alias": null, "name": "timeline", "storageKey": null, - "args": v17, + "args": (v17/*: any*/), "concreteType": "IssueTimelineConnection", "plural": false, "selections": [ - v20, + (v20/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1347,7 +1342,7 @@ return { "concreteType": "IssueTimelineItemEdge", "plural": true, "selections": [ - v21, + (v21/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1357,11 +1352,11 @@ return { "concreteType": null, "plural": false, "selections": [ - v4, - v2, - v24, - v28, - v31 + (v4/*: any*/), + (v2/*: any*/), + (v24/*: any*/), + (v28/*: any*/), + (v31/*: any*/) ] } ] @@ -1372,12 +1367,12 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v17, + "args": (v17/*: any*/), "handle": "connection", "key": "IssueTimelineController_timeline", "filters": null }, - v33 + (v33/*: any*/) ] } ] @@ -1387,12 +1382,12 @@ return { "alias": "pullRequest", "name": "issueOrPullRequest", "storageKey": null, - "args": v8, + "args": (v8/*: any*/), "concreteType": null, "plural": false, "selections": [ - v4, - v2, + (v4/*: any*/), + (v2/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", @@ -1402,11 +1397,11 @@ return { "alias": null, "name": "commits", "storageKey": null, - "args": v34, + "args": (v34/*: any*/), "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ - v20, + (v20/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1416,7 +1411,7 @@ return { "concreteType": "PullRequestCommitEdge", "plural": true, "selections": [ - v21, + (v21/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1435,7 +1430,7 @@ return { "concreteType": "Commit", "plural": false, "selections": [ - v2, + (v2/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1445,8 +1440,8 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v13, - v3, + (v13/*: any*/), + (v3/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1477,12 +1472,12 @@ return { "args": null, "storageKey": null }, - v30, - v14 + (v30/*: any*/), + (v14/*: any*/) ] }, - v2, - v4 + (v2/*: any*/), + (v4/*: any*/) ] } ] @@ -1493,12 +1488,12 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v34, + "args": (v34/*: any*/), "handle": "connection", "key": "prCommitsView_commits", "filters": null }, - v9, + (v9/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1515,9 +1510,9 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v3, - v7, - v14, + (v3/*: any*/), + (v7/*: any*/), + (v14/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1525,10 +1520,10 @@ return { "args": null, "storageKey": null }, - v2 + (v2/*: any*/) ] }, - v22, + (v22/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1536,17 +1531,17 @@ return { "args": null, "storageKey": null }, - v14, + (v14/*: any*/), { "kind": "LinkedField", "alias": null, "name": "reviews", "storageKey": null, - "args": v35, + "args": (v35/*: any*/), "concreteType": "PullRequestReviewConnection", "plural": false, "selections": [ - v36, + (v36/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1556,7 +1551,7 @@ return { "concreteType": "PullRequestReviewEdge", "plural": true, "selections": [ - v21, + (v21/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1566,7 +1561,7 @@ return { "concreteType": "PullRequestReview", "plural": false, "selections": [ - v2, + (v2/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1582,9 +1577,9 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": (v37/*: any*/) }, - v11, + (v11/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1600,7 +1595,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v6 + "selections": (v6/*: any*/) }, { "kind": "LinkedField", @@ -1611,9 +1606,9 @@ return { "concreteType": null, "plural": false, "selections": [ - v4, - v13, - v2 + (v4/*: any*/), + (v13/*: any*/), + (v2/*: any*/) ] }, { @@ -1621,11 +1616,11 @@ return { "alias": null, "name": "comments", "storageKey": null, - "args": v38, + "args": (v38/*: any*/), "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ - v36, + (v36/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1635,7 +1630,7 @@ return { "concreteType": "PullRequestReviewCommentEdge", "plural": true, "selections": [ - v21, + (v21/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1645,9 +1640,9 @@ return { "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v2, - v26, - v12, + (v2/*: any*/), + (v26/*: any*/), + (v12/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1655,8 +1650,8 @@ return { "args": null, "storageKey": null }, - v39, - v40, + (v39/*: any*/), + (v40/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1666,12 +1661,12 @@ return { "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v2 + (v2/*: any*/) ] }, - v27, - v14, - v4 + (v27/*: any*/), + (v14/*: any*/), + (v4/*: any*/) ] } ] @@ -1682,12 +1677,12 @@ return { "kind": "LinkedHandle", "alias": null, "name": "comments", - "args": v38, + "args": (v38/*: any*/), "handle": "connection", "key": "PrReviewCommentsContainer_comments", "filters": null }, - v4 + (v4/*: any*/) ] } ] @@ -1698,12 +1693,12 @@ return { "kind": "LinkedHandle", "alias": null, "name": "reviews", - "args": v35, + "args": (v35/*: any*/), "handle": "connection", "key": "PrReviewsContainer_reviews", "filters": null }, - v10, + (v10/*: any*/), { "kind": "LinkedField", "alias": "countedCommits", @@ -1712,7 +1707,7 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v32 + "selections": (v32/*: any*/) }, { "kind": "LinkedField", @@ -1766,7 +1761,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v11, + (v11/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1776,8 +1771,8 @@ return { "concreteType": "StatusContext", "plural": true, "selections": [ - v2, - v11, + (v2/*: any*/), + (v11/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1801,21 +1796,21 @@ return { } ] }, - v2 + (v2/*: any*/) ] }, - v2 + (v2/*: any*/) ] }, - v2 + (v2/*: any*/) ] } ] } ] }, - v11, - v12, + (v11/*: any*/), + (v12/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1823,7 +1818,7 @@ return { "args": null, "storageKey": null }, - v16, + (v16/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1832,7 +1827,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v6 + "selections": (v6/*: any*/) }, { "kind": "LinkedField", @@ -1843,8 +1838,8 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v7, - v2 + (v7/*: any*/), + (v2/*: any*/) ] }, { @@ -1852,11 +1847,11 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": v17, + "args": (v17/*: any*/), "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v20, + (v20/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1866,7 +1861,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v21, + (v21/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1876,14 +1871,14 @@ return { "concreteType": null, "plural": false, "selections": [ - v4, - v2, - v24, + (v4/*: any*/), + (v2/*: any*/), + (v24/*: any*/), { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v41, + (v41/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1918,7 +1913,7 @@ return { "concreteType": "CommitComment", "plural": false, "selections": [ - v2, + (v2/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1927,13 +1922,13 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v23 + "selections": (v23/*: any*/) }, - v41, - v12, - v27, - v39, - v40 + (v41/*: any*/), + (v12/*: any*/), + (v27/*: any*/), + (v39/*: any*/), + (v40/*: any*/) ] } ] @@ -1946,7 +1941,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v42, + (v42/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1955,7 +1950,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": (v37/*: any*/) }, { "kind": "LinkedField", @@ -1965,17 +1960,17 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v37 + "selections": (v37/*: any*/) }, - v27 + (v27/*: any*/) ] }, { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v42, - v41, + (v42/*: any*/), + (v41/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1983,11 +1978,11 @@ return { "args": null, "storageKey": null }, - v27 + (v27/*: any*/) ] }, - v28, - v31 + (v28/*: any*/), + (v31/*: any*/) ] } ] @@ -1998,12 +1993,12 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v17, + "args": (v17/*: any*/), "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null }, - v33 + (v33/*: any*/) ] } ] @@ -2011,6 +2006,13 @@ return { ] } ] + }, + "params": { + "operationKind": "query", + "name": "issueishDetailContainerQuery", + "id": null, + "text": "query issueishDetailContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $issueishNumber: Int!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n ...issueishDetailController_repository_y3nHF\n id\n }\n}\n\nfragment issueishDetailController_repository_y3nHF on Repository {\n ...issueDetailView_repository\n ...prDetailView_repository\n name\n owner {\n __typename\n login\n id\n }\n issue: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on Issue {\n title\n number\n ...issueDetailView_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n pullRequest: issueOrPullRequest(number: $issueishNumber) {\n __typename\n ... on PullRequest {\n title\n number\n headRefName\n headRepository {\n name\n owner {\n __typename\n login\n id\n }\n url\n sshUrl\n id\n }\n ...prDetailView_pullRequest_2qM2KL\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_repository on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_3D8CP9 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n", + "metadata": {} } }; })(); diff --git a/lib/containers/__generated__/issueishSearchContainerQuery.graphql.js b/lib/containers/__generated__/issueishSearchContainerQuery.graphql.js index a23ceb7401..5da39bd72d 100644 --- a/lib/containers/__generated__/issueishSearchContainerQuery.graphql.js +++ b/lib/containers/__generated__/issueishSearchContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 4f7294887e96b0a41dd57f0f3164f765 + * @relayHash 2976f0b1cbe75dfca74d37fc0f14877b */ /* eslint-disable */ @@ -139,28 +139,23 @@ v4 = { }; return { "kind": "Request", - "operationKind": "query", - "name": "issueishSearchContainerQuery", - "id": null, - "text": "query issueishSearchContainerQuery(\n $query: String!\n $first: Int!\n) {\n search(first: $first, query: $query, type: ISSUE) {\n issueCount\n nodes {\n __typename\n ...issueishListController_results\n ... on Node {\n id\n }\n }\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n repository {\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "issueishSearchContainerQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "search", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": "SearchResultItemConnection", "plural": false, "selections": [ - v2, + (v2/*: any*/), { "kind": "LinkedField", "alias": null, @@ -184,18 +179,18 @@ return { "operation": { "kind": "Operation", "name": "issueishSearchContainerQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "search", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": "SearchResultItemConnection", "plural": false, "selections": [ - v2, + (v2/*: any*/), { "kind": "LinkedField", "alias": null, @@ -205,8 +200,8 @@ return { "concreteType": null, "plural": true, "selections": [ - v3, - v4, + (v3/*: any*/), + (v4/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", @@ -241,7 +236,7 @@ return { "concreteType": null, "plural": false, "selections": [ - v3, + (v3/*: any*/), { "kind": "ScalarField", "alias": null, @@ -256,7 +251,7 @@ return { "args": null, "storageKey": null }, - v4 + (v4/*: any*/) ] }, { @@ -282,7 +277,7 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v4 + (v4/*: any*/) ] }, { @@ -344,16 +339,16 @@ return { "args": null, "storageKey": null }, - v4 + (v4/*: any*/) ] }, - v4 + (v4/*: any*/) ] }, - v4 + (v4/*: any*/) ] }, - v4 + (v4/*: any*/) ] } ] @@ -365,6 +360,13 @@ return { ] } ] + }, + "params": { + "operationKind": "query", + "name": "issueishSearchContainerQuery", + "id": null, + "text": "query issueishSearchContainerQuery(\n $query: String!\n $first: Int!\n) {\n search(first: $first, query: $query, type: ISSUE) {\n issueCount\n nodes {\n __typename\n ...issueishListController_results\n ... on Node {\n id\n }\n }\n }\n}\n\nfragment issueishListController_results on PullRequest {\n number\n title\n url\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n createdAt\n headRefName\n repository {\n id\n }\n commits(last: 1) {\n nodes {\n commit {\n status {\n contexts {\n state\n id\n }\n id\n }\n id\n }\n id\n }\n }\n}\n", + "metadata": {} } }; })(); diff --git a/lib/containers/__generated__/issueishTooltipContainer_resource.graphql.js b/lib/containers/__generated__/issueishTooltipContainer_resource.graphql.js index c07f7ed456..78554a9501 100644 --- a/lib/containers/__generated__/issueishTooltipContainer_resource.graphql.js +++ b/lib/containers/__generated__/issueishTooltipContainer_resource.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; export type IssueState = "CLOSED" | "OPEN" | "%future added value"; export type PullRequestState = "CLOSED" | "MERGED" | "OPEN" | "%future added value"; import type { FragmentReference } from "relay-runtime"; @@ -53,7 +53,7 @@ export type issueishTooltipContainer_resource = {| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = { "kind": "ScalarField", "alias": null, @@ -108,7 +108,7 @@ v1 = [ "concreteType": null, "plural": false, "selections": [ - v0 + (v0/*: any*/) ] } ] @@ -122,7 +122,7 @@ v1 = [ "concreteType": null, "plural": false, "selections": [ - v0, + (v0/*: any*/), { "kind": "ScalarField", "alias": null, @@ -150,12 +150,12 @@ return { { "kind": "InlineFragment", "type": "PullRequest", - "selections": v1 + "selections": (v1/*: any*/) }, { "kind": "InlineFragment", "type": "Issue", - "selections": v1 + "selections": (v1/*: any*/) } ] }; diff --git a/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js index 6fa92aa46b..b5fec8befa 100644 --- a/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewCommentsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash d372fbac67c0b387985686b68db27130 + * @relayHash 64864427d1bd48cdc524cbec06af166c */ /* eslint-disable */ @@ -137,24 +137,19 @@ v4 = [ ]; return { "kind": "Request", - "operationKind": "query", - "name": "prReviewCommentsContainerQuery", - "id": null, - "text": "query prReviewCommentsContainerQuery(\n $commentCount: Int!\n $commentCursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequestReview {\n ...prReviewCommentsContainer_review_1VbUmL\n }\n id\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "prReviewCommentsContainerQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "node", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -189,19 +184,19 @@ return { "operation": { "kind": "Operation", "name": "prReviewCommentsContainerQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "node", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ - v2, - v3, + (v2/*: any*/), + (v3/*: any*/), { "kind": "InlineFragment", "type": "PullRequestReview", @@ -218,7 +213,7 @@ return { "alias": null, "name": "comments", "storageKey": null, - "args": v4, + "args": (v4/*: any*/), "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ @@ -272,7 +267,7 @@ return { "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v3, + (v3/*: any*/), { "kind": "LinkedField", "alias": null, @@ -282,7 +277,7 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, + (v2/*: any*/), { "kind": "ScalarField", "alias": null, @@ -297,7 +292,7 @@ return { "args": null, "storageKey": null }, - v3 + (v3/*: any*/) ] }, { @@ -337,7 +332,7 @@ return { "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v3 + (v3/*: any*/) ] }, { @@ -354,7 +349,7 @@ return { "args": null, "storageKey": null }, - v2 + (v2/*: any*/) ] } ] @@ -365,7 +360,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "comments", - "args": v4, + "args": (v4/*: any*/), "handle": "connection", "key": "PrReviewCommentsContainer_comments", "filters": null @@ -375,6 +370,13 @@ return { ] } ] + }, + "params": { + "operationKind": "query", + "name": "prReviewCommentsContainerQuery", + "id": null, + "text": "query prReviewCommentsContainerQuery(\n $commentCount: Int!\n $commentCursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequestReview {\n ...prReviewCommentsContainer_review_1VbUmL\n }\n id\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "metadata": {} } }; })(); diff --git a/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js b/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js index ebe2215fea..078224f564 100644 --- a/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js +++ b/lib/containers/__generated__/prReviewCommentsContainer_review.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; declare export opaque type prReviewCommentsContainer_review$ref: FragmentReference; export type prReviewCommentsContainer_review = {| @@ -43,7 +43,7 @@ export type prReviewCommentsContainer_review = {| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = { "kind": "ScalarField", "alias": null, @@ -82,7 +82,7 @@ return { } ], "selections": [ - v0, + (v0/*: any*/), { "kind": "ScalarField", "alias": null, @@ -149,7 +149,7 @@ return { "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v0, + (v0/*: any*/), { "kind": "LinkedField", "alias": null, @@ -212,7 +212,7 @@ return { "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v0 + (v0/*: any*/) ] }, { diff --git a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js index 19537cca71..539d652da7 100644 --- a/lib/containers/__generated__/prReviewsContainerQuery.graphql.js +++ b/lib/containers/__generated__/prReviewsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash a3845eb13d831f5f140cc6adc98de1df + * @relayHash ccf4c910993e0eac7e4d84076a406ae7 */ /* eslint-disable */ @@ -261,24 +261,19 @@ v10 = [ ]; return { "kind": "Request", - "operationKind": "query", - "name": "prReviewsContainerQuery", - "id": null, - "text": "query prReviewsContainerQuery(\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_y4qc0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "prReviewsContainerQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "resource", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -325,34 +320,34 @@ return { "operation": { "kind": "Operation", "name": "prReviewsContainerQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "resource", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ - v2, - v3, + (v2/*: any*/), + (v3/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v4, + (v4/*: any*/), { "kind": "LinkedField", "alias": null, "name": "reviews", "storageKey": null, - "args": v5, + "args": (v5/*: any*/), "concreteType": "PullRequestReviewConnection", "plural": false, "selections": [ - v6, + (v6/*: any*/), { "kind": "LinkedField", "alias": null, @@ -362,7 +357,7 @@ return { "concreteType": "PullRequestReviewEdge", "plural": true, "selections": [ - v7, + (v7/*: any*/), { "kind": "LinkedField", "alias": null, @@ -372,7 +367,7 @@ return { "concreteType": "PullRequestReview", "plural": false, "selections": [ - v3, + (v3/*: any*/), { "kind": "ScalarField", "alias": null, @@ -396,7 +391,7 @@ return { "args": null, "storageKey": null }, - v3 + (v3/*: any*/) ] }, { @@ -422,9 +417,9 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, - v8, - v3 + (v2/*: any*/), + (v8/*: any*/), + (v3/*: any*/) ] }, { @@ -436,9 +431,9 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, - v9, - v3 + (v2/*: any*/), + (v9/*: any*/), + (v3/*: any*/) ] }, { @@ -446,11 +441,11 @@ return { "alias": null, "name": "comments", "storageKey": null, - "args": v10, + "args": (v10/*: any*/), "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ - v6, + (v6/*: any*/), { "kind": "LinkedField", "alias": null, @@ -460,7 +455,7 @@ return { "concreteType": "PullRequestReviewCommentEdge", "plural": true, "selections": [ - v7, + (v7/*: any*/), { "kind": "LinkedField", "alias": null, @@ -470,7 +465,7 @@ return { "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v3, + (v3/*: any*/), { "kind": "LinkedField", "alias": null, @@ -480,10 +475,10 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, - v9, - v8, - v3 + (v2/*: any*/), + (v9/*: any*/), + (v8/*: any*/), + (v3/*: any*/) ] }, { @@ -523,7 +518,7 @@ return { "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v3 + (v3/*: any*/) ] }, { @@ -533,8 +528,8 @@ return { "args": null, "storageKey": null }, - v4, - v2 + (v4/*: any*/), + (v2/*: any*/) ] } ] @@ -545,12 +540,12 @@ return { "kind": "LinkedHandle", "alias": null, "name": "comments", - "args": v10, + "args": (v10/*: any*/), "handle": "connection", "key": "PrReviewCommentsContainer_comments", "filters": null }, - v2 + (v2/*: any*/) ] } ] @@ -561,7 +556,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "reviews", - "args": v5, + "args": (v5/*: any*/), "handle": "connection", "key": "PrReviewsContainer_reviews", "filters": null @@ -571,6 +566,13 @@ return { ] } ] + }, + "params": { + "operationKind": "query", + "name": "prReviewsContainerQuery", + "id": null, + "text": "query prReviewsContainerQuery(\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prReviewsContainer_pullRequest_y4qc0\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "metadata": {} } }; })(); diff --git a/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js index 04d2100cf7..9d8b491a56 100644 --- a/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js +++ b/lib/containers/__generated__/prReviewsContainer_pullRequest.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; type prReviewCommentsContainer_review$ref = any; export type PullRequestReviewState = "APPROVED" | "CHANGES_REQUESTED" | "COMMENTED" | "DISMISSED" | "PENDING" | "%future added value"; import type { FragmentReference } from "relay-runtime"; @@ -44,7 +44,7 @@ export type prReviewsContainer_pullRequest = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "prReviewsContainer_pullRequest", "type": "PullRequest", diff --git a/lib/containers/__generated__/remoteContainerQuery.graphql.js b/lib/containers/__generated__/remoteContainerQuery.graphql.js index a5ac465623..0e82900d15 100644 --- a/lib/containers/__generated__/remoteContainerQuery.graphql.js +++ b/lib/containers/__generated__/remoteContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 982797d241da7600c6e95299dff83585 + * @relayHash 727f857cb06ae341da8460148250d694 */ /* eslint-disable */ @@ -97,28 +97,23 @@ v4 = { }; return { "kind": "Request", - "operationKind": "query", - "name": "remoteContainerQuery", - "id": null, - "text": "query remoteContainerQuery(\n $owner: String!\n $name: String!\n) {\n repository(owner: $owner, name: $name) {\n id\n defaultBranchRef {\n prefix\n name\n id\n }\n }\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "remoteContainerQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "repository", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": "Repository", "plural": false, "selections": [ - v2, + (v2/*: any*/), { "kind": "LinkedField", "alias": null, @@ -128,8 +123,8 @@ return { "concreteType": "Ref", "plural": false, "selections": [ - v3, - v4 + (v3/*: any*/), + (v4/*: any*/) ] } ] @@ -139,18 +134,18 @@ return { "operation": { "kind": "Operation", "name": "remoteContainerQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "repository", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": "Repository", "plural": false, "selections": [ - v2, + (v2/*: any*/), { "kind": "LinkedField", "alias": null, @@ -160,14 +155,21 @@ return { "concreteType": "Ref", "plural": false, "selections": [ - v3, - v4, - v2 + (v3/*: any*/), + (v4/*: any*/), + (v2/*: any*/) ] } ] } ] + }, + "params": { + "operationKind": "query", + "name": "remoteContainerQuery", + "id": null, + "text": "query remoteContainerQuery(\n $owner: String!\n $name: String!\n) {\n repository(owner: $owner, name: $name) {\n id\n defaultBranchRef {\n prefix\n name\n id\n }\n }\n}\n", + "metadata": {} } }; })(); diff --git a/lib/containers/__generated__/userMentionTooltipContainer_repositoryOwner.graphql.js b/lib/containers/__generated__/userMentionTooltipContainer_repositoryOwner.graphql.js index 1f4b1e0cfe..3a0c3b2550 100644 --- a/lib/containers/__generated__/userMentionTooltipContainer_repositoryOwner.graphql.js +++ b/lib/containers/__generated__/userMentionTooltipContainer_repositoryOwner.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; declare export opaque type userMentionTooltipContainer_repositoryOwner$ref: FragmentReference; export type userMentionTooltipContainer_repositoryOwner = {| @@ -25,7 +25,7 @@ export type userMentionTooltipContainer_repositoryOwner = {| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = [ { "kind": "ScalarField", @@ -64,7 +64,7 @@ return { "args": null, "concreteType": "RepositoryConnection", "plural": false, - "selections": v0 + "selections": (v0/*: any*/) }, { "kind": "InlineFragment", @@ -78,7 +78,7 @@ return { "args": null, "concreteType": "UserConnection", "plural": false, - "selections": v0 + "selections": (v0/*: any*/) } ] }, diff --git a/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js b/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js index 61cd337896..582ea5717e 100644 --- a/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js +++ b/lib/controllers/__generated__/issueTimelineControllerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 70fb97e27904226bef17642a8a7b34e2 + * @relayHash a967f9435e3ba31acfede3717315be7e */ /* eslint-disable */ @@ -292,30 +292,25 @@ v11 = { "concreteType": "User", "plural": false, "selections": [ - v6, - v3 + (v6/*: any*/), + (v3/*: any*/) ] }; return { "kind": "Request", - "operationKind": "query", - "name": "issueTimelineControllerQuery", - "id": null, - "text": "query issueTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on Issue {\n ...issueTimelineController_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "issueTimelineControllerQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "resource", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -350,30 +345,30 @@ return { "operation": { "kind": "Operation", "name": "issueTimelineControllerQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "resource", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ - v2, - v3, + (v2/*: any*/), + (v3/*: any*/), { "kind": "InlineFragment", "type": "Issue", "selections": [ - v4, + (v4/*: any*/), { "kind": "LinkedField", "alias": null, "name": "timeline", "storageKey": null, - "args": v5, + "args": (v5/*: any*/), "concreteType": "IssueTimelineConnection", "plural": false, "selections": [ @@ -427,8 +422,8 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, - v3, + (v2/*: any*/), + (v3/*: any*/), { "kind": "InlineFragment", "type": "CrossReferencedEvent", @@ -456,10 +451,10 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, - v6, - v7, - v3 + (v2/*: any*/), + (v6/*: any*/), + (v7/*: any*/), + (v3/*: any*/) ] }, { @@ -471,7 +466,7 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, + (v2/*: any*/), { "kind": "LinkedField", "alias": null, @@ -481,7 +476,7 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v8, + (v8/*: any*/), { "kind": "LinkedField", "alias": null, @@ -491,12 +486,12 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, - v6, - v3 + (v2/*: any*/), + (v6/*: any*/), + (v3/*: any*/) ] }, - v3, + (v3/*: any*/), { "kind": "ScalarField", "alias": null, @@ -506,14 +501,14 @@ return { } ] }, - v3, + (v3/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v9, - v10, - v4, + (v9/*: any*/), + (v10/*: any*/), + (v4/*: any*/), { "kind": "ScalarField", "alias": "prState", @@ -527,9 +522,9 @@ return { "kind": "InlineFragment", "type": "Issue", "selections": [ - v9, - v10, - v4, + (v9/*: any*/), + (v10/*: any*/), + (v4/*: any*/), { "kind": "ScalarField", "alias": "issueState", @@ -556,10 +551,10 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, - v7, - v6, - v3 + (v2/*: any*/), + (v7/*: any*/), + (v6/*: any*/), + (v3/*: any*/) ] }, { @@ -576,7 +571,7 @@ return { "args": null, "storageKey": null }, - v4 + (v4/*: any*/) ] }, { @@ -592,9 +587,9 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v8, - v11, - v7 + (v8/*: any*/), + (v11/*: any*/), + (v7/*: any*/) ] }, { @@ -606,9 +601,9 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v8, - v7, - v11 + (v8/*: any*/), + (v7/*: any*/), + (v11/*: any*/) ] }, { @@ -658,7 +653,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v5, + "args": (v5/*: any*/), "handle": "connection", "key": "IssueTimelineController_timeline", "filters": null @@ -668,6 +663,13 @@ return { ] } ] + }, + "params": { + "operationKind": "query", + "name": "issueTimelineControllerQuery", + "id": null, + "text": "query issueTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on Issue {\n ...issueTimelineController_issue_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", + "metadata": {} } }; })(); diff --git a/lib/controllers/__generated__/issueTimelineController_issue.graphql.js b/lib/controllers/__generated__/issueTimelineController_issue.graphql.js index d5f348a00f..225b374ff6 100644 --- a/lib/controllers/__generated__/issueTimelineController_issue.graphql.js +++ b/lib/controllers/__generated__/issueTimelineController_issue.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; type commitsView_nodes$ref = any; type crossReferencedEventsView_nodes$ref = any; type issueCommentView_item$ref = any; @@ -33,7 +33,7 @@ export type issueTimelineController_issue = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "issueTimelineController_issue", "type": "Issue", diff --git a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js index fa323bdbdd..d2d232f883 100644 --- a/lib/controllers/__generated__/issueishDetailController_repository.graphql.js +++ b/lib/controllers/__generated__/issueishDetailController_repository.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; type issueDetailView_issue$ref = any; type issueDetailView_repository$ref = any; type prDetailView_pullRequest$ref = any; @@ -54,7 +54,7 @@ export type issueishDetailController_repository = {| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = { "kind": "ScalarField", "alias": null, @@ -193,30 +193,30 @@ return { "name": "prDetailView_repository", "args": null }, - v0, - v1, + (v0/*: any*/), + (v1/*: any*/), { "kind": "LinkedField", "alias": "issue", "name": "issueOrPullRequest", "storageKey": null, - "args": v2, + "args": (v2/*: any*/), "concreteType": null, "plural": false, "selections": [ - v3, + (v3/*: any*/), { "kind": "InlineFragment", "type": "Issue", "selections": [ - v4, - v5, + (v4/*: any*/), + (v5/*: any*/), { "kind": "FragmentSpread", "name": "issueDetailView_issue", "args": [ - v6, - v7 + (v6/*: any*/), + (v7/*: any*/) ] } ] @@ -228,17 +228,17 @@ return { "alias": "pullRequest", "name": "issueOrPullRequest", "storageKey": null, - "args": v2, + "args": (v2/*: any*/), "concreteType": null, "plural": false, "selections": [ - v3, + (v3/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v4, - v5, + (v4/*: any*/), + (v5/*: any*/), { "kind": "ScalarField", "alias": null, @@ -255,8 +255,8 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v0, - v1, + (v0/*: any*/), + (v1/*: any*/), { "kind": "ScalarField", "alias": null, @@ -313,8 +313,8 @@ return { "variableName": "reviewCursor", "type": null }, - v6, - v7 + (v6/*: any*/), + (v7/*: any*/) ] } ] diff --git a/lib/controllers/__generated__/issueishListController_results.graphql.js b/lib/controllers/__generated__/issueishListController_results.graphql.js index 9349b1b393..79ba552a04 100644 --- a/lib/controllers/__generated__/issueishListController_results.graphql.js +++ b/lib/controllers/__generated__/issueishListController_results.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; export type StatusState = "ERROR" | "EXPECTED" | "FAILURE" | "PENDING" | "SUCCESS" | "%future added value"; import type { FragmentReference } from "relay-runtime"; declare export opaque type issueishListController_results$ref: FragmentReference; @@ -40,7 +40,7 @@ export type issueishListController_results = $ReadOnlyArray<{| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "issueishListController_results", "type": "PullRequest", diff --git a/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js b/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js index 33b5c8ca6a..0a33d7c6ce 100644 --- a/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js +++ b/lib/controllers/__generated__/prTimelineControllerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash bef5de96f41034a1a27b9ace9f641f7b + * @relayHash b92dc04d77687fc820129507a7ab69a9 */ /* eslint-disable */ @@ -334,9 +334,9 @@ v5 = { "storageKey": null }, v6 = [ - v2, - v5, - v3 + (v2/*: any*/), + (v5/*: any*/), + (v3/*: any*/) ], v7 = { "kind": "LinkedField", @@ -346,7 +346,7 @@ v7 = { "args": null, "concreteType": null, "plural": false, - "selections": v6 + "selections": (v6/*: any*/) }, v8 = [ { @@ -370,10 +370,10 @@ v9 = { "storageKey": null }, v10 = [ - v2, - v5, - v9, - v3 + (v2/*: any*/), + (v5/*: any*/), + (v9/*: any*/), + (v3/*: any*/) ], v11 = { "kind": "ScalarField", @@ -404,7 +404,7 @@ v14 = [ "args": null, "storageKey": null }, - v3 + (v3/*: any*/) ], v15 = { "kind": "LinkedField", @@ -414,7 +414,7 @@ v15 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v14 + "selections": (v14/*: any*/) }, v16 = { "kind": "ScalarField", @@ -431,10 +431,10 @@ v17 = { "storageKey": null }, v18 = [ - v2, - v9, - v5, - v3 + (v2/*: any*/), + (v9/*: any*/), + (v5/*: any*/), + (v3/*: any*/) ], v19 = { "kind": "LinkedField", @@ -444,7 +444,7 @@ v19 = { "args": null, "concreteType": null, "plural": false, - "selections": v18 + "selections": (v18/*: any*/) }, v20 = { "kind": "LinkedField", @@ -455,30 +455,25 @@ v20 = { "concreteType": "User", "plural": false, "selections": [ - v5, - v3 + (v5/*: any*/), + (v3/*: any*/) ] }; return { "kind": "Request", - "operationKind": "query", - "name": "prTimelineControllerQuery", - "id": null, - "text": "query prTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "prTimelineControllerQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "resource", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -513,24 +508,24 @@ return { "operation": { "kind": "Operation", "name": "prTimelineControllerQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "resource", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ - v2, - v3, + (v2/*: any*/), + (v3/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v4, + (v4/*: any*/), { "kind": "ScalarField", "alias": null, @@ -546,7 +541,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v6 + "selections": (v6/*: any*/) }, { "kind": "LinkedField", @@ -557,8 +552,8 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v7, - v3 + (v7/*: any*/), + (v3/*: any*/) ] }, { @@ -566,7 +561,7 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": v8, + "args": (v8/*: any*/), "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ @@ -620,8 +615,8 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, - v3, + (v2/*: any*/), + (v3/*: any*/), { "kind": "InlineFragment", "type": "CrossReferencedEvent", @@ -648,7 +643,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v10 + "selections": (v10/*: any*/) }, { "kind": "LinkedField", @@ -659,7 +654,7 @@ return { "concreteType": null, "plural": false, "selections": [ - v2, + (v2/*: any*/), { "kind": "LinkedField", "alias": null, @@ -669,9 +664,9 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v11, - v7, - v3, + (v11/*: any*/), + (v7/*: any*/), + (v3/*: any*/), { "kind": "ScalarField", "alias": null, @@ -681,14 +676,14 @@ return { } ] }, - v3, + (v3/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v12, - v13, - v4, + (v12/*: any*/), + (v13/*: any*/), + (v4/*: any*/), { "kind": "ScalarField", "alias": "prState", @@ -702,9 +697,9 @@ return { "kind": "InlineFragment", "type": "Issue", "selections": [ - v12, - v13, - v4, + (v12/*: any*/), + (v13/*: any*/), + (v4/*: any*/), { "kind": "ScalarField", "alias": "issueState", @@ -722,7 +717,7 @@ return { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v15, + (v15/*: any*/), { "kind": "LinkedField", "alias": null, @@ -757,7 +752,7 @@ return { "concreteType": "CommitComment", "plural": false, "selections": [ - v3, + (v3/*: any*/), { "kind": "LinkedField", "alias": null, @@ -766,11 +761,11 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v10 + "selections": (v10/*: any*/) }, - v15, - v16, - v17, + (v15/*: any*/), + (v16/*: any*/), + (v17/*: any*/), { "kind": "ScalarField", "alias": null, @@ -797,7 +792,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v19, + (v19/*: any*/), { "kind": "LinkedField", "alias": null, @@ -806,7 +801,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v14 + "selections": (v14/*: any*/) }, { "kind": "LinkedField", @@ -816,17 +811,17 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v14 + "selections": (v14/*: any*/) }, - v17 + (v17/*: any*/) ] }, { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v19, - v15, + (v19/*: any*/), + (v15/*: any*/), { "kind": "ScalarField", "alias": null, @@ -834,7 +829,7 @@ return { "args": null, "storageKey": null }, - v17 + (v17/*: any*/) ] }, { @@ -849,11 +844,11 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v18 + "selections": (v18/*: any*/) }, - v16, - v17, - v4 + (v16/*: any*/), + (v17/*: any*/), + (v4/*: any*/) ] }, { @@ -869,9 +864,9 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v11, - v20, - v9 + (v11/*: any*/), + (v20/*: any*/), + (v9/*: any*/) ] }, { @@ -883,9 +878,9 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v11, - v9, - v20 + (v11/*: any*/), + (v9/*: any*/), + (v20/*: any*/) ] }, { @@ -935,7 +930,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v8, + "args": (v8/*: any*/), "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null @@ -945,6 +940,13 @@ return { ] } ] + }, + "params": { + "operationKind": "query", + "name": "prTimelineControllerQuery", + "id": null, + "text": "query prTimelineControllerQuery(\n $timelineCount: Int!\n $timelineCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prTimelineController_pullRequest_3D8CP9\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", + "metadata": {} } }; })(); diff --git a/lib/controllers/__generated__/prTimelineController_pullRequest.graphql.js b/lib/controllers/__generated__/prTimelineController_pullRequest.graphql.js index b30a37083b..2a2488194d 100644 --- a/lib/controllers/__generated__/prTimelineController_pullRequest.graphql.js +++ b/lib/controllers/__generated__/prTimelineController_pullRequest.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; type commitCommentThreadView_item$ref = any; type commitsView_nodes$ref = any; type crossReferencedEventsView_nodes$ref = any; @@ -38,7 +38,7 @@ export type prTimelineController_pullRequest = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "prTimelineController_pullRequest", "type": "PullRequest", diff --git a/lib/items/__generated__/issueishTooltipItemQuery.graphql.js b/lib/items/__generated__/issueishTooltipItemQuery.graphql.js index e72d52912c..7471d4cb07 100644 --- a/lib/items/__generated__/issueishTooltipItemQuery.graphql.js +++ b/lib/items/__generated__/issueishTooltipItemQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash ec7add21f4125e294e4679a0fed3dfc9 + * @relayHash 2af853c01640ff29fc45ef2a08b60e21 */ /* eslint-disable */ @@ -172,12 +172,12 @@ v5 = [ "concreteType": null, "plural": false, "selections": [ - v2, - v4, - v3 + (v2/*: any*/), + (v4/*: any*/), + (v3/*: any*/) ] }, - v3 + (v3/*: any*/) ] }, { @@ -189,8 +189,8 @@ v5 = [ "concreteType": null, "plural": false, "selections": [ - v2, - v4, + (v2/*: any*/), + (v4/*: any*/), { "kind": "ScalarField", "alias": null, @@ -198,30 +198,25 @@ v5 = [ "args": null, "storageKey": null }, - v3 + (v3/*: any*/) ] } ]; return { "kind": "Request", - "operationKind": "query", - "name": "issueishTooltipItemQuery", - "id": null, - "text": "query issueishTooltipItemQuery(\n $issueishUrl: URI!\n) {\n resource(url: $issueishUrl) {\n __typename\n ...issueishTooltipContainer_resource\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishTooltipContainer_resource on UniformResourceLocatable {\n __typename\n ... on Issue {\n state\n number\n title\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n }\n ... on PullRequest {\n state\n number\n title\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n }\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "issueishTooltipItemQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "resource", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -237,32 +232,39 @@ return { "operation": { "kind": "Operation", "name": "issueishTooltipItemQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "resource", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ - v2, - v3, + (v2/*: any*/), + (v3/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", - "selections": v5 + "selections": (v5/*: any*/) }, { "kind": "InlineFragment", "type": "Issue", - "selections": v5 + "selections": (v5/*: any*/) } ] } ] + }, + "params": { + "operationKind": "query", + "name": "issueishTooltipItemQuery", + "id": null, + "text": "query issueishTooltipItemQuery(\n $issueishUrl: URI!\n) {\n resource(url: $issueishUrl) {\n __typename\n ...issueishTooltipContainer_resource\n ... on Node {\n id\n }\n }\n}\n\nfragment issueishTooltipContainer_resource on UniformResourceLocatable {\n __typename\n ... on Issue {\n state\n number\n title\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n }\n ... on PullRequest {\n state\n number\n title\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n }\n}\n", + "metadata": {} } }; })(); diff --git a/lib/items/__generated__/userMentionTooltipItemQuery.graphql.js b/lib/items/__generated__/userMentionTooltipItemQuery.graphql.js index 85f27f9e43..3bd8491f4c 100644 --- a/lib/items/__generated__/userMentionTooltipItemQuery.graphql.js +++ b/lib/items/__generated__/userMentionTooltipItemQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 618ef28f16a644f2aa8240535a6b5ea4 + * @relayHash cbae41158b2bedaa2322e49d0f1da45d */ /* eslint-disable */ @@ -81,24 +81,19 @@ v2 = [ ]; return { "kind": "Request", - "operationKind": "query", - "name": "userMentionTooltipItemQuery", - "id": null, - "text": "query userMentionTooltipItemQuery(\n $username: String!\n) {\n repositoryOwner(login: $username) {\n __typename\n ...userMentionTooltipContainer_repositoryOwner\n id\n }\n}\n\nfragment userMentionTooltipContainer_repositoryOwner on RepositoryOwner {\n login\n avatarUrl\n repositories {\n totalCount\n }\n ... on User {\n company\n }\n ... on Organization {\n members {\n totalCount\n }\n }\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "userMentionTooltipItemQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "repositoryOwner", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -114,14 +109,14 @@ return { "operation": { "kind": "Operation", "name": "userMentionTooltipItemQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "repositoryOwner", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -154,7 +149,7 @@ return { "args": null, "concreteType": "RepositoryConnection", "plural": false, - "selections": v2 + "selections": (v2/*: any*/) }, { "kind": "ScalarField", @@ -175,7 +170,7 @@ return { "args": null, "concreteType": "UserConnection", "plural": false, - "selections": v2 + "selections": (v2/*: any*/) } ] }, @@ -195,6 +190,13 @@ return { ] } ] + }, + "params": { + "operationKind": "query", + "name": "userMentionTooltipItemQuery", + "id": null, + "text": "query userMentionTooltipItemQuery(\n $username: String!\n) {\n repositoryOwner(login: $username) {\n __typename\n ...userMentionTooltipContainer_repositoryOwner\n id\n }\n}\n\nfragment userMentionTooltipContainer_repositoryOwner on RepositoryOwner {\n login\n avatarUrl\n repositories {\n totalCount\n }\n ... on User {\n company\n }\n ... on Organization {\n members {\n totalCount\n }\n }\n}\n", + "metadata": {} } }; })(); diff --git a/lib/views/__generated__/issueDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/issueDetailViewRefetchQuery.graphql.js index dfb9d262df..861efb7789 100644 --- a/lib/views/__generated__/issueDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/issueDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 0de8f3b80a7115e2fb90301e39c4591d + * @relayHash 52b4d4eae123e9624bea3c36531049e8 */ /* eslint-disable */ @@ -332,9 +332,9 @@ v8 = { "concreteType": null, "plural": false, "selections": [ - v4, - v7, - v5 + (v4/*: any*/), + (v7/*: any*/), + (v5/*: any*/) ] }, v9 = { @@ -373,7 +373,7 @@ v13 = { "storageKey": null }, v14 = [ - v13 + (v13/*: any*/) ], v15 = [ { @@ -398,37 +398,32 @@ v16 = { "concreteType": "User", "plural": false, "selections": [ - v7, - v5 + (v7/*: any*/), + (v5/*: any*/) ] }; return { "kind": "Request", - "operationKind": "query", - "name": "issueDetailViewRefetchQuery", - "id": null, - "text": "query issueDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueDetailView_repository_3D8CP9\n id\n }\n issue: node(id: $issueishId) {\n __typename\n ...issueDetailView_issue_3D8CP9\n id\n }\n}\n\nfragment issueDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_3D8CP9 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "issueDetailViewRefetchQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": "repository", "name": "node", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ { "kind": "FragmentSpread", "name": "issueDetailView_repository", - "args": v2 + "args": (v2/*: any*/) } ] }, @@ -437,14 +432,14 @@ return { "alias": "issue", "name": "node", "storageKey": null, - "args": v3, + "args": (v3/*: any*/), "concreteType": null, "plural": false, "selections": [ { "kind": "FragmentSpread", "name": "issueDetailView_issue", - "args": v2 + "args": (v2/*: any*/) } ] } @@ -453,25 +448,25 @@ return { "operation": { "kind": "Operation", "name": "issueDetailViewRefetchQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": "repository", "name": "node", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ - v4, - v5, + (v4/*: any*/), + (v5/*: any*/), { "kind": "InlineFragment", "type": "Repository", "selections": [ - v6, - v8 + (v6/*: any*/), + (v8/*: any*/) ] } ] @@ -481,17 +476,17 @@ return { "alias": "issue", "name": "node", "storageKey": null, - "args": v3, + "args": (v3/*: any*/), "concreteType": null, "plural": false, "selections": [ - v4, - v5, + (v4/*: any*/), + (v5/*: any*/), { "kind": "InlineFragment", "type": "Issue", "selections": [ - v4, + (v4/*: any*/), { "kind": "ScalarField", "alias": null, @@ -499,9 +494,9 @@ return { "args": null, "storageKey": null }, - v9, - v10, - v11, + (v9/*: any*/), + (v10/*: any*/), + (v11/*: any*/), { "kind": "LinkedField", "alias": null, @@ -511,29 +506,29 @@ return { "concreteType": null, "plural": false, "selections": [ - v4, - v7, - v12, - v5, + (v4/*: any*/), + (v7/*: any*/), + (v12/*: any*/), + (v5/*: any*/), { "kind": "InlineFragment", "type": "Bot", - "selections": v14 + "selections": (v14/*: any*/) }, { "kind": "InlineFragment", "type": "User", - "selections": v14 + "selections": (v14/*: any*/) } ] }, - v13, + (v13/*: any*/), { "kind": "LinkedField", "alias": null, "name": "timeline", "storageKey": null, - "args": v15, + "args": (v15/*: any*/), "concreteType": "IssueTimelineConnection", "plural": false, "selections": [ @@ -587,8 +582,8 @@ return { "concreteType": null, "plural": false, "selections": [ - v4, - v5, + (v4/*: any*/), + (v5/*: any*/), { "kind": "InlineFragment", "type": "CrossReferencedEvent", @@ -616,10 +611,10 @@ return { "concreteType": null, "plural": false, "selections": [ - v4, - v7, - v12, - v5 + (v4/*: any*/), + (v7/*: any*/), + (v12/*: any*/), + (v5/*: any*/) ] }, { @@ -631,7 +626,7 @@ return { "concreteType": null, "plural": false, "selections": [ - v4, + (v4/*: any*/), { "kind": "LinkedField", "alias": null, @@ -641,9 +636,9 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v6, - v8, - v5, + (v6/*: any*/), + (v8/*: any*/), + (v5/*: any*/), { "kind": "ScalarField", "alias": null, @@ -653,14 +648,14 @@ return { } ] }, - v5, + (v5/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v9, - v10, - v13, + (v9/*: any*/), + (v10/*: any*/), + (v13/*: any*/), { "kind": "ScalarField", "alias": "prState", @@ -674,9 +669,9 @@ return { "kind": "InlineFragment", "type": "Issue", "selections": [ - v9, - v10, - v13, + (v9/*: any*/), + (v10/*: any*/), + (v13/*: any*/), { "kind": "ScalarField", "alias": "issueState", @@ -703,13 +698,13 @@ return { "concreteType": null, "plural": false, "selections": [ - v4, - v12, - v7, - v5 + (v4/*: any*/), + (v12/*: any*/), + (v7/*: any*/), + (v5/*: any*/) ] }, - v11, + (v11/*: any*/), { "kind": "ScalarField", "alias": null, @@ -717,7 +712,7 @@ return { "args": null, "storageKey": null }, - v13 + (v13/*: any*/) ] }, { @@ -733,9 +728,9 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v6, - v16, - v12 + (v6/*: any*/), + (v16/*: any*/), + (v12/*: any*/) ] }, { @@ -747,9 +742,9 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v6, - v12, - v16 + (v6/*: any*/), + (v12/*: any*/), + (v16/*: any*/) ] }, { @@ -799,7 +794,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v15, + "args": (v15/*: any*/), "handle": "connection", "key": "IssueTimelineController_timeline", "filters": null @@ -845,6 +840,13 @@ return { ] } ] + }, + "params": { + "operationKind": "query", + "name": "issueDetailViewRefetchQuery", + "id": null, + "text": "query issueDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...issueDetailView_repository_3D8CP9\n id\n }\n issue: node(id: $issueishId) {\n __typename\n ...issueDetailView_issue_3D8CP9\n id\n }\n}\n\nfragment issueDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment issueDetailView_issue_3D8CP9 on Issue {\n __typename\n ... on Node {\n id\n }\n state\n number\n title\n bodyHTML\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...issueTimelineController_issue_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment issueTimelineController_issue_3D8CP9 on Issue {\n url\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n", + "metadata": {} } }; })(); diff --git a/lib/views/__generated__/issueDetailView_issue.graphql.js b/lib/views/__generated__/issueDetailView_issue.graphql.js index 3ccf457baf..8eabadcabd 100644 --- a/lib/views/__generated__/issueDetailView_issue.graphql.js +++ b/lib/views/__generated__/issueDetailView_issue.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; type issueTimelineController_issue$ref = any; export type IssueState = "CLOSED" | "OPEN" | "%future added value"; export type ReactionContent = "CONFUSED" | "HEART" | "HOORAY" | "LAUGH" | "THUMBS_DOWN" | "THUMBS_UP" | "%future added value"; @@ -38,7 +38,7 @@ export type issueDetailView_issue = {| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = { "kind": "ScalarField", "alias": null, @@ -47,7 +47,7 @@ var v0 = { "storageKey": null }, v1 = [ - v0 + (v0/*: any*/) ]; return { "kind": "Fragment", @@ -137,12 +137,12 @@ return { { "kind": "InlineFragment", "type": "Bot", - "selections": v1 + "selections": (v1/*: any*/) }, { "kind": "InlineFragment", "type": "User", - "selections": v1 + "selections": (v1/*: any*/) } ] }, @@ -164,7 +164,7 @@ return { } ] }, - v0, + (v0/*: any*/), { "kind": "LinkedField", "alias": null, diff --git a/lib/views/__generated__/issueDetailView_repository.graphql.js b/lib/views/__generated__/issueDetailView_repository.graphql.js index efd212d10c..0c843ff1cc 100644 --- a/lib/views/__generated__/issueDetailView_repository.graphql.js +++ b/lib/views/__generated__/issueDetailView_repository.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; declare export opaque type issueDetailView_repository$ref: FragmentReference; export type issueDetailView_repository = {| @@ -21,7 +21,7 @@ export type issueDetailView_repository = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "issueDetailView_repository", "type": "Repository", diff --git a/lib/views/__generated__/prCommitView_item.graphql.js b/lib/views/__generated__/prCommitView_item.graphql.js index 2d1203207c..230bdcd7da 100644 --- a/lib/views/__generated__/prCommitView_item.graphql.js +++ b/lib/views/__generated__/prCommitView_item.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; declare export opaque type prCommitView_item$ref: FragmentReference; export type prCommitView_item = {| @@ -26,7 +26,7 @@ export type prCommitView_item = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "prCommitView_item", "type": "Commit", diff --git a/lib/views/__generated__/prCommitsViewQuery.graphql.js b/lib/views/__generated__/prCommitsViewQuery.graphql.js index 7d20b34ac5..826920ceb9 100644 --- a/lib/views/__generated__/prCommitsViewQuery.graphql.js +++ b/lib/views/__generated__/prCommitsViewQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 86632ba0fe5f43bd343d798b397ad81b + * @relayHash f553e531257d2b674f00b3d93a7740b0 */ /* eslint-disable */ @@ -145,24 +145,19 @@ v5 = [ ]; return { "kind": "Request", - "operationKind": "query", - "name": "prCommitsViewQuery", - "id": null, - "text": "query prCommitsViewQuery(\n $commitCount: Int!\n $commitCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prCommitsView_pullRequest_38TpXw\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "prCommitsViewQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "resource", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -197,30 +192,30 @@ return { "operation": { "kind": "Operation", "name": "prCommitsViewQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "resource", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ - v2, - v3, + (v2/*: any*/), + (v3/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v4, + (v4/*: any*/), { "kind": "LinkedField", "alias": null, "name": "commits", "storageKey": null, - "args": v5, + "args": (v5/*: any*/), "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ @@ -283,7 +278,7 @@ return { "concreteType": "Commit", "plural": false, "selections": [ - v3, + (v3/*: any*/), { "kind": "LinkedField", "alias": null, @@ -344,11 +339,11 @@ return { "args": null, "storageKey": null }, - v4 + (v4/*: any*/) ] }, - v3, - v2 + (v3/*: any*/), + (v2/*: any*/) ] } ] @@ -359,7 +354,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v5, + "args": (v5/*: any*/), "handle": "connection", "key": "prCommitsView_commits", "filters": null @@ -369,6 +364,13 @@ return { ] } ] + }, + "params": { + "operationKind": "query", + "name": "prCommitsViewQuery", + "id": null, + "text": "query prCommitsViewQuery(\n $commitCount: Int!\n $commitCursor: String\n $url: URI!\n) {\n resource(url: $url) {\n __typename\n ... on PullRequest {\n ...prCommitsView_pullRequest_38TpXw\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n", + "metadata": {} } }; })(); diff --git a/lib/views/__generated__/prCommitsView_pullRequest.graphql.js b/lib/views/__generated__/prCommitsView_pullRequest.graphql.js index 8fb99fb788..de0b9fb9cb 100644 --- a/lib/views/__generated__/prCommitsView_pullRequest.graphql.js +++ b/lib/views/__generated__/prCommitsView_pullRequest.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; type prCommitView_item$ref = any; import type { FragmentReference } from "relay-runtime"; declare export opaque type prCommitsView_pullRequest$ref: FragmentReference; @@ -33,7 +33,7 @@ export type prCommitsView_pullRequest = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "prCommitsView_pullRequest", "type": "PullRequest", diff --git a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js index 42e336a55a..4d45a80559 100644 --- a/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prDetailViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash c9c759b66c17ed333ce2946f8675ee19 + * @relayHash 7b0866b16d5c49faece538eda674deed */ /* eslint-disable */ @@ -610,9 +610,9 @@ v8 = { "storageKey": null }, v9 = [ - v5, - v8, - v6 + (v5/*: any*/), + (v8/*: any*/), + (v6/*: any*/) ], v10 = { "kind": "LinkedField", @@ -622,7 +622,7 @@ v10 = { "args": null, "concreteType": null, "plural": false, - "selections": v9 + "selections": (v9/*: any*/) }, v11 = { "kind": "ScalarField", @@ -682,8 +682,8 @@ v17 = { "concreteType": "PageInfo", "plural": false, "selections": [ - v15, - v16 + (v15/*: any*/), + (v16/*: any*/) ] }, v18 = { @@ -701,7 +701,7 @@ v19 = [ "args": null, "storageKey": null }, - v6 + (v6/*: any*/) ], v20 = { "kind": "ScalarField", @@ -732,10 +732,10 @@ v22 = [ } ], v23 = [ - v5, - v21, - v8, - v6 + (v5/*: any*/), + (v21/*: any*/), + (v8/*: any*/), + (v6/*: any*/) ], v24 = { "kind": "LinkedField", @@ -745,7 +745,7 @@ v24 = { "args": null, "concreteType": null, "plural": false, - "selections": v23 + "selections": (v23/*: any*/) }, v25 = { "kind": "ScalarField", @@ -798,8 +798,8 @@ v30 = { "concreteType": "PageInfo", "plural": false, "selections": [ - v16, - v15 + (v16/*: any*/), + (v15/*: any*/) ] }, v31 = { @@ -826,7 +826,7 @@ v33 = { "storageKey": null }, v34 = [ - v13 + (v13/*: any*/) ], v35 = [ { @@ -843,10 +843,10 @@ v35 = [ } ], v36 = [ - v5, - v8, - v21, - v6 + (v5/*: any*/), + (v8/*: any*/), + (v21/*: any*/), + (v6/*: any*/) ], v37 = { "kind": "LinkedField", @@ -856,7 +856,7 @@ v37 = { "args": null, "concreteType": "Commit", "plural": false, - "selections": v19 + "selections": (v19/*: any*/) }, v38 = { "kind": "LinkedField", @@ -866,7 +866,7 @@ v38 = { "args": null, "concreteType": null, "plural": false, - "selections": v23 + "selections": (v23/*: any*/) }, v39 = { "kind": "LinkedField", @@ -877,30 +877,25 @@ v39 = { "concreteType": "User", "plural": false, "selections": [ - v8, - v6 + (v8/*: any*/), + (v6/*: any*/) ] }; return { "kind": "Request", - "operationKind": "query", - "name": "prDetailViewRefetchQuery", - "id": null, - "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "prDetailViewRefetchQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": "repository", "name": "node", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -908,8 +903,8 @@ return { "kind": "FragmentSpread", "name": "prDetailView_repository", "args": [ - v2, - v3 + (v2/*: any*/), + (v3/*: any*/) ] } ] @@ -919,7 +914,7 @@ return { "alias": "pullRequest", "name": "node", "storageKey": null, - "args": v4, + "args": (v4/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -963,8 +958,8 @@ return { "variableName": "reviewCursor", "type": null }, - v2, - v3 + (v2/*: any*/), + (v3/*: any*/) ] } ] @@ -974,25 +969,25 @@ return { "operation": { "kind": "Operation", "name": "prDetailViewRefetchQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": "repository", "name": "node", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ - v5, - v6, + (v5/*: any*/), + (v6/*: any*/), { "kind": "InlineFragment", "type": "Repository", "selections": [ - v7, - v10 + (v7/*: any*/), + (v10/*: any*/) ] } ] @@ -1002,19 +997,19 @@ return { "alias": "pullRequest", "name": "node", "storageKey": null, - "args": v4, + "args": (v4/*: any*/), "concreteType": null, "plural": false, "selections": [ - v5, - v6, + (v5/*: any*/), + (v6/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v11, - v5, - v12, + (v11/*: any*/), + (v5/*: any*/), + (v12/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1022,17 +1017,17 @@ return { "args": null, "storageKey": null }, - v13, + (v13/*: any*/), { "kind": "LinkedField", "alias": null, "name": "reviews", "storageKey": null, - "args": v14, + "args": (v14/*: any*/), "concreteType": "PullRequestReviewConnection", "plural": false, "selections": [ - v17, + (v17/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1042,7 +1037,7 @@ return { "concreteType": "PullRequestReviewEdge", "plural": true, "selections": [ - v18, + (v18/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1052,7 +1047,7 @@ return { "concreteType": "PullRequestReview", "plural": false, "selections": [ - v6, + (v6/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1068,9 +1063,9 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v19 + "selections": (v19/*: any*/) }, - v20, + (v20/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1086,7 +1081,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v9 + "selections": (v9/*: any*/) }, { "kind": "LinkedField", @@ -1097,9 +1092,9 @@ return { "concreteType": null, "plural": false, "selections": [ - v5, - v21, - v6 + (v5/*: any*/), + (v21/*: any*/), + (v6/*: any*/) ] }, { @@ -1107,11 +1102,11 @@ return { "alias": null, "name": "comments", "storageKey": null, - "args": v22, + "args": (v22/*: any*/), "concreteType": "PullRequestReviewCommentConnection", "plural": false, "selections": [ - v17, + (v17/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1121,7 +1116,7 @@ return { "concreteType": "PullRequestReviewCommentEdge", "plural": true, "selections": [ - v18, + (v18/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1131,9 +1126,9 @@ return { "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v6, - v24, - v25, + (v6/*: any*/), + (v24/*: any*/), + (v25/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1141,8 +1136,8 @@ return { "args": null, "storageKey": null }, - v26, - v27, + (v26/*: any*/), + (v27/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1152,12 +1147,12 @@ return { "concreteType": "PullRequestReviewComment", "plural": false, "selections": [ - v6 + (v6/*: any*/) ] }, - v28, - v13, - v5 + (v28/*: any*/), + (v13/*: any*/), + (v5/*: any*/) ] } ] @@ -1168,12 +1163,12 @@ return { "kind": "LinkedHandle", "alias": null, "name": "comments", - "args": v22, + "args": (v22/*: any*/), "handle": "connection", "key": "PrReviewCommentsContainer_comments", "filters": null }, - v5 + (v5/*: any*/) ] } ] @@ -1184,7 +1179,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "reviews", - "args": v14, + "args": (v14/*: any*/), "handle": "connection", "key": "PrReviewsContainer_reviews", "filters": null @@ -1194,11 +1189,11 @@ return { "alias": null, "name": "commits", "storageKey": null, - "args": v29, + "args": (v29/*: any*/), "concreteType": "PullRequestCommitConnection", "plural": false, "selections": [ - v30, + (v30/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1208,7 +1203,7 @@ return { "concreteType": "PullRequestCommitEdge", "plural": true, "selections": [ - v18, + (v18/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1227,7 +1222,7 @@ return { "concreteType": "Commit", "plural": false, "selections": [ - v6, + (v6/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1237,8 +1232,8 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v21, - v7, + (v21/*: any*/), + (v7/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1269,12 +1264,12 @@ return { "args": null, "storageKey": null }, - v31, - v13 + (v31/*: any*/), + (v13/*: any*/) ] }, - v6, - v5 + (v6/*: any*/), + (v5/*: any*/) ] } ] @@ -1285,7 +1280,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "commits", - "args": v29, + "args": (v29/*: any*/), "handle": "connection", "key": "prCommitsView_commits", "filters": null @@ -1298,7 +1293,7 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v32 + "selections": (v32/*: any*/) }, { "kind": "LinkedField", @@ -1352,7 +1347,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v20, + (v20/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1362,8 +1357,8 @@ return { "concreteType": "StatusContext", "plural": true, "selections": [ - v6, - v20, + (v6/*: any*/), + (v20/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1387,22 +1382,22 @@ return { } ] }, - v6 + (v6/*: any*/) ] }, - v6 + (v6/*: any*/) ] }, - v6 + (v6/*: any*/) ] } ] } ] }, - v20, - v33, - v25, + (v20/*: any*/), + (v33/*: any*/), + (v25/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1426,19 +1421,19 @@ return { "concreteType": null, "plural": false, "selections": [ - v5, - v8, - v21, - v6, + (v5/*: any*/), + (v8/*: any*/), + (v21/*: any*/), + (v6/*: any*/), { "kind": "InlineFragment", "type": "Bot", - "selections": v34 + "selections": (v34/*: any*/) }, { "kind": "InlineFragment", "type": "User", - "selections": v34 + "selections": (v34/*: any*/) } ] }, @@ -1450,7 +1445,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v9 + "selections": (v9/*: any*/) }, { "kind": "LinkedField", @@ -1461,8 +1456,8 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v10, - v6 + (v10/*: any*/), + (v6/*: any*/) ] }, { @@ -1470,11 +1465,11 @@ return { "alias": null, "name": "timeline", "storageKey": null, - "args": v35, + "args": (v35/*: any*/), "concreteType": "PullRequestTimelineConnection", "plural": false, "selections": [ - v30, + (v30/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1484,7 +1479,7 @@ return { "concreteType": "PullRequestTimelineItemEdge", "plural": true, "selections": [ - v18, + (v18/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1494,8 +1489,8 @@ return { "concreteType": null, "plural": false, "selections": [ - v5, - v6, + (v5/*: any*/), + (v6/*: any*/), { "kind": "InlineFragment", "type": "CrossReferencedEvent", @@ -1507,7 +1502,7 @@ return { "args": null, "storageKey": null }, - v12, + (v12/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1516,7 +1511,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v36 + "selections": (v36/*: any*/) }, { "kind": "LinkedField", @@ -1527,7 +1522,7 @@ return { "concreteType": null, "plural": false, "selections": [ - v5, + (v5/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1537,9 +1532,9 @@ return { "concreteType": "Repository", "plural": false, "selections": [ - v7, - v10, - v6, + (v7/*: any*/), + (v10/*: any*/), + (v6/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1549,14 +1544,14 @@ return { } ] }, - v6, + (v6/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v11, - v33, - v13, + (v11/*: any*/), + (v33/*: any*/), + (v13/*: any*/), { "kind": "ScalarField", "alias": "prState", @@ -1570,9 +1565,9 @@ return { "kind": "InlineFragment", "type": "Issue", "selections": [ - v11, - v33, - v13, + (v11/*: any*/), + (v33/*: any*/), + (v13/*: any*/), { "kind": "ScalarField", "alias": "issueState", @@ -1590,7 +1585,7 @@ return { "kind": "InlineFragment", "type": "CommitCommentThread", "selections": [ - v37, + (v37/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1625,7 +1620,7 @@ return { "concreteType": "CommitComment", "plural": false, "selections": [ - v6, + (v6/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1634,13 +1629,13 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v36 + "selections": (v36/*: any*/) }, - v37, - v25, - v28, - v26, - v27 + (v37/*: any*/), + (v25/*: any*/), + (v28/*: any*/), + (v26/*: any*/), + (v27/*: any*/) ] } ] @@ -1653,7 +1648,7 @@ return { "kind": "InlineFragment", "type": "HeadRefForcePushedEvent", "selections": [ - v38, + (v38/*: any*/), { "kind": "LinkedField", "alias": null, @@ -1662,7 +1657,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v19 + "selections": (v19/*: any*/) }, { "kind": "LinkedField", @@ -1672,17 +1667,17 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v19 + "selections": (v19/*: any*/) }, - v28 + (v28/*: any*/) ] }, { "kind": "InlineFragment", "type": "MergedEvent", "selections": [ - v38, - v37, + (v38/*: any*/), + (v37/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1690,17 +1685,17 @@ return { "args": null, "storageKey": null }, - v28 + (v28/*: any*/) ] }, { "kind": "InlineFragment", "type": "IssueComment", "selections": [ - v24, - v25, - v28, - v13 + (v24/*: any*/), + (v25/*: any*/), + (v28/*: any*/), + (v13/*: any*/) ] }, { @@ -1716,9 +1711,9 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v7, - v39, - v21 + (v7/*: any*/), + (v39/*: any*/), + (v21/*: any*/) ] }, { @@ -1730,9 +1725,9 @@ return { "concreteType": "GitActor", "plural": false, "selections": [ - v7, - v21, - v39 + (v7/*: any*/), + (v21/*: any*/), + (v39/*: any*/) ] }, { @@ -1742,7 +1737,7 @@ return { "args": null, "storageKey": null }, - v31, + (v31/*: any*/), { "kind": "ScalarField", "alias": null, @@ -1776,7 +1771,7 @@ return { "kind": "LinkedHandle", "alias": null, "name": "timeline", - "args": v35, + "args": (v35/*: any*/), "handle": "connection", "key": "prTimelineContainer_timeline", "filters": null @@ -1805,7 +1800,7 @@ return { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v32 + "selections": (v32/*: any*/) } ] } @@ -1814,6 +1809,13 @@ return { ] } ] + }, + "params": { + "operationKind": "query", + "name": "prDetailViewRefetchQuery", + "id": null, + "text": "query prDetailViewRefetchQuery(\n $repoId: ID!\n $issueishId: ID!\n $timelineCount: Int!\n $timelineCursor: String\n $commitCount: Int!\n $commitCursor: String\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository: node(id: $repoId) {\n __typename\n ...prDetailView_repository_3D8CP9\n id\n }\n pullRequest: node(id: $issueishId) {\n __typename\n ...prDetailView_pullRequest_2qM2KL\n id\n }\n}\n\nfragment prDetailView_repository_3D8CP9 on Repository {\n id\n name\n owner {\n __typename\n login\n id\n }\n}\n\nfragment prDetailView_pullRequest_2qM2KL on PullRequest {\n __typename\n ... on Node {\n id\n }\n isCrossRepository\n changedFiles\n ...prReviewsContainer_pullRequest_y4qc0\n ...prCommitsView_pullRequest_38TpXw\n countedCommits: commits {\n totalCount\n }\n ...prStatusesView_pullRequest\n state\n number\n title\n bodyHTML\n baseRefName\n headRefName\n author {\n __typename\n login\n avatarUrl\n ... on User {\n url\n }\n ... on Bot {\n url\n }\n ... on Node {\n id\n }\n }\n ...prTimelineController_pullRequest_3D8CP9\n ... on UniformResourceLocatable {\n url\n }\n ... on Reactable {\n reactionGroups {\n content\n users {\n totalCount\n }\n }\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prCommitsView_pullRequest_38TpXw on PullRequest {\n url\n commits(first: $commitCount, after: $commitCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n commit {\n id\n ...prCommitView_item\n }\n id\n __typename\n }\n }\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prTimelineController_pullRequest_3D8CP9 on PullRequest {\n url\n ...headRefForcePushedEventView_issueish\n timeline(first: $timelineCount, after: $timelineCursor) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n __typename\n ...commitsView_nodes\n ...issueCommentView_item\n ...mergedEventView_item\n ...headRefForcePushedEventView_item\n ...commitCommentThreadView_item\n ...crossReferencedEventsView_nodes\n ... on Node {\n id\n }\n }\n }\n }\n}\n\nfragment headRefForcePushedEventView_issueish on PullRequest {\n headRefName\n headRepositoryOwner {\n __typename\n login\n id\n }\n repository {\n owner {\n __typename\n login\n id\n }\n id\n }\n}\n\nfragment commitsView_nodes on Commit {\n id\n author {\n name\n user {\n login\n id\n }\n }\n ...commitView_commit\n}\n\nfragment issueCommentView_item on IssueComment {\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n createdAt\n url\n}\n\nfragment mergedEventView_item on MergedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n mergeRefName\n createdAt\n}\n\nfragment headRefForcePushedEventView_item on HeadRefForcePushedEvent {\n actor {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n beforeCommit {\n oid\n id\n }\n afterCommit {\n oid\n id\n }\n createdAt\n}\n\nfragment commitCommentThreadView_item on CommitCommentThread {\n commit {\n oid\n id\n }\n comments(first: 100) {\n edges {\n node {\n id\n ...commitCommentView_item\n }\n }\n }\n}\n\nfragment crossReferencedEventsView_nodes on CrossReferencedEvent {\n id\n referencedAt\n isCrossRepository\n actor {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n source {\n __typename\n ... on RepositoryNode {\n repository {\n name\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n ...crossReferencedEventView_item\n}\n\nfragment crossReferencedEventView_item on CrossReferencedEvent {\n id\n isCrossRepository\n source {\n __typename\n ... on Issue {\n number\n title\n url\n issueState: state\n }\n ... on PullRequest {\n number\n title\n url\n prState: state\n }\n ... on RepositoryNode {\n repository {\n name\n isPrivate\n owner {\n __typename\n login\n id\n }\n id\n }\n }\n ... on Node {\n id\n }\n }\n}\n\nfragment commitCommentView_item on CommitComment {\n author {\n __typename\n login\n avatarUrl\n ... on Node {\n id\n }\n }\n commit {\n oid\n id\n }\n bodyHTML\n createdAt\n path\n position\n}\n\nfragment commitView_commit on Commit {\n author {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n committer {\n name\n avatarUrl\n user {\n login\n id\n }\n }\n authoredByCommitter\n sha: oid\n message\n messageHeadlineHTML\n commitUrl\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n\nfragment prCommitView_item on Commit {\n committer {\n avatarUrl\n name\n date\n }\n messageHeadline\n messageBody\n shortSha: abbreviatedOid\n sha: oid\n url\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", + "metadata": {} } }; })(); diff --git a/lib/views/__generated__/prDetailView_pullRequest.graphql.js b/lib/views/__generated__/prDetailView_pullRequest.graphql.js index 399ae2333d..ff7516fd2a 100644 --- a/lib/views/__generated__/prDetailView_pullRequest.graphql.js +++ b/lib/views/__generated__/prDetailView_pullRequest.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; type prCommitsView_pullRequest$ref = any; type prReviewsContainer_pullRequest$ref = any; type prStatusesView_pullRequest$ref = any; @@ -48,7 +48,7 @@ export type prDetailView_pullRequest = {| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = [ { "kind": "ScalarField", @@ -66,7 +66,7 @@ v1 = { "storageKey": null }, v2 = [ - v1 + (v1/*: any*/) ]; return { "kind": "Fragment", @@ -208,7 +208,7 @@ return { "args": null, "concreteType": "PullRequestCommitConnection", "plural": false, - "selections": v0 + "selections": (v0/*: any*/) }, { "kind": "FragmentSpread", @@ -283,12 +283,12 @@ return { { "kind": "InlineFragment", "type": "Bot", - "selections": v2 + "selections": (v2/*: any*/) }, { "kind": "InlineFragment", "type": "User", - "selections": v2 + "selections": (v2/*: any*/) } ] }, @@ -310,7 +310,7 @@ return { } ] }, - v1, + (v1/*: any*/), { "kind": "LinkedField", "alias": null, @@ -335,7 +335,7 @@ return { "args": null, "concreteType": "ReactingUserConnection", "plural": false, - "selections": v0 + "selections": (v0/*: any*/) } ] } diff --git a/lib/views/__generated__/prDetailView_repository.graphql.js b/lib/views/__generated__/prDetailView_repository.graphql.js index 22a7c77d8b..69e6a95e8f 100644 --- a/lib/views/__generated__/prDetailView_repository.graphql.js +++ b/lib/views/__generated__/prDetailView_repository.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; declare export opaque type prDetailView_repository$ref: FragmentReference; export type prDetailView_repository = {| @@ -21,7 +21,7 @@ export type prDetailView_repository = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "prDetailView_repository", "type": "Repository", diff --git a/lib/views/__generated__/prStatusContextView_context.graphql.js b/lib/views/__generated__/prStatusContextView_context.graphql.js index c85134d3fa..0172100a92 100644 --- a/lib/views/__generated__/prStatusContextView_context.graphql.js +++ b/lib/views/__generated__/prStatusContextView_context.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; export type StatusState = "ERROR" | "EXPECTED" | "FAILURE" | "PENDING" | "SUCCESS" | "%future added value"; import type { FragmentReference } from "relay-runtime"; declare export opaque type prStatusContextView_context$ref: FragmentReference; @@ -21,7 +21,7 @@ export type prStatusContextView_context = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "prStatusContextView_context", "type": "StatusContext", diff --git a/lib/views/__generated__/prStatusesViewRefetchQuery.graphql.js b/lib/views/__generated__/prStatusesViewRefetchQuery.graphql.js index ae88ff6cba..0e759b9585 100644 --- a/lib/views/__generated__/prStatusesViewRefetchQuery.graphql.js +++ b/lib/views/__generated__/prStatusesViewRefetchQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash b2e4fb850c19404c7973310ca0813874 + * @relayHash 88ba0c5c281db6e27a193a18c597e5a3 */ /* eslint-disable */ @@ -102,24 +102,19 @@ v3 = { }; return { "kind": "Request", - "operationKind": "query", - "name": "prStatusesViewRefetchQuery", - "id": null, - "text": "query prStatusesViewRefetchQuery(\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequest {\n ...prStatusesView_pullRequest\n }\n id\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", - "metadata": {}, "fragment": { "kind": "Fragment", "name": "prStatusesViewRefetchQuery", "type": "Query", "metadata": null, - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "node", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -141,14 +136,14 @@ return { "operation": { "kind": "Operation", "name": "prStatusesViewRefetchQuery", - "argumentDefinitions": v0, + "argumentDefinitions": (v0/*: any*/), "selections": [ { "kind": "LinkedField", "alias": null, "name": "node", "storageKey": null, - "args": v1, + "args": (v1/*: any*/), "concreteType": null, "plural": false, "selections": [ @@ -159,7 +154,7 @@ return { "args": null, "storageKey": null }, - v2, + (v2/*: any*/), { "kind": "InlineFragment", "type": "PullRequest", @@ -216,7 +211,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v3, + (v3/*: any*/), { "kind": "LinkedField", "alias": null, @@ -226,8 +221,8 @@ return { "concreteType": "StatusContext", "plural": true, "selections": [ - v2, - v3, + (v2/*: any*/), + (v3/*: any*/), { "kind": "ScalarField", "alias": null, @@ -251,13 +246,13 @@ return { } ] }, - v2 + (v2/*: any*/) ] }, - v2 + (v2/*: any*/) ] }, - v2 + (v2/*: any*/) ] } ] @@ -269,6 +264,13 @@ return { ] } ] + }, + "params": { + "operationKind": "query", + "name": "prStatusesViewRefetchQuery", + "id": null, + "text": "query prStatusesViewRefetchQuery(\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ... on PullRequest {\n ...prStatusesView_pullRequest\n }\n id\n }\n}\n\nfragment prStatusesView_pullRequest on PullRequest {\n id\n recentCommits: commits(last: 1) {\n edges {\n node {\n commit {\n status {\n state\n contexts {\n id\n state\n ...prStatusContextView_context\n }\n id\n }\n id\n }\n id\n }\n }\n }\n}\n\nfragment prStatusContextView_context on StatusContext {\n context\n description\n state\n targetUrl\n}\n", + "metadata": {} } }; })(); diff --git a/lib/views/__generated__/prStatusesView_pullRequest.graphql.js b/lib/views/__generated__/prStatusesView_pullRequest.graphql.js index 558e786d20..3e87d14c42 100644 --- a/lib/views/__generated__/prStatusesView_pullRequest.graphql.js +++ b/lib/views/__generated__/prStatusesView_pullRequest.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; type prStatusContextView_context$ref = any; export type StatusState = "ERROR" | "EXPECTED" | "FAILURE" | "PENDING" | "SUCCESS" | "%future added value"; import type { FragmentReference } from "relay-runtime"; @@ -35,7 +35,7 @@ export type prStatusesView_pullRequest = {| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = { "kind": "ScalarField", "alias": null, @@ -57,7 +57,7 @@ return { "metadata": null, "argumentDefinitions": [], "selections": [ - v0, + (v0/*: any*/), { "kind": "LinkedField", "alias": "recentCommits", @@ -110,7 +110,7 @@ return { "concreteType": "Status", "plural": false, "selections": [ - v1, + (v1/*: any*/), { "kind": "LinkedField", "alias": null, @@ -120,8 +120,8 @@ return { "concreteType": "StatusContext", "plural": true, "selections": [ - v0, - v1, + (v0/*: any*/), + (v1/*: any*/), { "kind": "FragmentSpread", "name": "prStatusContextView_context", diff --git a/lib/views/timeline-items/__generated__/commitCommentThreadView_item.graphql.js b/lib/views/timeline-items/__generated__/commitCommentThreadView_item.graphql.js index 608c31f35c..212eede57d 100644 --- a/lib/views/timeline-items/__generated__/commitCommentThreadView_item.graphql.js +++ b/lib/views/timeline-items/__generated__/commitCommentThreadView_item.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; type commitCommentView_item$ref = any; import type { FragmentReference } from "relay-runtime"; declare export opaque type commitCommentThreadView_item$ref: FragmentReference; @@ -28,7 +28,7 @@ export type commitCommentThreadView_item = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "commitCommentThreadView_item", "type": "CommitCommentThread", diff --git a/lib/views/timeline-items/__generated__/commitCommentView_item.graphql.js b/lib/views/timeline-items/__generated__/commitCommentView_item.graphql.js index 9d47e87acf..85b1fc53d2 100644 --- a/lib/views/timeline-items/__generated__/commitCommentView_item.graphql.js +++ b/lib/views/timeline-items/__generated__/commitCommentView_item.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; declare export opaque type commitCommentView_item$ref: FragmentReference; export type commitCommentView_item = {| @@ -27,7 +27,7 @@ export type commitCommentView_item = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "commitCommentView_item", "type": "CommitComment", diff --git a/lib/views/timeline-items/__generated__/commitView_commit.graphql.js b/lib/views/timeline-items/__generated__/commitView_commit.graphql.js index a011cb9432..236c16deec 100644 --- a/lib/views/timeline-items/__generated__/commitView_commit.graphql.js +++ b/lib/views/timeline-items/__generated__/commitView_commit.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; declare export opaque type commitView_commit$ref: FragmentReference; export type commitView_commit = {| @@ -35,7 +35,7 @@ export type commitView_commit = {| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = [ { "kind": "ScalarField", @@ -85,7 +85,7 @@ return { "args": null, "concreteType": "GitActor", "plural": false, - "selections": v0 + "selections": (v0/*: any*/) }, { "kind": "LinkedField", @@ -95,7 +95,7 @@ return { "args": null, "concreteType": "GitActor", "plural": false, - "selections": v0 + "selections": (v0/*: any*/) }, { "kind": "ScalarField", diff --git a/lib/views/timeline-items/__generated__/commitsView_nodes.graphql.js b/lib/views/timeline-items/__generated__/commitsView_nodes.graphql.js index 8b4c04b559..abc10f01d0 100644 --- a/lib/views/timeline-items/__generated__/commitsView_nodes.graphql.js +++ b/lib/views/timeline-items/__generated__/commitsView_nodes.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; type commitView_commit$ref = any; import type { FragmentReference } from "relay-runtime"; declare export opaque type commitsView_nodes$ref: FragmentReference; @@ -25,7 +25,7 @@ export type commitsView_nodes = $ReadOnlyArray<{| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "commitsView_nodes", "type": "Commit", diff --git a/lib/views/timeline-items/__generated__/crossReferencedEventView_item.graphql.js b/lib/views/timeline-items/__generated__/crossReferencedEventView_item.graphql.js index aa95dffc61..a3a3294803 100644 --- a/lib/views/timeline-items/__generated__/crossReferencedEventView_item.graphql.js +++ b/lib/views/timeline-items/__generated__/crossReferencedEventView_item.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; export type IssueState = "CLOSED" | "OPEN" | "%future added value"; export type PullRequestState = "CLOSED" | "MERGED" | "OPEN" | "%future added value"; import type { FragmentReference } from "relay-runtime"; @@ -35,7 +35,7 @@ export type crossReferencedEventView_item = {| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = { "kind": "ScalarField", "alias": null, @@ -141,9 +141,9 @@ return { "kind": "InlineFragment", "type": "PullRequest", "selections": [ - v0, - v1, - v2, + (v0/*: any*/), + (v1/*: any*/), + (v2/*: any*/), { "kind": "ScalarField", "alias": "prState", @@ -157,9 +157,9 @@ return { "kind": "InlineFragment", "type": "Issue", "selections": [ - v0, - v1, - v2, + (v0/*: any*/), + (v1/*: any*/), + (v2/*: any*/), { "kind": "ScalarField", "alias": "issueState", diff --git a/lib/views/timeline-items/__generated__/crossReferencedEventsView_nodes.graphql.js b/lib/views/timeline-items/__generated__/crossReferencedEventsView_nodes.graphql.js index de1bcffdd1..0934fe001f 100644 --- a/lib/views/timeline-items/__generated__/crossReferencedEventsView_nodes.graphql.js +++ b/lib/views/timeline-items/__generated__/crossReferencedEventsView_nodes.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; type crossReferencedEventView_item$ref = any; import type { FragmentReference } from "relay-runtime"; declare export opaque type crossReferencedEventsView_nodes$ref: FragmentReference; @@ -34,7 +34,7 @@ export type crossReferencedEventsView_nodes = $ReadOnlyArray<{| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = { "kind": "ScalarField", "alias": null, @@ -81,7 +81,7 @@ return { "concreteType": null, "plural": false, "selections": [ - v0, + (v0/*: any*/), { "kind": "ScalarField", "alias": null, @@ -132,7 +132,7 @@ return { "concreteType": null, "plural": false, "selections": [ - v0 + (v0/*: any*/) ] } ] diff --git a/lib/views/timeline-items/__generated__/headRefForcePushedEventView_issueish.graphql.js b/lib/views/timeline-items/__generated__/headRefForcePushedEventView_issueish.graphql.js index 096a04ceac..e5b5daf4ea 100644 --- a/lib/views/timeline-items/__generated__/headRefForcePushedEventView_issueish.graphql.js +++ b/lib/views/timeline-items/__generated__/headRefForcePushedEventView_issueish.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; declare export opaque type headRefForcePushedEventView_issueish$ref: FragmentReference; export type headRefForcePushedEventView_issueish = {| @@ -25,7 +25,7 @@ export type headRefForcePushedEventView_issueish = {| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = [ { "kind": "ScalarField", @@ -57,7 +57,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v0 + "selections": (v0/*: any*/) }, { "kind": "LinkedField", @@ -76,7 +76,7 @@ return { "args": null, "concreteType": null, "plural": false, - "selections": v0 + "selections": (v0/*: any*/) } ] } diff --git a/lib/views/timeline-items/__generated__/headRefForcePushedEventView_item.graphql.js b/lib/views/timeline-items/__generated__/headRefForcePushedEventView_item.graphql.js index ee92dc785c..7d6cfdfca4 100644 --- a/lib/views/timeline-items/__generated__/headRefForcePushedEventView_item.graphql.js +++ b/lib/views/timeline-items/__generated__/headRefForcePushedEventView_item.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; declare export opaque type headRefForcePushedEventView_item$ref: FragmentReference; export type headRefForcePushedEventView_item = {| @@ -27,7 +27,7 @@ export type headRefForcePushedEventView_item = {| */ -const node/*: ConcreteFragment*/ = (function(){ +const node/*: ReaderFragment*/ = (function(){ var v0 = [ { "kind": "ScalarField", @@ -77,7 +77,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v0 + "selections": (v0/*: any*/) }, { "kind": "LinkedField", @@ -87,7 +87,7 @@ return { "args": null, "concreteType": "Commit", "plural": false, - "selections": v0 + "selections": (v0/*: any*/) }, { "kind": "ScalarField", diff --git a/lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js b/lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js index 03c065e29b..515ea0c0be 100644 --- a/lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js +++ b/lib/views/timeline-items/__generated__/issueCommentView_item.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; declare export opaque type issueCommentView_item$ref: FragmentReference; export type issueCommentView_item = {| @@ -23,7 +23,7 @@ export type issueCommentView_item = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "issueCommentView_item", "type": "IssueComment", diff --git a/lib/views/timeline-items/__generated__/mergedEventView_item.graphql.js b/lib/views/timeline-items/__generated__/mergedEventView_item.graphql.js index 1d1fa6d560..9532181e66 100644 --- a/lib/views/timeline-items/__generated__/mergedEventView_item.graphql.js +++ b/lib/views/timeline-items/__generated__/mergedEventView_item.graphql.js @@ -7,7 +7,7 @@ 'use strict'; /*:: -import type { ConcreteFragment } from 'relay-runtime'; +import type { ReaderFragment } from 'relay-runtime'; import type { FragmentReference } from "relay-runtime"; declare export opaque type mergedEventView_item$ref: FragmentReference; export type mergedEventView_item = {| @@ -25,7 +25,7 @@ export type mergedEventView_item = {| */ -const node/*: ConcreteFragment*/ = { +const node/*: ReaderFragment*/ = { "kind": "Fragment", "name": "mergedEventView_item", "type": "MergedEvent", From 5edc2397a05b8cf1a47013c0c29fe35d115beccd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Feb 2019 15:18:47 -0500 Subject: [PATCH 2901/4847] Update transpiler link in CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 389fefee47..54ab8637bf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -162,7 +162,7 @@ We use the following technologies: * We interact with GitHub via its [GraphQL](https://graphql.org/) API. * [Relay](https://github.com/facebook/relay) is a layer of glue between React and GraphQL queries that handles responsibilities like query composition and caching. * Our tests are written with [Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/) [_(with the "assert" style)_](https://www.chaijs.com/api/assert/). We also use [Enzyme](https://airbnb.io/enzyme/) to assert against React behavior. -* We use a [custom Babel 6 transpiler pipeline](https://github.com/atom/atom-babel6-transpiler) to write modern source with JSX, `import` statements, and other constructs unavailable natively within Atom's Node.js version. +* We use a [custom Babel 7 transpiler pipeline](https://github.com/atom/atom-babel7-transpiler) to write modern source with JSX, `import` statements, and other constructs unavailable natively within Atom's Node.js version. ### Updating the GraphQL Schema From 53dfb0ecc6db7281aa3bbfe498a26d6c48f12b83 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Feb 2019 15:19:01 -0500 Subject: [PATCH 2902/4847] Update manual transpiler import --- test/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/helpers.js b/test/helpers.js index ba2a7c9897..aeb6e88a62 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -2,7 +2,7 @@ import fs from 'fs-extra'; import path from 'path'; import temp from 'temp'; import until from 'test-until'; -import transpiler from 'atom-babel6-transpiler'; +import transpiler from '@atom/babel7-transpiler'; import React from 'react'; import ReactDom from 'react-dom'; From 5279efbc5517877e2e39bb92cf571365d80cb1e0 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Feb 2019 16:26:20 -0500 Subject: [PATCH 2903/4847] Move to the @atom fork of babel-plugin-chai-assert-async --- .babelrc.js | 4 ++-- package-lock.json | 13 ++++++++----- package.json | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.babelrc.js b/.babelrc.js index c3189debec..890087a771 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -1,9 +1,9 @@ module.exports = { sourceMaps: "inline", plugins: [ - "relay", + "babel-plugin-relay", "./assert-messages-plugin.js", - "babel-plugin-chai-assert-async", + "@atom/babel-plugin-chai-assert-async", "@babel/plugin-proposal-class-properties", ], presets: [ diff --git a/package-lock.json b/package-lock.json index 22b705408d..f7dc540a00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,14 @@ "integrity": "sha1-nK+xca+CMpSQNTtIFvAzR6oVCjA=", "dev": true }, + "@atom/babel-plugin-chai-assert-async": { + "version": "1.0.0-0", + "resolved": "https://registry.npmjs.org/@atom/babel-plugin-chai-assert-async/-/babel-plugin-chai-assert-async-1.0.0-0.tgz", + "integrity": "sha512-Hh0JrFu7THfCVJEudceu92KR0vaTXHx6QW2kWdZiUnfOXFskc55TUCXJZ39tdEIX14HQboVBYr+EM5LzPV714w==", + "requires": { + "@babel/helper-module-imports": "7.0.0" + } + }, "@atom/babel7-transpiler": { "version": "1.0.0-1", "resolved": "https://registry.npmjs.org/@atom/babel7-transpiler/-/babel7-transpiler-1.0.0-1.tgz", @@ -1635,11 +1643,6 @@ "babel-runtime": "^6.22.0" } }, - "babel-plugin-chai-assert-async": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-chai-assert-async/-/babel-plugin-chai-assert-async-0.1.0.tgz", - "integrity": "sha1-pJMXc79WPcKt3mzXm28ZRknr/SU=" - }, "babel-plugin-istanbul": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz", diff --git a/package.json b/package.json index 1b09706fbe..46664d0eb0 100644 --- a/package.json +++ b/package.json @@ -39,12 +39,12 @@ } ], "dependencies": { + "@atom/babel-plugin-chai-assert-async": "1.0.0-0", "@atom/babel7-transpiler": "1.0.0-1", "@babel/generator": "7.3.4", "@babel/plugin-proposal-class-properties": "7.3.4", "@babel/preset-env": "7.3.4", "@babel/preset-react": "7.0.0", - "babel-plugin-chai-assert-async": "0.1.0", "babel-plugin-relay": "3.0.0", "bintrees": "1.0.2", "bytes": "^3.0.0", From 89f3f2f3aa004b44d67e2aa613585e5470e88af8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Feb 2019 16:32:01 -0500 Subject: [PATCH 2904/4847] Depend on stable release of @atom/babel-plugin-chai-assert-async --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index f7dc540a00..cff59613eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,9 @@ "dev": true }, "@atom/babel-plugin-chai-assert-async": { - "version": "1.0.0-0", - "resolved": "https://registry.npmjs.org/@atom/babel-plugin-chai-assert-async/-/babel-plugin-chai-assert-async-1.0.0-0.tgz", - "integrity": "sha512-Hh0JrFu7THfCVJEudceu92KR0vaTXHx6QW2kWdZiUnfOXFskc55TUCXJZ39tdEIX14HQboVBYr+EM5LzPV714w==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@atom/babel-plugin-chai-assert-async/-/babel-plugin-chai-assert-async-1.0.0.tgz", + "integrity": "sha512-YGYfZkFzMfw/fa/vVivqSMJQPN/wbReg6ikTq53/CDsN3aZgtdWKwYOQThExN0GvrgXsTGqmZl5uWs1hccKE5w==", "requires": { "@babel/helper-module-imports": "7.0.0" } diff --git a/package.json b/package.json index 46664d0eb0..0494eeb9e6 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ } ], "dependencies": { - "@atom/babel-plugin-chai-assert-async": "1.0.0-0", + "@atom/babel-plugin-chai-assert-async": "1.0.0", "@atom/babel7-transpiler": "1.0.0-1", "@babel/generator": "7.3.4", "@babel/plugin-proposal-class-properties": "7.3.4", From 95900e48767ce4ebd4d01e31ca5996516193afb5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 25 Feb 2019 16:51:26 -0500 Subject: [PATCH 2905/4847] "errors" is a top-level key within the payload, not a child of "data" --- lib/relay-network-layer-manager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/relay-network-layer-manager.js b/lib/relay-network-layer-manager.js index fd6abf2861..a79d8190f2 100644 --- a/lib/relay-network-layer-manager.js +++ b/lib/relay-network-layer-manager.js @@ -118,10 +118,10 @@ function createFetchQuery(url) { const payload = await response.json(); - if (payload.data && payload.data.errors && payload.data.errors.length > 0) { + if (payload && payload.errors && payload.errors.length > 0) { const e = new Error(`GraphQL API endpoint at ${url} returned an error for query ${operation.name}.`); e.response = response; - e.errors = payload.data.errors; + e.errors = payload.errors; e.rawStack = e.stack; throw e; } From c86cbf0ba7bee55973c8fe74840dba5a0fb2941d Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Mon, 25 Feb 2019 19:39:48 -0800 Subject: [PATCH 2906/4847] Fix broken file patch symlink test @smashwilson curious why you added the 'selected' class in fb07191163049b4e3bed017a88ac9126ddbbe205 --- test/integration/file-patch.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/file-patch.test.js b/test/integration/file-patch.test.js index 63d3746cfc..b000e59790 100644 --- a/test/integration/file-patch.test.js +++ b/test/integration/file-patch.test.js @@ -514,7 +514,7 @@ describe('integration: file patches', function() { await patchContent( 'unstaged', 'sample.js', [repoPath('target.txt'), 'added', 'selected'], - [' No newline at end of file', 'nonewline', 'selected'], + [' No newline at end of file', 'nonewline'], ); assert.isTrue(getPatchItem('unstaged', 'sample.js').find('.github-FilePatchView-metaTitle').exists()); From e5fd7e891e1d84e7baae04bdcb8ced307a3be9a0 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 26 Feb 2019 14:02:45 +0900 Subject: [PATCH 2907/4847] Add right padding to comments --- styles/pr-comment.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styles/pr-comment.less b/styles/pr-comment.less index f71f9f097f..cec3c1c8b0 100644 --- a/styles/pr-comment.less +++ b/styles/pr-comment.less @@ -5,7 +5,7 @@ .github-PrCommentThread { - padding: @component-padding 0; + padding: @component-padding @component-padding @component-padding 0; } From 68f8513854b20c70693348292969551d3913784a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 08:34:07 -0500 Subject: [PATCH 2908/4847] Explicitly enable object-rest-spread plugin We need this because esprima, the JavaScript parser used by electron-link, only supports ES2017, even though our current Electron version supports some ES2018 features. Without this plugin enabled, `npm run test:snapshot` fails with an esprima error. --- .babelrc.js | 5 ++++- package-lock.json | 7 +++---- package.json | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.babelrc.js b/.babelrc.js index 890087a771..b4b117e5d1 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -5,10 +5,13 @@ module.exports = { "./assert-messages-plugin.js", "@atom/babel-plugin-chai-assert-async", "@babel/plugin-proposal-class-properties", + + // Needed for esprima + "@babel/plugin-proposal-object-rest-spread", ], presets: [ ["@babel/preset-env", { - "targets": {"electron": process.versions.electron} + targets: {electron: process.versions.electron} }], "@babel/preset-react" ], diff --git a/package-lock.json b/package-lock.json index 2cf6f9c2a9..8b3ce3a84d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -544,10 +544,9 @@ } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz", - "integrity": "sha512-DjeMS+J2+lpANkYLLO+m6GjoTMygYglKmRe6cDTbFv3L9i6mmiE8fe6B8MtCSLZpVXscD5kn7s6SgtHrDoBWoA==", - "dev": true, + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.4.tgz", + "integrity": "sha512-j7VQmbbkA+qrzNqbKHrBsW3ddFnOeva6wzSe/zB7T+xaxGc+RCpwo44wCmRixAIGRoIpmVgvzFzNJqQcO3/9RA==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-object-rest-spread": "^7.2.0" diff --git a/package.json b/package.json index 0cf3acf591..192044789b 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@atom/babel7-transpiler": "1.0.0-1", "@babel/generator": "7.3.4", "@babel/plugin-proposal-class-properties": "7.3.4", + "@babel/plugin-proposal-object-rest-spread": "7.3.4", "@babel/preset-env": "7.3.4", "@babel/preset-react": "7.0.0", "babel-plugin-relay": "3.0.0", From f8f041f9af09274df2c199104b0bcfddf8c82a95 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 10:14:22 -0500 Subject: [PATCH 2909/4847] Construct symlink-only patch bodies consistently with git At some point, git changed the way that it generated patches containing only changes related to symlink targets. This caused some odd, but ultimately harmless, discrepancies in our artificial patches. This brings our diff builder up to date with the behavior I'm observing with the current git: ``` $ git --version git version 2.21.0 $ git diff --no-prefix --no-ext-diff --no-renames --staged \ --diff-filter=u -- symlink-only-change.txt diff --git symlink-only-change.txt symlink-only-change.txt index a42ffcb..afef8f7 120000 --- symlink-only-change.txt +++ symlink-only-change.txt @@ -1 +1 @@ -lorem.md \ No newline at end of file +zzz.txt \ No newline at end of file ``` --- test/builder/patch.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/builder/patch.js b/test/builder/patch.js index bdc3046373..73a6819aeb 100644 --- a/test/builder/patch.js +++ b/test/builder/patch.js @@ -124,13 +124,12 @@ class FilePatchBuilder { const hb = new HunkBuilder(); if (this._oldSymlink !== null) { - hb.unchanged(this._oldSymlink); - } - if (this._oldSymlink !== null && this._newSymlink !== null) { - hb.unchanged('--'); + hb.deleted(this._oldSymlink); + hb.noNewline(); } if (this._newSymlink !== null) { - hb.unchanged(this._newSymlink); + hb.added(this._newSymlink); + hb.noNewline(); } rawPatch.hunks = [hb.build().raw]; From 50f0514356743c94a7138e90ea9d5e8194515e00 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 10:21:35 -0500 Subject: [PATCH 2910/4847] Render file header decorations with position: before for any empty patch When the final FilePatch within a MultiFilePatch is a mode change or symlink change diff with no content, the final patch's header content was incorrectly being placed in a Decoration with `position: after`. This broke the order in which the Decorations were rendered, because the `order` property is only respected within the set of block decorations at a given screen row that have the same position. This manifested in a glitch when collapsing and expanding FilePatches that include at least one with an empty mode change. --- lib/views/multi-file-patch-view.js | 3 +- test/views/multi-file-patch-view.test.js | 118 ++++++++++++++++------- 2 files changed, 87 insertions(+), 34 deletions(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 989ccf14e7..235d7de49c 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -391,8 +391,9 @@ export default class MultiFilePatchView extends React.Component { renderFilePatchDecorations = (filePatch, index) => { const isCollapsed = !filePatch.getRenderStatus().isVisible(); + const isEmpty = filePatch.getMarker().getRange().isEmpty(); const atEnd = filePatch.getStartRange().start.isEqual(this.props.multiFilePatch.getBuffer().getEndPosition()); - const position = isCollapsed && atEnd ? 'after' : 'before'; + const position = isEmpty && atEnd ? 'after' : 'before'; return ( diff --git a/test/views/multi-file-patch-view.test.js b/test/views/multi-file-patch-view.test.js index e96c3df4bc..4c057b5b22 100644 --- a/test/views/multi-file-patch-view.test.js +++ b/test/views/multi-file-patch-view.test.js @@ -88,44 +88,96 @@ describe('MultiFilePatchView', function() { assert.isTrue(wrapper.find('FilePatchHeaderView').exists()); }); - it('renders a final collapsed file header with position: after', function() { - const {multiFilePatch} = multiFilePatchBuilder() - .addFilePatch(fp => { - fp.renderStatus(COLLAPSED); - fp.setOldFile(f => f.path('0.txt')); - fp.addHunk(h => h.unchanged('a-0').added('a-1').unchanged('a-2')); - }) - .addFilePatch(fp => { - fp.setOldFile(f => f.path('1.txt')); - fp.addHunk(h => h.unchanged('b-0').added('b-1').unchanged('b-2')); - }) - .addFilePatch(fp => { - fp.renderStatus(COLLAPSED); - fp.setOldFile(f => f.path('2.txt')); - fp.addHunk(h => h.unchanged('c-0').added('c-1').unchanged('c-2')); - }) - .addFilePatch(fp => { - fp.setOldFile(f => f.path('3.txt')); - fp.addHunk(h => h.unchanged('d-0').added('d-1').unchanged('d-2')); - }) - .addFilePatch(fp => { - fp.renderStatus(COLLAPSED); - fp.setOldFile(f => f.path('4.txt')); - fp.addHunk(h => h.unchanged('e-0').added('e-1').unchanged('e-2')); - }) - .build(); - - const wrapper = shallow(buildApp({multiFilePatch})); + describe('file header decoration positioning', function() { + let wrapper; function decorationForFileHeader(fileName) { return wrapper.find('Decoration').filterWhere(dw => dw.exists(`FilePatchHeaderView[relPath="${fileName}"]`)); } - assert.strictEqual(decorationForFileHeader('0.txt').prop('position'), 'before'); - assert.strictEqual(decorationForFileHeader('1.txt').prop('position'), 'before'); - assert.strictEqual(decorationForFileHeader('2.txt').prop('position'), 'before'); - assert.strictEqual(decorationForFileHeader('3.txt').prop('position'), 'before'); - assert.strictEqual(decorationForFileHeader('4.txt').prop('position'), 'after'); + it('renders visible file headers with position: before', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('0.txt')); + fp.addHunk(h => h.unchanged('a-0').deleted('a-1').unchanged('a-2')); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('1.txt')); + fp.addHunk(h => h.unchanged('b-0').added('b-1').unchanged('b-2')); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('2.txt')); + fp.addHunk(h => h.unchanged('c-0').deleted('c-1').unchanged('c-2')); + }) + .build(); + + wrapper = shallow(buildApp({multiFilePatch})); + + assert.strictEqual(decorationForFileHeader('0.txt').prop('position'), 'before'); + assert.strictEqual(decorationForFileHeader('1.txt').prop('position'), 'before'); + assert.strictEqual(decorationForFileHeader('2.txt').prop('position'), 'before'); + }); + + it('renders a final collapsed file header with position: after', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.renderStatus(COLLAPSED); + fp.setOldFile(f => f.path('0.txt')); + fp.addHunk(h => h.unchanged('a-0').added('a-1').unchanged('a-2')); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('1.txt')); + fp.addHunk(h => h.unchanged('b-0').added('b-1').unchanged('b-2')); + }) + .addFilePatch(fp => { + fp.renderStatus(COLLAPSED); + fp.setOldFile(f => f.path('2.txt')); + fp.addHunk(h => h.unchanged('c-0').added('c-1').unchanged('c-2')); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('3.txt')); + fp.addHunk(h => h.unchanged('d-0').added('d-1').unchanged('d-2')); + }) + .addFilePatch(fp => { + fp.renderStatus(COLLAPSED); + fp.setOldFile(f => f.path('4.txt')); + fp.addHunk(h => h.unchanged('e-0').added('e-1').unchanged('e-2')); + }) + .build(); + + wrapper = shallow(buildApp({multiFilePatch})); + + assert.strictEqual(decorationForFileHeader('0.txt').prop('position'), 'before'); + assert.strictEqual(decorationForFileHeader('1.txt').prop('position'), 'before'); + assert.strictEqual(decorationForFileHeader('2.txt').prop('position'), 'before'); + assert.strictEqual(decorationForFileHeader('3.txt').prop('position'), 'before'); + assert.strictEqual(decorationForFileHeader('4.txt').prop('position'), 'after'); + }); + + it('renders a final mode change-only file header with position: after', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('0.txt')); + fp.setNewFile(f => f.path('0.txt').executable()); + fp.empty(); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('1.txt')); + fp.addHunk(h => h.unchanged('b-0').added('b-1').unchanged('b-2')); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('2.txt').executable()); + fp.setNewFile(f => f.path('2.txt')); + fp.empty(); + }) + .build(); + + wrapper = shallow(buildApp({multiFilePatch})); + + assert.strictEqual(decorationForFileHeader('0.txt').prop('position'), 'before'); + assert.strictEqual(decorationForFileHeader('1.txt').prop('position'), 'before'); + assert.strictEqual(decorationForFileHeader('2.txt').prop('position'), 'after'); + }); }); it('undoes the last discard from the file header button', function() { From f28f86507725e923ef770308c3e0816b820d07f4 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 11:26:28 -0500 Subject: [PATCH 2911/4847] Log destroyed and invalid markers in inspect() output --- lib/models/patch/hunk.js | 6 ++++++ lib/models/patch/patch.js | 9 ++++++++- lib/models/patch/region.js | 9 ++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/models/patch/hunk.js b/lib/models/patch/hunk.js index c4da9a48a8..1f5535b08c 100644 --- a/lib/models/patch/hunk.js +++ b/lib/models/patch/hunk.js @@ -171,6 +171,12 @@ export default class Hunk { } let inspectString = `${indentation}(Hunk marker=${this.marker.id}\n`; + if (this.marker.isDestroyed()) { + inspectString += ' [destroyed]'; + } + if (!this.marker.isValid()) { + inspectString += ' [invalid]'; + } for (const region of this.regions) { inspectString += region.inspect({indent: options.indent + 2}); } diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index ae07554b32..a44fba121e 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -343,7 +343,14 @@ export default class Patch { indentation += ' '; } - let inspectString = `${indentation}(Patch marker=${this.marker.id}\n`; + let inspectString = `${indentation}(Patch marker=${this.marker.id}`; + if (this.marker.isDestroyed()) { + inspectString += ' [destroyed]'; + } + if (!this.marker.isValid()) { + inspectString += ' [invalid]'; + } + inspectString += '\n'; for (const hunk of this.hunks) { inspectString += hunk.inspect({indent: options.indent + 2}); } diff --git a/lib/models/patch/region.js b/lib/models/patch/region.js index 85e05dbeef..b637ea6091 100644 --- a/lib/models/patch/region.js +++ b/lib/models/patch/region.js @@ -135,7 +135,14 @@ class Region { indentation += ' '; } - return `${indentation}(${this.constructor.name} marker=${this.marker.id})\n`; + let inspectString = `${indentation}(${this.constructor.name} marker=${this.marker.id})`; + if (this.marker.isDestroyed()) { + inspectString += ' [destroyed]'; + } + if (!this.marker.isValid()) { + inspectString += ' [invalid]'; + } + return inspectString + '\n'; } isChange() { From 726e09f14a6be89fb0edf6a0eb84f03d264b8a75 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 11:29:29 -0500 Subject: [PATCH 2912/4847] PatchBuffer::extractPatchBuffer() accepts a Set of boundary Markers Automatically excluding any zero-length boundary Markers didn't account for the case in which the range you're actually extracting is empty. This was causing a bug in which Markers belonging to empty (not non-collapsed) FilePatches were being destroyed and not updated on collapse. --- lib/models/patch/patch-buffer.js | 16 +++++++--------- test/models/patch/patch-buffer.test.js | 11 ++++++++--- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 182f9c381f..44aa501989 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -59,20 +59,18 @@ export default class PatchBuffer { return this.createInserterAt(this.getInsertionPoint()); } - extractPatchBuffer(rangeLike) { + extractPatchBuffer(rangeLike, options = {}) { + const opts = { + exclude: new Set(), + ...options, + }; + const range = Range.fromObject(rangeLike); const baseOffset = range.start.negate(); const movedMarkersByLayer = LAYER_NAMES.reduce((map, layerName) => { map[layerName] = this.layers[layerName] .findMarkers({containedInRange: range}) - .filter(m => { - // Manually exclude zero-length markers at the extraction range's beginning and end. - const r = m.getRange(); - if (!r.isEmpty()) { return true; } - - const point = r.start; - return !point.isEqual(range.start) && !point.isEqual(range.end); - }); + .filter(m => !opts.exclude.has(m)); return map; }, {}); const markerMap = new Map(); diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index ca4ea294f6..29bfc2379f 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -92,15 +92,18 @@ describe('PatchBuffer', function() { assert.deepEqual(markerMap.get(m3).getRange().serialize(), [[2, 0], [3, 1]]); }); - it("does not destroy zero-length markers at the extraction range's boundaries", function() { + it("does not destroy excluded markers at the extraction range's boundaries", function() { const before0 = patchBuffer.markRange('patch', [[2, 0], [2, 0]]); const before1 = patchBuffer.markRange('patch', [[2, 0], [2, 0]]); const within0 = patchBuffer.markRange('patch', [[2, 0], [2, 1]]); const within1 = patchBuffer.markRange('patch', [[3, 0], [3, 4]]); + const within2 = patchBuffer.markRange('patch', [[4, 0], [4, 0]]); const after0 = patchBuffer.markRange('patch', [[4, 0], [4, 0]]); const after1 = patchBuffer.markRange('patch', [[4, 0], [4, 0]]); - const {patchBuffer: subPatchBuffer, markerMap} = patchBuffer.extractPatchBuffer([[2, 0], [4, 0]]); + const {patchBuffer: subPatchBuffer, markerMap} = patchBuffer.extractPatchBuffer([[2, 0], [4, 0]], { + exclude: new Set([before0, before1, after0, after1]), + }); assert.strictEqual(patchBuffer.getBuffer().getText(), dedent` 0000 @@ -125,13 +128,14 @@ describe('PatchBuffer', function() { `); assert.deepEqual( subPatchBuffer.findMarkers('patch', {}).map(m => m.getRange().serialize()), - [[[0, 0], [0, 1]], [[1, 0], [1, 4]]], + [[[0, 0], [0, 1]], [[1, 0], [1, 4]], [[2, 0], [2, 0]]], ); assert.isFalse(markerMap.has(before0)); assert.isFalse(markerMap.has(before1)); assert.isTrue(markerMap.has(within0)); assert.isTrue(markerMap.has(within1)); + assert.isTrue(markerMap.has(within2)); assert.isFalse(markerMap.has(after0)); assert.isFalse(markerMap.has(after1)); @@ -139,6 +143,7 @@ describe('PatchBuffer', function() { assert.isFalse(before1.isDestroyed()); assert.isTrue(within0.isDestroyed()); assert.isTrue(within1.isDestroyed()); + assert.isTrue(within2.isDestroyed()); assert.isFalse(after0.isDestroyed()); assert.isFalse(after1.isDestroyed()); }); From 22666a1296f94f28537320477e0ad93c456223fc Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 11:31:26 -0500 Subject: [PATCH 2913/4847] Pass a set of boundary markers in FilePatch::triggerCollapseIn() This allows us to gracefully handle the case in which a FilePatch's marker is itself empty, and distinguish between empty markers we want to include in the extracted PatchBuffer and the ones we do not. --- lib/models/patch/file-patch.js | 6 +++--- test/models/patch/file-patch.test.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index b474fa1a00..b7ebbf1589 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -123,14 +123,15 @@ export default class FilePatch { return this.patch.updateMarkers(map); } - triggerCollapseIn(patchBuffer) { + triggerCollapseIn(patchBuffer, {before, after}) { if (!this.patch.getRenderStatus().isVisible()) { return false; } const oldPatch = this.patch; const insertionPosition = oldPatch.getRange().start.copy(); - const {patchBuffer: subPatchBuffer, markerMap} = patchBuffer.extractPatchBuffer(oldPatch.getRange()); + const exclude = new Set([...before, ...after]); + const {patchBuffer: subPatchBuffer, markerMap} = patchBuffer.extractPatchBuffer(oldPatch.getRange(), {exclude}); oldPatch.destroyMarkers(); oldPatch.updateMarkers(markerMap); @@ -193,7 +194,6 @@ export default class FilePatch { .apply(); } - patchBuffer .createInserterAt(this.patch.getInsertionPoint()) .keepBefore(before) diff --git a/test/models/patch/file-patch.test.js b/test/models/patch/file-patch.test.js index f5fcd52922..e2743828d5 100644 --- a/test/models/patch/file-patch.test.js +++ b/test/models/patch/file-patch.test.js @@ -683,7 +683,7 @@ describe('FilePatch', function() { assert.strictEqual(EXPANDED, filePatch.getRenderStatus()); - filePatch.triggerCollapseIn(new PatchBuffer()); + multiFilePatch.collapseFilePatch(filePatch); assert.strictEqual(COLLAPSED, filePatch.getRenderStatus()); assert.isTrue(callback.calledWith(filePatch)); @@ -695,7 +695,7 @@ describe('FilePatch', function() { fp.renderStatus(TOO_LARGE); }).build(); const filePatch = multiFilePatch.getFilePatches()[0]; - assert.isFalse(filePatch.triggerCollapseIn(new PatchBuffer())); + assert.isFalse(filePatch.triggerCollapseIn(new PatchBuffer(), {before: [], after: []})); }); it('announces the expansion of a collapsed patch', function() { From 81f6b512f06dcf4561c83b1aa11b23c54793fd00 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 11:34:49 -0500 Subject: [PATCH 2914/4847] Pass {before, after} Marker sets to FilePatch::triggerCollapseIn() This allows the PatchBuffer::extractPatchBuffer() call within the collapse operation to correctly identify which boundary markers should be included in the extracted PatchBuffer and which should not, even when the FilePatch's marker is itself empty. I've also refactored out MultiFilePatch::getMarkersBefore() and MultiFilePatch::getMarkersAfter() methods to save some duplication among triggerExpandIn() and triggerCollapseIn() methods, and added a test case that minimally reproduces the lost marker. --- lib/models/patch/multi-file-patch.js | 34 +++++++++++++++------- test/models/patch/multi-file-patch.test.js | 32 ++++++++++++++++++++ 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 72fb5f937b..47e7e635e0 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -294,12 +294,17 @@ export default class MultiFilePatch { } collapseFilePatch(filePatch) { + const index = this.filePatches.indexOf(filePatch); + this.filePatchesByMarker.delete(filePatch.getMarker()); for (const hunk of filePatch.getHunks()) { this.hunksByMarker.delete(hunk.getMarker()); } - filePatch.triggerCollapseIn(this.patchBuffer); + const before = this.getMarkersBefore(index); + const after = this.getMarkersAfter(index); + + filePatch.triggerCollapseIn(this.patchBuffer, {before, after}); this.filePatchesByMarker.set(filePatch.getMarker(), filePatch); @@ -318,8 +323,20 @@ export default class MultiFilePatch { this.hunksByMarker.delete(hunk.getMarker()); } + const before = this.getMarkersBefore(index); + const after = this.getMarkersAfter(index); + + filePatch.triggerExpandIn(this.patchBuffer, {before, after}); + + this.filePatchesByMarker.set(filePatch.getMarker(), filePatch); + for (const hunk of filePatch.getHunks()) { + this.hunksByMarker.set(hunk.getMarker(), hunk); + } + } + + getMarkersBefore(filePatchIndex) { const before = []; - let beforeIndex = index - 1; + let beforeIndex = filePatchIndex - 1; while (beforeIndex >= 0) { const beforeFilePatch = this.filePatches[beforeIndex]; before.push(...beforeFilePatch.getEndingMarkers()); @@ -329,9 +346,12 @@ export default class MultiFilePatch { } beforeIndex--; } + return before; + } + getMarkersAfter(filePatchIndex) { const after = []; - let afterIndex = index + 1; + let afterIndex = filePatchIndex + 1; while (afterIndex < this.filePatches.length) { const afterFilePatch = this.filePatches[afterIndex]; after.push(...afterFilePatch.getStartingMarkers()); @@ -341,13 +361,7 @@ export default class MultiFilePatch { } afterIndex++; } - - filePatch.triggerExpandIn(this.patchBuffer, {before, after}); - - this.filePatchesByMarker.set(filePatch.getMarker(), filePatch); - for (const hunk of filePatch.getHunks()) { - this.hunksByMarker.set(hunk.getMarker(), hunk); - } + return after; } isPatchVisible = filePatchPath => { diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index 0917a6e0e4..7ab1cde4cd 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -1176,5 +1176,37 @@ describe('MultiFilePatch', function() { } }); }); + + describe('when a file patch has no content', function() { + it('collapses and expands', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('0.txt').executable()); + fp.setNewFile(f => f.path('0.txt')); + fp.empty(); + }) + .build(); + + assert.strictEqual(multiFilePatch.getBuffer().getText(), ''); + + const [fp0] = multiFilePatch.getFilePatches(); + + multiFilePatch.collapseFilePatch(fp0); + + assert.strictEqual(multiFilePatch.getBuffer().getText(), ''); + assertInFilePatch(fp0, multiFilePatch.getBuffer()).hunks(); + assert.deepEqual(fp0.getMarker().getRange().serialize(), [[0, 0], [0, 0]]); + assert.isTrue(fp0.getMarker().isValid()); + assert.isFalse(fp0.getMarker().isDestroyed()); + + multiFilePatch.expandFilePatch(fp0); + + assert.strictEqual(multiFilePatch.getBuffer().getText(), ''); + assertInFilePatch(fp0, multiFilePatch.getBuffer()).hunks(); + assert.deepEqual(fp0.getMarker().getRange().serialize(), [[0, 0], [0, 0]]); + assert.isTrue(fp0.getMarker().isValid()); + assert.isFalse(fp0.getMarker().isDestroyed()); + }); + }); }); }); From 135ccce59b7c2b553bd7d3da321936183f691c93 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 13:13:19 -0500 Subject: [PATCH 2915/4847] Collapse and expand content-less FilePatches When collapsing and expanding FilePatches that have no content, ensure that separating newlines are preserved or omitted correctly. This prevents a glitch where the final newline will pop in and out as you collapse and expand a mode-only patch at the end of a MultiFilePatchView. --- lib/models/patch/file-patch.js | 12 ++++-- test/models/patch/multi-file-patch.test.js | 46 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index b7ebbf1589..6ae550af29 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -129,14 +129,17 @@ export default class FilePatch { } const oldPatch = this.patch; - const insertionPosition = oldPatch.getRange().start.copy(); + const oldRange = oldPatch.getRange().copy(); + const insertionPosition = oldRange.start; const exclude = new Set([...before, ...after]); - const {patchBuffer: subPatchBuffer, markerMap} = patchBuffer.extractPatchBuffer(oldPatch.getRange(), {exclude}); + const {patchBuffer: subPatchBuffer, markerMap} = patchBuffer.extractPatchBuffer(oldRange, {exclude}); oldPatch.destroyMarkers(); oldPatch.updateMarkers(markerMap); // Delete the separating newline after the collapsing patch, if any. - patchBuffer.getBuffer().deleteRow(insertionPosition.row); + if (!oldRange.isEmpty()) { + patchBuffer.getBuffer().deleteRow(insertionPosition.row); + } const patchMarker = patchBuffer.markPosition( Patch.layerName, @@ -159,6 +162,7 @@ export default class FilePatch { const {patch: nextPatch, patchBuffer: subPatchBuffer} = this.patch.show(); const atStart = this.patch.getInsertionPoint().isEqual([0, 0]); const atEnd = this.patch.getInsertionPoint().isEqual(patchBuffer.getBuffer().getEndPosition()); + const willHaveContent = !subPatchBuffer.getBuffer().isEmpty(); // The expanding patch's insertion point is just after the unmarked newline that separates adjacent visible // patches: @@ -174,7 +178,7 @@ export default class FilePatch { // (so it isn't also the end of the buffer). Insert a newline *after* the expanding patch when inserting anywhere // but the buffer's end. - if (atEnd && !atStart) { + if (willHaveContent && atEnd && !atStart) { const beforeNewline = []; const afterNewline = after.slice(); diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index 7ab1cde4cd..580da3ddd5 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -1207,6 +1207,52 @@ describe('MultiFilePatch', function() { assert.isTrue(fp0.getMarker().isValid()); assert.isFalse(fp0.getMarker().isDestroyed()); }); + + it('does not insert a trailing newline when expanding a final content-less patch', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('0.txt')); + fp.addHunk(h => h.unchanged('0').added('1').unchanged('2')); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('1.txt').executable()); + fp.setNewFile(f => f.path('1.txt')); + fp.empty(); + }) + .build(); + const [fp0, fp1] = multiFilePatch.getFilePatches(); + + assert.isTrue(fp1.getRenderStatus().isVisible()); + assert.strictEqual(multiFilePatch.getBuffer().getText(), dedent` + 0 + 1 + 2 + `); + assert.deepEqual(fp0.getMarker().getRange().serialize(), [[0, 0], [2, 1]]); + assert.deepEqual(fp1.getMarker().getRange().serialize(), [[2, 1], [2, 1]]); + + multiFilePatch.collapseFilePatch(fp1); + + assert.isFalse(fp1.getRenderStatus().isVisible()); + assert.strictEqual(multiFilePatch.getBuffer().getText(), dedent` + 0 + 1 + 2 + `); + assert.deepEqual(fp0.getMarker().getRange().serialize(), [[0, 0], [2, 1]]); + assert.deepEqual(fp1.getMarker().getRange().serialize(), [[2, 1], [2, 1]]); + + multiFilePatch.expandFilePatch(fp1); + + assert.isTrue(fp1.getRenderStatus().isVisible()); + assert.strictEqual(multiFilePatch.getBuffer().getText(), dedent` + 0 + 1 + 2 + `); + assert.deepEqual(fp0.getMarker().getRange().serialize(), [[0, 0], [2, 1]]); + assert.deepEqual(fp1.getMarker().getRange().serialize(), [[2, 1], [2, 1]]); + }); }); }); }); From e11e6877b5727036f3ee013d4b0b3bea1911db84 Mon Sep 17 00:00:00 2001 From: annthurium Date: Tue, 26 Feb 2019 11:04:10 -0800 Subject: [PATCH 2916/4847] support new reaction emoji from GitHub.com --- lib/views/emoji-reactions-view.js | 23 +++++++++++++++-------- test/views/emoji-reactions-view.test.js | 10 ++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/lib/views/emoji-reactions-view.js b/lib/views/emoji-reactions-view.js index 240d55fd42..729566fd4a 100644 --- a/lib/views/emoji-reactions-view.js +++ b/lib/views/emoji-reactions-view.js @@ -9,6 +9,8 @@ const reactionTypeToEmoji = { HOORAY: '🎉', CONFUSED: '😕', HEART: '❤️', + ROCKET: '🚀', + EYES: '👀', }; export default class EmojiReactionsView extends React.Component { @@ -26,14 +28,19 @@ export default class EmojiReactionsView extends React.Component { render() { return (
    - {this.props.reactionGroups.map(group => ( - group.users.totalCount > 0 - ? - {reactionTypeToEmoji[group.content]}   {group.users.totalCount} - - : null - ))} + {this.props.reactionGroups.map(group => { + const emoji = reactionTypeToEmoji[group.content]; + if (!emoji) { + return null; + } + return ( + group.users.totalCount > 0 + ? + {reactionTypeToEmoji[group.content]}   {group.users.totalCount} + + : null); + })}
    ); } diff --git a/test/views/emoji-reactions-view.test.js b/test/views/emoji-reactions-view.test.js index 9c6e31e3b1..767116e6fa 100644 --- a/test/views/emoji-reactions-view.test.js +++ b/test/views/emoji-reactions-view.test.js @@ -7,6 +7,9 @@ describe('EmojiReactionsView', function() { const reactionGroups = [ {content: 'THUMBS_UP', users: {totalCount: 10}}, {content: 'THUMBS_DOWN', users: {totalCount: 5}}, + {content: 'ROCKET', users: {totalCount: 42}}, + {content: 'EYES', users: {totalCount: 13}}, + {content: 'AVOCADO', users: {totalCount: 11}}, {content: 'LAUGH', users: {totalCount: 0}}]; beforeEach(function() { wrapper = shallow(); @@ -15,6 +18,13 @@ describe('EmojiReactionsView', function() { const groups = wrapper.find('.github-IssueishDetailView-reactionsGroup'); assert.lengthOf(groups.findWhere(n => /👍/u.test(n.text()) && /\b10\b/.test(n.text())), 1); assert.lengthOf(groups.findWhere(n => /👎/u.test(n.text()) && /\b5\b/.test(n.text())), 1); + assert.lengthOf(groups.findWhere(n => /🚀/u.test(n.text()) && /\b42\b/.test(n.text())), 1); + assert.lengthOf(groups.findWhere(n => /👀/u.test(n.text()) && /\b13\b/.test(n.text())), 1); assert.isFalse(groups.someWhere(n => /😆/u.test(n.text()))); }); + it('gracefully skips unknown emoji', function() { + assert.isFalse(wrapper.text().includes(11)); + const groups = wrapper.find('.github-IssueishDetailView-reactionsGroup'); + assert.lengthOf(groups, 4); + }); }); From 9a3c4dac12f416d0000ed9d4c75943856696c4a1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 14:27:22 -0500 Subject: [PATCH 2917/4847] Use IIFEs to bind variables in arrow functions --- lib/models/patch/builder.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index f378c3f838..2321141855 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -58,7 +58,9 @@ export function buildMultiFilePatch(diffs, options) { if (otherHalf) { // The second half. Complete the paired diff, or fail if they have unexpected statuses or modes. const [otherDiff, otherIndex] = otherHalf; - actions[otherIndex] = () => dualDiffFilePatch(diff, otherDiff, patchBuffer, opts); + actions[otherIndex] = (function(_diff, _otherDiff) { + return () => dualDiffFilePatch(_diff, _otherDiff, patchBuffer, opts); + })(diff, otherDiff); byPath.delete(thePath); } else { // The first half we've seen. @@ -66,14 +68,18 @@ export function buildMultiFilePatch(diffs, options) { index++; } } else { - actions[index] = () => singleDiffFilePatch(diff, patchBuffer, opts); + actions[index] = (function(_diff) { + return () => singleDiffFilePatch(_diff, patchBuffer, opts); + })(diff); index++; } } // Populate unpaired diffs that looked like they could be part of a pair, but weren't. for (const [unpairedDiff, originalIndex] of byPath.values()) { - actions[originalIndex] = () => singleDiffFilePatch(unpairedDiff, patchBuffer, opts); + actions[originalIndex] = (function(_unpairedDiff) { + return () => singleDiffFilePatch(_unpairedDiff, patchBuffer, opts); + })(unpairedDiff); } const filePatches = actions.map(action => action()); From 817143ee065059ff94a8cb092b6ff188523bcdb3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 14:27:44 -0500 Subject: [PATCH 2918/4847] Only measure the contentChangeDiff when determining if it's "too large" --- lib/models/patch/builder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index 2321141855..aecd09aca0 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -188,7 +188,7 @@ function dualDiffFilePatch(diff1, diff2, patchBuffer, opts) { const newFile = new File({path: filePath, mode: newMode, symlink: newSymlink}); const renderStatus = opts.renderStatusOverrides[filePath] || - (isDiffLarge([diff1, diff2], opts) && TOO_LARGE) || + (isDiffLarge([contentChangeDiff], opts) && TOO_LARGE) || EXPANDED; if (!renderStatus.isVisible()) { From 69b8a7370b8292ce62b5acb60e7e110994fd2f85 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 14:39:27 -0500 Subject: [PATCH 2919/4847] Lock dependencies with exact ranges --- package-lock.json | 118 ++++++++++++++++++++++++++++++---------------- package.json | 10 ++-- 2 files changed, 82 insertions(+), 46 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8b3ce3a84d..3800777f48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1767,20 +1767,62 @@ } }, "babel-traverse": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", - "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "^6.22.0", + "babel-code-frame": "^6.26.0", "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-types": "^6.25.0", - "babylon": "^6.17.2", - "debug": "^2.2.0", - "globals": "^9.0.0", - "invariant": "^2.2.0", - "lodash": "^4.2.0" + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + }, + "dependencies": { + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + } } }, "babel-types": { @@ -2034,9 +2076,9 @@ "dev": true }, "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, "cache-base": { "version": "1.0.1", @@ -2778,9 +2820,9 @@ } }, "dugite": { - "version": "1.81.0", - "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.81.0.tgz", - "integrity": "sha512-aH1cVzbEXOHqpiub9PWJUN+R2p7H+tvN+VqyAYHR9Tj/axLDccWJk5aKDN1/US82DkaIYWUZz8x0lAbjfqrq4Q==", + "version": "1.84.0", + "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.84.0.tgz", + "integrity": "sha512-TKBfeQAq4f4bcrPRtb9k1LnI/dssl8K85A5LxnJIaKdhGUbOtmcJacSzNSiokz0OFbSOEIYxtgZMRnkVONIURg==", "requires": { "checksum": "^0.1.1", "mkdirp": "^0.5.1", @@ -2791,9 +2833,9 @@ }, "dependencies": { "ajv": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", - "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz", + "integrity": "sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg==", "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -2831,16 +2873,16 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "mime-db": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" }, "mime-types": { - "version": "2.1.21", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", - "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", "requires": { - "mime-db": "~1.37.0" + "mime-db": "~1.38.0" } }, "oauth-sign": { @@ -2848,11 +2890,6 @@ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" - }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", @@ -4121,7 +4158,7 @@ "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true }, "globby": { @@ -5111,9 +5148,9 @@ } }, "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha1-maktZcAnLevoyWtgV7yPv6O+1RE=", + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, "lodash.escape": { @@ -5691,9 +5728,9 @@ } }, "node-emoji": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz", - "integrity": "sha512-+ktMAh1Jwas+TnGodfCfjUbJKoANqPaJFN0z0iqh41eqD8dvguNzcitVSBSVK1pidz0AqGbLKcoVuVLRVZ/aVg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", "requires": { "lodash.toarray": "^4.4.0" } @@ -7225,8 +7262,7 @@ "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, "progress-stream": { "version": "1.2.0", diff --git a/package.json b/package.json index 192044789b..8090ae522e 100644 --- a/package.json +++ b/package.json @@ -48,17 +48,17 @@ "@babel/preset-react": "7.0.0", "babel-plugin-relay": "3.0.0", "bintrees": "1.0.2", - "bytes": "^3.0.0", + "bytes": "3.1.0", "classnames": "2.2.6", "compare-sets": "1.0.1", - "dugite": "^1.81.0", + "dugite": "1.84.0", "event-kit": "2.5.3", "fs-extra": "4.0.3", "graphql": "14.1.1", "keytar": "4.4.0", "lodash.memoize": "4.1.2", "moment": "2.23.0", - "node-emoji": "^1.8.1", + "node-emoji": "1.10.0", "prop-types": "15.7.2", "react": "16.8.3", "react-dom": "16.8.3", @@ -95,9 +95,9 @@ "hock": "1.3.3", "lodash.isequalwith": "4.4.0", "mkdirp": "0.5.1", - "mocha": "^5.2.0", + "mocha": "5.2.0", "mocha-junit-reporter": "1.18.0", - "mocha-multi-reporters": "^1.1.7", + "mocha-multi-reporters": "1.1.7", "mocha-stress": "1.0.0", "node-fetch": "2.3.0", "nyc": "13.3.0", From 4839a108975760ff0484b6b785896c608b03ebe8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 14:40:38 -0500 Subject: [PATCH 2920/4847] Update devDependencies that have drifted --- package-lock.json | 73 ++++++++++++++++++++++++++--------------------- package.json | 4 +-- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3800777f48..2d9cf2bcf0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2720,12 +2720,11 @@ "dev": true }, "dir-glob": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", - "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", "dev": true, "requires": { - "arrify": "^1.0.1", "path-type": "^3.0.0" }, "dependencies": { @@ -3046,9 +3045,9 @@ "integrity": "sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g==" }, "emoji-regex": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz", - "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, "encoding": { @@ -3435,17 +3434,17 @@ "dev": true }, "eslint-plugin-jsx-a11y": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.2.tgz", - "integrity": "sha512-7gSSmwb3A+fQwtw0arguwMdOdzmKUgnUcbSNlo+GjKLAQFuC2EZxWqG9XHRI8VscBJD5a8raz3RuxQNFW+XJbw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz", + "integrity": "sha512-cjN2ObWrRz0TTw7vEcGQrx+YltMvZoOEx4hWU8eEERDnBIU00OTq7Vr+jA7DFKxiwLNv4tTh5Pq2GUNEa8b6+w==", "dev": true, "requires": { "aria-query": "^3.0.0", "array-includes": "^3.0.3", "ast-types-flow": "^0.0.7", - "axobject-query": "^2.0.1", + "axobject-query": "^2.0.2", "damerau-levenshtein": "^1.0.4", - "emoji-regex": "^6.5.1", + "emoji-regex": "^7.0.2", "has": "^1.0.3", "jsx-ast-utils": "^2.0.1" }, @@ -4162,30 +4161,38 @@ "dev": true }, "globby": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", - "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.0.0.tgz", + "integrity": "sha512-q0qiO/p1w/yJ0hk8V9x1UXlgsXUxlGd0AHUOXZVXBO6aznDtpx7M8D1kBrCAItoPm+4l8r6ATXV1JpjY2SBQOw==", "dev": true, "requires": { - "array-union": "^1.0.1", - "dir-glob": "2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" + "array-union": "^1.0.2", + "dir-glob": "^2.2.1", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" }, "dependencies": { - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } }, "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true } } @@ -8059,9 +8066,9 @@ } }, "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, "slice-ansi": { diff --git a/package.json b/package.json index 8090ae522e..4561e5f43b 100644 --- a/package.json +++ b/package.json @@ -90,8 +90,8 @@ "enzyme-adapter-react-16": "1.7.1", "eslint": "5.14.1", "eslint-config-fbjs-opensource": "1.0.0", - "eslint-plugin-jsx-a11y": "6.1.2", - "globby": "8.0.2", + "eslint-plugin-jsx-a11y": "6.2.1", + "globby": "9.0.0", "hock": "1.3.3", "lodash.isequalwith": "4.4.0", "mkdirp": "0.5.1", From 9cec6ee53fedf3979525de45a243e83a6ca49cf2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 14:43:09 -0500 Subject: [PATCH 2921/4847] Update non-dev dependencies --- package-lock.json | 85 ++++++++++++++++++++++++++--------------------- package.json | 4 +-- 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d9cf2bcf0..9b0775d449 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1246,36 +1246,6 @@ "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", "dev": true }, - "@shiftkey/prebuild-install": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/@shiftkey/prebuild-install/-/prebuild-install-5.2.4.tgz", - "integrity": "sha512-42L/pSGD/+diCg8SwhZaXjDlkAWV10u42UozyG7rqDdyPW7HDp2/j/RYRZ3x0sXFf7hAUtLYvI9HdACWdjyfVw==", - "requires": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.2.0", - "noop-logger": "^0.1.1", - "npmlog": "^4.0.1", - "os-homedir": "^1.0.1", - "pump": "^2.0.1", - "rc": "^1.2.7", - "simple-get": "^2.7.0", - "tar-fs": "^1.13.0", - "tunnel-agent": "^0.6.0", - "which-pm-runs": "^1.0.0" - }, - "dependencies": { - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" - } - } - }, "@sinonjs/commons": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.3.0.tgz", @@ -4991,12 +4961,12 @@ "dev": true }, "keytar": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-4.4.0.tgz", - "integrity": "sha512-IX6rvzrXVCWwQDGxf0FmF1IYDU2UuKsTPl1rhMCvoFfvkpRyKQYHYNqmKISwTseh/JVk4VPRlLsP4L3J25odBg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-4.4.1.tgz", + "integrity": "sha512-6xEe7ybXSR5EZC+z0GI2yqLYZjV1tyPQY2xSZ8rGsBxrrLEh8VR/Lfqv59uGX+I+W+OZxH0jCXN1dU1++ify4g==", "requires": { - "@shiftkey/prebuild-install": "5.2.4", - "nan": "2.12.1" + "nan": "2.12.1", + "prebuild-install": "5.2.4" } }, "kind-of": { @@ -5612,9 +5582,9 @@ "dev": true }, "moment": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz", - "integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==" + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, "moo": { "version": "0.4.3", @@ -5730,6 +5700,7 @@ "version": "2.4.5", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.5.tgz", "integrity": "sha512-aa/UC6Nr3+tqhHGRsAuw/edz7/q9nnetBrKWxj6rpTtm+0X9T1qU7lIEHMS3yN9JwAbRiKUbRRFy1PLz/y3aaA==", + "dev": true, "requires": { "semver": "^5.4.1" } @@ -7234,6 +7205,44 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, + "prebuild-install": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.2.4.tgz", + "integrity": "sha512-CG3JnpTZXdmr92GW4zbcba4jkDha6uHraJ7hW4Fn8j0mExxwOKK20hqho8ZuBDCKYCHYIkFM1P2jhtG+KpP4fg==", + "requires": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "os-homedir": "^1.0.1", + "pump": "^2.0.1", + "rc": "^1.2.7", + "simple-get": "^2.7.0", + "tar-fs": "^1.13.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + }, + "dependencies": { + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, + "node-abi": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.7.1.tgz", + "integrity": "sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw==", + "requires": { + "semver": "^5.4.1" + } + } + } + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", diff --git a/package.json b/package.json index 4561e5f43b..13e84b5618 100644 --- a/package.json +++ b/package.json @@ -55,9 +55,9 @@ "event-kit": "2.5.3", "fs-extra": "4.0.3", "graphql": "14.1.1", - "keytar": "4.4.0", + "keytar": "4.4.1", "lodash.memoize": "4.1.2", - "moment": "2.23.0", + "moment": "2.24.0", "node-emoji": "1.10.0", "prop-types": "15.7.2", "react": "16.8.3", From 0b7811d8fac32d2dea161416967bc73aabdf9aa5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 15:20:24 -0500 Subject: [PATCH 2922/4847] Patch :100: --- lib/models/patch/patch.js | 11 ++++++----- test/models/patch/patch.test.js | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/models/patch/patch.js b/lib/models/patch/patch.js index a44fba121e..2e75f666cd 100644 --- a/lib/models/patch/patch.js +++ b/lib/models/patch/patch.js @@ -4,18 +4,21 @@ import Hunk from './hunk'; import {Unchanged, Addition, Deletion, NoNewline} from './region'; export const EXPANDED = { + /* istanbul ignore next */ toString() { return 'RenderStatus(expanded)'; }, isVisible() { return true; }, }; export const COLLAPSED = { + /* istanbul ignore next */ toString() { return 'RenderStatus(collapsed)'; }, isVisible() { return false; }, }; export const TOO_LARGE = { + /* istanbul ignore next */ toString() { return 'RenderStatus(too-large)'; }, isVisible() { return false; }, @@ -331,8 +334,8 @@ export default class Patch { /* * Construct a String containing internal diagnostic information. */ + /* istanbul ignore next */ inspect(opts = {}) { - /* istanbul ignore next */ const options = { indent: 0, ...opts, @@ -386,6 +389,7 @@ class HiddenPatch extends Patch { /* * Construct a String containing internal diagnostic information. */ + /* istanbul ignore next */ inspect(opts = {}) { const options = { indent: 0, @@ -486,6 +490,7 @@ class NullPatch { /* * Construct a String containing internal diagnostic information. */ + /* istanbul ignore next */ inspect(opts = {}) { const options = { indent: 0, @@ -593,8 +598,4 @@ class BufferBuilder { return {regions: [], marker: null}; } - - getLayeredBuffer() { - return this.nextPatchBuffer; - } } diff --git a/test/models/patch/patch.test.js b/test/models/patch/patch.test.js index 09648d39a2..5fe2e3050e 100644 --- a/test/models/patch/patch.test.js +++ b/test/models/patch/patch.test.js @@ -684,6 +684,7 @@ describe('Patch', function() { const nullPatch = Patch.createNull(); assert.isNull(nullPatch.getStatus()); assert.deepEqual(nullPatch.getMarker().getRange().serialize(), [[0, 0], [0, 0]]); + assert.deepEqual(nullPatch.getRange().serialize(), [[0, 0], [0, 0]]); assert.deepEqual(nullPatch.getStartRange().serialize(), [[0, 0], [0, 0]]); assert.deepEqual(nullPatch.getHunks(), []); assert.strictEqual(nullPatch.getChangedLineCount(), 0); @@ -692,6 +693,8 @@ describe('Patch', function() { assert.deepEqual(nullPatch.getFirstChangeRange().serialize(), [[0, 0], [0, 0]]); assert.strictEqual(nullPatch.toStringIn(), ''); assert.isFalse(nullPatch.isPresent()); + assert.lengthOf(nullPatch.getStartingMarkers(), 0); + assert.lengthOf(nullPatch.getEndingMarkers(), 0); }); }); From 6e4ae952e36abd83569cfb5d609efe22d61aae83 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 15:21:55 -0500 Subject: [PATCH 2923/4847] Region :100: --- lib/models/patch/region.js | 1 + test/models/patch/region.test.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/models/patch/region.js b/lib/models/patch/region.js index b637ea6091..39f0414b0f 100644 --- a/lib/models/patch/region.js +++ b/lib/models/patch/region.js @@ -124,6 +124,7 @@ class Region { /* * Construct a String containing internal diagnostic information. */ + /* istanbul ignore next */ inspect(opts = {}) { const options = { indent: 0, diff --git a/test/models/patch/region.test.js b/test/models/patch/region.test.js index 105a8746b5..8bbc7961c5 100644 --- a/test/models/patch/region.test.js +++ b/test/models/patch/region.test.js @@ -1,7 +1,7 @@ import {TextBuffer} from 'atom'; import {Addition, Deletion, NoNewline, Unchanged} from '../../../lib/models/patch/region'; -describe('Regions', function() { +describe('Region', function() { let buffer, marker; beforeEach(function() { From 2681e23da4359f756d455b760db31c2a992469b5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 15:41:46 -0500 Subject: [PATCH 2924/4847] FilePatch :100: --- lib/models/patch/file-patch.js | 1 + test/models/patch/file-patch.test.js | 30 +++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/models/patch/file-patch.js b/lib/models/patch/file-patch.js index 6ae550af29..87764c0d41 100644 --- a/lib/models/patch/file-patch.js +++ b/lib/models/patch/file-patch.js @@ -324,6 +324,7 @@ export default class FilePatch { /* * Construct a String containing diagnostic information about the internal state of this FilePatch. */ + /* istanbul ignore next */ inspect(opts = {}) { const options = { indent: 0, diff --git a/test/models/patch/file-patch.test.js b/test/models/patch/file-patch.test.js index e2743828d5..4ee102cd27 100644 --- a/test/models/patch/file-patch.test.js +++ b/test/models/patch/file-patch.test.js @@ -23,7 +23,7 @@ describe('FilePatch', function() { ], }), ]; - const marker = markRange(layers.patch); + const marker = markRange(layers.patch, 0, 2); const patch = new Patch({status: 'modified', hunks, marker}); const oldFile = new File({path: 'a.txt', mode: '120000', symlink: 'dest.txt'}); const newFile = new File({path: 'b.txt', mode: '100755'}); @@ -42,6 +42,14 @@ describe('FilePatch', function() { assert.strictEqual(filePatch.getMarker(), marker); assert.strictEqual(filePatch.getMaxLineNumberWidth(), 1); + + assert.deepEqual(filePatch.getFirstChangeRange().serialize(), [[1, 0], [1, Infinity]]); + assert.isTrue(filePatch.containsRow(0)); + assert.isFalse(filePatch.containsRow(3)); + + const nMarker = markRange(layers.patch, 0, 2); + filePatch.updateMarkers(new Map([[marker, nMarker]])); + assert.strictEqual(filePatch.getMarker(), nMarker); }); it('accesses a file path from either side of the patch', function() { @@ -698,6 +706,26 @@ describe('FilePatch', function() { assert.isFalse(filePatch.triggerCollapseIn(new PatchBuffer(), {before: [], after: []})); }); + it('triggerCollapseIn does not delete the trailing line if the collapsed patch has no content', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => { + fp.setOldFile(f => f.path('0.txt')); + fp.addHunk(h => h.added('0')); + }) + .addFilePatch(fp => { + fp.setOldFile(f => f.path('1.txt')); + fp.setNewFile(f => f.path('1.txt').executable()); + fp.empty(); + }) + .build(); + + assert.strictEqual(multiFilePatch.getBuffer().getText(), '0'); + + multiFilePatch.collapseFilePatch(multiFilePatch.getFilePatches()[1]); + + assert.strictEqual(multiFilePatch.getBuffer().getText(), '0'); + }); + it('announces the expansion of a collapsed patch', function() { const {multiFilePatch} = multiFilePatchBuilder() .addFilePatch(fp => { From 7dc1b78e18eb01e9a34efc46d7d5a78fef84a3d8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 26 Feb 2019 15:52:52 -0500 Subject: [PATCH 2925/4847] Starting on MultiFilePatchView test coverage --- lib/views/multi-file-patch-view.js | 21 +++++++++++++++------ test/views/multi-file-patch-view.test.js | 6 ++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 235d7de49c..c86aad5906 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -121,6 +121,7 @@ export default class MultiFilePatchView extends React.Component { }), this.props.onDidUpdatePatch(nextPatch => { this.refEditor.map(editor => { + /* istanbul ignore else */ if (lastSelectionIndex !== null) { const nextSelectionRange = nextPatch.getSelectionRangeForIndex(lastSelectionIndex); if (this.props.selectionMode === 'line') { @@ -132,6 +133,7 @@ export default class MultiFilePatchView extends React.Component { .map(row => nextPatch.getHunkAt(row)) .filter(Boolean), ); + /* istanbul ignore next */ const nextRanges = nextHunks.size > 0 ? Array.from(nextHunks, hunk => hunk.getRange()) : [[[0, 0], [0, 0]]]; @@ -140,7 +142,11 @@ export default class MultiFilePatchView extends React.Component { editor.setSelectedBufferRanges(nextRanges); } } + + /* istanbul ignore else */ if (lastScrollTop !== null) { editor.getElement().setScrollTop(lastScrollTop); } + + /* istanbul ignore else */ if (lastScrollLeft !== null) { editor.getElement().setScrollLeft(lastScrollLeft); } return null; }); @@ -170,11 +176,11 @@ export default class MultiFilePatchView extends React.Component { }); this.subs.add( - this.props.config.onDidChange('github.showDiffIconGutter', ({newValue}) => this.forceUpdate()), + this.props.config.onDidChange('github.showDiffIconGutter', () => this.forceUpdate()), ); } - componentDidUpdate(prevProps, prevState) { + componentDidUpdate(prevProps) { this.measurePerformance('update'); if (prevProps.refInitialFocus !== this.props.refInitialFocus) { @@ -260,7 +266,7 @@ export default class MultiFilePatchView extends React.Component { {stageModeCommand} {stageSymlinkCommand} - {atom.inDevMode() && + {/* istanbul ignore next */ atom.inDevMode() && { // eslint-disable-next-line no-console console.log(this.props.multiFilePatch.getLayeredBuffer().inspect({ @@ -269,7 +275,7 @@ export default class MultiFilePatchView extends React.Component { }} /> } - {atom.inDevMode() && + {/* istanbul ignore next */ atom.inDevMode() && { // eslint-disable-next-line no-console console.log(this.props.multiFilePatch.getLayeredBuffer().inspect({ @@ -278,7 +284,7 @@ export default class MultiFilePatchView extends React.Component { }} /> } - {atom.inDevMode() && + {/* istanbul ignore next */ atom.inDevMode() && { // eslint-disable-next-line no-console console.log(this.props.multiFilePatch.inspect()); @@ -707,6 +713,7 @@ export default class MultiFilePatchView extends React.Component { undoLastDiscardFromCoreUndo = () => { if (this.props.hasUndoHistory) { const selectedFilePatches = Array.from(this.getSelectedFilePatches()); + /* istanbul ignore else */ if (this.props.itemType === ChangedFileItem) { this.props.undoLastDiscard(selectedFilePatches[0], {eventSource: {command: 'core:undo'}}); } @@ -923,6 +930,7 @@ export default class MultiFilePatchView extends React.Component { let firstChangeRow = Infinity; for (const hunk of selectedHunks) { const [firstChange] = hunk.getChanges(); + /* istanbul ignore else */ if (firstChange && (!firstChangeRow || firstChange.getStartBufferRow() < firstChangeRow)) { firstChangeRow = firstChange.getStartBufferRow(); } @@ -977,7 +985,7 @@ export default class MultiFilePatchView extends React.Component { }); } - didOpenFile({selectedFilePatch} = {}) { + didOpenFile({selectedFilePatch}) { const cursorsByFilePatch = new Map(); this.refEditor.map(editor => { @@ -1205,6 +1213,7 @@ export default class MultiFilePatchView extends React.Component { } measurePerformance(action) { + /* istanbul ignore else */ if ((action === 'update' || action === 'mount') && performance.getEntriesByName(`MultiFilePatchView-${action}-start`).length > 0) { performance.mark(`MultiFilePatchView-${action}-end`); diff --git a/test/views/multi-file-patch-view.test.js b/test/views/multi-file-patch-view.test.js index 4c057b5b22..8af61c38ff 100644 --- a/test/views/multi-file-patch-view.test.js +++ b/test/views/multi-file-patch-view.test.js @@ -88,6 +88,12 @@ describe('MultiFilePatchView', function() { assert.isTrue(wrapper.find('FilePatchHeaderView').exists()); }); + it('populates an externally provided refEditor', async function() { + const refEditor = new RefHolder(); + mount(buildApp({refEditor})); + assert.isDefined(await refEditor.getPromise()); + }); + describe('file header decoration positioning', function() { let wrapper; From f01deb9a1d5b39fe542156d241aae4c3d7205cde Mon Sep 17 00:00:00 2001 From: annthurium Date: Tue, 26 Feb 2019 13:49:11 -0800 Subject: [PATCH 2926/4847] respect core.commentChar in commit message templates --- lib/git-shell-out-strategy.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/git-shell-out-strategy.js b/lib/git-shell-out-strategy.js index 37b64d8307..eee64471bf 100644 --- a/lib/git-shell-out-strategy.js +++ b/lib/git-shell-out-strategy.js @@ -519,7 +519,14 @@ export default class GitShellOutStrategy { // to be consistent with command line git. const template = await this.fetchCommitMessageTemplate(); if (template) { - msg = msg.split('\n').filter(line => !line.startsWith('#')).join('\n'); + + // respecting the comment character from user settings or fall back to # as default. + // https://git-scm.com/docs/git-config#git-config-corecommentChar + let commentChar = await this.getConfig('core.commentChar'); + if (!commentChar) { + commentChar = '#'; + } + msg = msg.split('\n').filter(line => !line.startsWith(commentChar)).join('\n'); } // Determine the cleanup mode. From 10d33b9923e78cfbb181d982f51916b6b44acb74 Mon Sep 17 00:00:00 2001 From: annthurium Date: Tue, 26 Feb 2019 14:11:33 -0800 Subject: [PATCH 2927/4847] add unit test for respecting core.commentChar --- test/git-strategies.test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index ef3851b5a1..7d395883e6 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -1198,6 +1198,25 @@ import * as reporterProxy from '../lib/reporter-proxy'; // message body should not contain the template text assert.strictEqual(lastCommit.messageBody, 'neither should this one'); }); + it('respects core.commentChar from git settings when determining which comment to strip', async function() { + const workingDirPath = await cloneRepository('three-files'); + const git = createTestStrategy(workingDirPath); + const templateText = 'templates are just the best'; + + const commitMsgTemplatePath = path.join(workingDirPath, '.gitmessage'); + await fs.writeFile(commitMsgTemplatePath, templateText, {encoding: 'utf8'}); + + await git.setConfig('commit.template', commitMsgTemplatePath); + await git.setConfig('commit.cleanup', 'default'); + await git.setConfig('core.commentChar', '$'); + + const commitMessage = ['# this line should not be stripped', '$ but this one should', '', 'ch-ch-changes'].join('\n'); + await git.commit(commitMessage, {allowEmpty: true, verbatim: true}); + + const lastCommit = await git.getHeadCommit(); + assert.strictEqual(lastCommit.messageSubject, '# this line should not be stripped'); + assert.strictEqual(lastCommit.messageBody, 'ch-ch-changes'); + }); }); describe('when amend option is true', function() { From 507f686adede3d0034cd5583f747d0a11c03fbfa Mon Sep 17 00:00:00 2001 From: annthurium Date: Tue, 26 Feb 2019 14:12:39 -0800 Subject: [PATCH 2928/4847] make sure that comment char stripping hits the commit message body --- test/git-strategies.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/git-strategies.test.js b/test/git-strategies.test.js index 7d395883e6..b853a3809a 100644 --- a/test/git-strategies.test.js +++ b/test/git-strategies.test.js @@ -1190,7 +1190,7 @@ import * as reporterProxy from '../lib/reporter-proxy'; await git.setConfig('commit.template', commitMsgTemplatePath); await git.setConfig('commit.cleanup', 'default'); - const commitMessage = ['this line should not be stripped', '', 'neither should this one', templateText].join('\n'); + const commitMessage = ['this line should not be stripped', '', 'neither should this one', '', '# but this one should', templateText].join('\n'); await git.commit(commitMessage, {allowEmpty: true, verbatim: true}); const lastCommit = await git.getHeadCommit(); From 5406bf1d4b3da550836fa380e1992e0d56564fe2 Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 27 Feb 2019 15:08:16 +0900 Subject: [PATCH 2929/4847] Style suggested changes --- styles/file-patch-view.less | 30 ++++---------- styles/pr-comment.less | 82 +++++++++++++++++++++++++++++++++++++ styles/variables.less | 10 +++++ 3 files changed, 99 insertions(+), 23 deletions(-) diff --git a/styles/file-patch-view.less b/styles/file-patch-view.less index 1075c8ac3a..4a4d05d2ec 100644 --- a/styles/file-patch-view.less +++ b/styles/file-patch-view.less @@ -183,32 +183,16 @@ // Line decorations &-line { - // mixin - .hunk-line-mixin(@color) { - background-color: fade(@color, 15%); - + &--deleted { + background-color: @github-diff-deleted; &.line.cursor-line { - background-color: fade(@color, 25%); - } - } - - // light themes - & when (lightness(@syntax-background-color) >= 50) { - &--deleted { - .hunk-line-mixin( hsl(353, 100%, 55%) ); // close to .com's hsl(353, 100%, 93%) - } - &--added { - .hunk-line-mixin( hsl(133, 100%, 50%) ); // close to .com's hsl(133, 100%, 90%) + background-color: fadein(@github-diff-deleted, 3%); } } - - // dark themes - & when (lightness(@syntax-background-color) < 50) { - &--deleted { - .hunk-line-mixin( hsl(353, 100%, 65%) ); // close to .com's hsl(353, 100%, 93%) - } - &--added { - .hunk-line-mixin( hsl(133, 40%, 60%) ); // close to .com's hsl(133, 100%, 90%) + &--added { + background-color: @github-diff-added; + &.line.cursor-line { + background-color: fadein(@github-diff-added, 3%); } } } diff --git a/styles/pr-comment.less b/styles/pr-comment.less index cec3c1c8b0..1076b07343 100644 --- a/styles/pr-comment.less +++ b/styles/pr-comment.less @@ -58,4 +58,86 @@ vertical-align: middle; } + + // Suggested changes + .js-suggested-changes-blob { + font-size: .9em; + border: 1px solid @base-border-color; + border-radius: @component-border-radius; + + .d-flex { display: flex; } + .d-inline-block { display: inline-block; } + .flex-auto { flex: 1 1 auto; } + .p-1 { padding: @component-padding/2; } + .px-1 { padding-left: @component-padding/2; padding-right: @component-padding/2; } + .p-2 { padding: @component-padding; } + .text-gray { color: @text-color-subtle; } + .lh-condensed { line-height: 1.25; } + .rounded-1 { border-radius: @component-border-radius; } + .border { border: 1px solid; } + .border-bottom { border-bottom: 1px solid @base-border-color; } + .border-green { border-color: @text-color-success; } + .octicon { vertical-align: -4px; fill: currentColor; } + + .blob-wrapper > table { + width: 100%; + margin: 0; + font-family: var(--editor-font-family); + font-size: var(--editor-font-size); + line-height: var(--editor-line-height); + + td { + border: none; + padding: 0 .5em; + } + } + + .blob-num { + padding: 0 .5em; + color: @text-color-subtle; + &:before { + content: attr(data-line-number); + } + &-addition { + background-color: fadein(@github-diff-added, 10%); + } + &-deletion { + background-color: fadein(@github-diff-deleted, 10%); + } + } + + .blob-code { + &-inner { + &:before { margin-right: .5em; } + .x { + &-first { + border-bottom-left-radius: @component-border-radius; + border-top-left-radius: @component-border-radius; + } + &-last { + border-bottom-right-radius: @component-border-radius; + border-top-right-radius: @component-border-radius; + } + } + } + + &-addition { + background-color: @github-diff-added; + &:before { content: "+"; } + .x { + background-color: @github-diff-added-highlight; + } + } + + &-deletion { + background-color: @github-diff-deleted; + &:before { content: "-"; } + .x { + background-color: @github-diff-deleted-highlight; + } + } + } + + } + } diff --git a/styles/variables.less b/styles/variables.less index 4919d1e60e..86ebf431f8 100644 --- a/styles/variables.less +++ b/styles/variables.less @@ -7,3 +7,13 @@ @gh-background-color-red: #dc3545; @gh-background-color-purple: #6f42c1; @gh-background-color-green: #28a745; + + +// diff colors ----------------- +// Needs to be semi transparent make it work with selections and different themes + +@github-diff-deleted: fade(hsl(353, 100%, 66%), 15%); // similar to .com's hsl(353, 100%, 97%) +@github-diff-added: fade(hsl(137, 100%, 55%), 15%); // similar to .com's hsl(137, 100%, 95%) + +@github-diff-deleted-highlight: fade(hsl(353, 95%, 66%), 25%); // similar to .com's hsl(353, 95%, 86%) +@github-diff-added-highlight: fade(hsl(135, 73%, 55%), 25%); // similar to .com's hsl(135, 73%, 81%) From 81a2d2c6337f8de32b48947d6694bb0e3ae5444c Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 27 Feb 2019 15:36:49 +0900 Subject: [PATCH 2930/4847] :memo: typo --- styles/variables.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styles/variables.less b/styles/variables.less index 86ebf431f8..d218b8cc7d 100644 --- a/styles/variables.less +++ b/styles/variables.less @@ -10,7 +10,7 @@ // diff colors ----------------- -// Needs to be semi transparent make it work with selections and different themes +// Needs to be semi transparent to make it work with selections and different themes @github-diff-deleted: fade(hsl(353, 100%, 66%), 15%); // similar to .com's hsl(353, 100%, 97%) @github-diff-added: fade(hsl(137, 100%, 55%), 15%); // similar to .com's hsl(137, 100%, 95%) From 521fb201e442b9742259a11d5bc473311d6904d7 Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 27 Feb 2019 17:29:35 +0900 Subject: [PATCH 2931/4847] Style info tooltip --- styles/pr-comment.less | 65 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/styles/pr-comment.less b/styles/pr-comment.less index 1076b07343..77fd06db85 100644 --- a/styles/pr-comment.less +++ b/styles/pr-comment.less @@ -138,6 +138,71 @@ } } + // These styles are mostly copied from the Primer tooltips + .tooltipped { + position: relative; + + // This is the tooltip bubble + &::after { + position: absolute; + z-index: 1000000; + display: none; + width: max-content; + max-width: 22em; + padding: .5em .6em; + font-weight: 500; + color: @base-background-color; + text-align: center; + pointer-events: none; + content: attr(aria-label); + background: @background-color-info; + border-radius: @component-border-radius; + } + + // This is the tooltip arrow + &::before { + position: absolute; + z-index: 1000001; + display: none; + width: 0; + height: 0; + color: @background-color-info; + pointer-events: none; + content: ""; + border: 6px solid transparent; + } + + // This will indicate when we'll activate the tooltip + &:hover, + &:active, + &:focus { + &::before, + &::after { + display: inline-block; + text-decoration: none; + } + } + + // Tooltipped south + &::after { + top: 100%; + right: 50%; + margin-top: 6px; + } + &::before { + top: auto; + right: 50%; + bottom: -7px; + margin-right: -6px; + border-bottom-color: @background-color-info; + } + + // Move the tooltip body to the center of the object. + &::after { + transform: translateX(50%); + } + } + } } From e758dc6fbd31f8ee74b84a6490c0d21e0ab3b041 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Wed, 27 Feb 2019 18:11:52 +0800 Subject: [PATCH 2932/4847] add test for unsub --- test/containers/pr-changed-files-container.test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/containers/pr-changed-files-container.test.js b/test/containers/pr-changed-files-container.test.js index 47896dcfb4..70cf28333a 100644 --- a/test/containers/pr-changed-files-container.test.js +++ b/test/containers/pr-changed-files-container.test.js @@ -115,6 +115,17 @@ describe('PullRequestChangedFilesContainer', function() { assert.isTrue(wrapper.instance().state.isLoading); await assert.async.strictEqual(window.fetch.callCount, 2); }); + it('disposes MFP subscription on unmount', async function() { + const wrapper = shallow(buildApp()); + await assert.async.isTrue(wrapper.update().find('MultiFilePatchController').exists()); + + const mfp = wrapper.find('MultiFilePatchController').prop('multiFilePatch'); + const [fp] = mfp.getFilePatches(); + assert.strictEqual(fp.emitter.listenerCountForEventName('change-render-status'), 1); + + wrapper.unmount(); + assert.strictEqual(fp.emitter.listenerCountForEventName('change-render-status'), 0); + }); }); describe('error states', function() { From f4954a795511be7a27a24f3f9d66a19b54443b51 Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 27 Feb 2019 20:15:17 +0900 Subject: [PATCH 2933/4847] Fix margins --- styles/github-dotcom-markdown.less | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/styles/github-dotcom-markdown.less b/styles/github-dotcom-markdown.less index d076f884d3..67f8e0e8f0 100644 --- a/styles/github-dotcom-markdown.less +++ b/styles/github-dotcom-markdown.less @@ -2,7 +2,7 @@ // This styles Markdown used in issueish panes. -@margin: 1.5em; +@margin: 1em; .github-DotComMarkdownHtml { @@ -179,4 +179,8 @@ color: @text-color-subtle; // same as .cross-referenced-event-label-number } + .js-suggested-changes-blob { // gets used for suggested changes + margin: @margin 0; + } + } From e456400d7d804de5143c37f0e20b1f0566463e90 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 27 Feb 2019 12:16:42 +0000 Subject: [PATCH 2934/4847] chore(package): update sinon to version 7.2.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 13e84b5618..3bce85d377 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "nyc": "13.3.0", "relay-compiler": "3.0.0", "semver": "5.6.0", - "sinon": "7.2.4", + "sinon": "7.2.5", "test-until": "1.1.1" }, "consumedServices": { From 76a54d0fa0086bb15bb1572e21aacb7ef45874da Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 27 Feb 2019 12:16:47 +0000 Subject: [PATCH 2935/4847] chore(package): update lockfile package-lock.json --- package-lock.json | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9b0775d449..2496c48f57 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1265,22 +1265,14 @@ } }, "@sinonjs/samsam": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.1.1.tgz", - "integrity": "sha512-ILlwvQUwAiaVBzr3qz8oT1moM7AIUHqUc2UmEjQcH9lLe+E+BZPwUMuc9FFojMswRK4r96x5zDTTrowMLw/vuA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.2.0.tgz", + "integrity": "sha512-j5F1rScewLtx6pbTK0UAjA3jJj4RYiSKOix53YWv+Jzy/AZ69qHxUpU8fwVLjyKbEEud9QrLpv6Ggs7WqTimYw==", "dev": true, "requires": { "@sinonjs/commons": "^1.0.2", "array-from": "^2.1.1", "lodash": "^4.17.11" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - } } }, "@sinonjs/text-encoding": { @@ -8049,14 +8041,14 @@ } }, "sinon": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.2.4.tgz", - "integrity": "sha512-FGlcfrkiBRfaEIKRw8s/9mk4nP4AMGswvKFixLo+AzsOhskjaBCHAHGLMd8pCJpQGS+9ZI71px6qoQUyvADeyA==", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.2.5.tgz", + "integrity": "sha512-1c2KK6g5NQr9XNYCEcUbeFtBpKZD1FXEw0VX7gNhWUBtkchguT2lNdS7XmS7y64OpQWfSNeeV/f8py3NNcQ63Q==", "dev": true, "requires": { "@sinonjs/commons": "^1.3.0", "@sinonjs/formatio": "^3.1.0", - "@sinonjs/samsam": "^3.1.1", + "@sinonjs/samsam": "^3.2.0", "diff": "^3.5.0", "lolex": "^3.1.0", "nise": "^1.4.10", From fafc766e035da60314f3c9a8184f2c619a45b090 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Feb 2019 12:05:28 -0500 Subject: [PATCH 2936/4847] Use @atom/mocha-test-runner instead of my fork --- package-lock.json | 1005 ++++++++++++++++++++++++++++++++++----------- package.json | 4 +- 2 files changed, 770 insertions(+), 239 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2496c48f57..4944fe8e6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,69 @@ "@babel/core": "7.x" } }, + "@atom/mocha-test-runner": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@atom/mocha-test-runner/-/mocha-test-runner-1.5.0.tgz", + "integrity": "sha512-Ctyw49G4rHv7v8YNyP01YyW1lPyMskv/gR6cxDsR+NDYSlpH8th07LTZDoESynhfLEYBuje0oYIrlosLvNPQ6g==", + "dev": true, + "requires": { + "diff": "4.0.1", + "etch": "0.14.0", + "grim": "^2.0.1", + "klaw-sync": "6.0.0", + "less": "3.9.0", + "mocha": "6.0.2", + "temp": "0.9.0", + "tmp": "0.0.33" + }, + "dependencies": { + "diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "dev": true + }, + "etch": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/etch/-/etch-0.14.0.tgz", + "integrity": "sha512-puqbFxz7lSm+YK6Q+bvRkNndRv6PRvGscSEhcFjmtL4nX/Az5rRCNPvK3aVTde85c/L5X0vI5kqfnpYddRalJQ==", + "dev": true + }, + "less": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz", + "integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==", + "dev": true, + "requires": { + "clone": "^2.1.2", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.4.1", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", + "request": "^2.83.0", + "source-map": "~0.6.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + } + } + }, "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", @@ -1281,20 +1344,6 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, - "@smashwilson/atom-mocha-test-runner": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@smashwilson/atom-mocha-test-runner/-/atom-mocha-test-runner-1.4.0.tgz", - "integrity": "sha512-Zp50XTy2QZEk53PUxXQ1kLTAkSwEuM2X7JXtMGLRWuU68piFghkXGaopTrjXK3CwgzmmFi26m65sTCrXg3zqbg==", - "dev": true, - "requires": { - "diff": "3.5.0", - "etch": "^0.8.0", - "grim": "^2.0.1", - "less": "^3.7.1", - "mocha": "^5.2.0", - "tmp": "0.0.31" - } - }, "@types/node": { "version": "10.12.12", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.12.tgz", @@ -1343,6 +1392,12 @@ "json-schema-traverse": "^0.3.0" } }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, "ansi-escapes": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", @@ -1975,16 +2030,10 @@ } } }, - "browser-split": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/browser-split/-/browser-split-0.0.1.tgz", - "integrity": "sha1-ewl1dPjj6tYG+0Zk5krf3aKYGpM=", - "dev": true - }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha1-uqVZ7hTO1zRSIputcyZGfGH6vWA=", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, "browserslist": { @@ -2118,12 +2167,6 @@ } } }, - "camelize": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", - "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=", - "dev": true - }, "caniuse-lite": { "version": "1.0.30000939", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000939.tgz", @@ -2670,6 +2713,12 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, "detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -2749,12 +2798,6 @@ } } }, - "dom-walk": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", - "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=", - "dev": true - }, "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", @@ -3133,17 +3176,6 @@ "prr": "~1.0.1" } }, - "error": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/error/-/error-4.4.0.tgz", - "integrity": "sha1-v2n/JR+0onnBmtzNqmth6Q2b8So=", - "dev": true, - "requires": { - "camelize": "^1.0.0", - "string-template": "~0.2.0", - "xtend": "~4.0.0" - } - }, "error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", @@ -3517,24 +3549,6 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, - "etch": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/etch/-/etch-0.8.0.tgz", - "integrity": "sha1-VPYZV0NG+KPueXP1T7vQG1YnItY=", - "dev": true, - "requires": { - "virtual-dom": "^2.0.1" - } - }, - "ev-store": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/ev-store/-/ev-store-7.0.0.tgz", - "integrity": "sha1-GrDH+CE2UF3XSzHRdwHLK+bSZVg=", - "dev": true, - "requires": { - "individual": "^3.0.0" - } - }, "event-kit": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.3.tgz", @@ -3596,6 +3610,15 @@ "integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==", "dev": true }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", @@ -3867,6 +3890,46 @@ "locate-path": "^2.0.0" } }, + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "dev": true + } + } + }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -4106,14 +4169,28 @@ "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", "dev": true }, - "global": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", - "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "dev": true, "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" } }, "globals": { @@ -4269,9 +4346,9 @@ } }, "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, "hock": { @@ -4284,6 +4361,15 @@ "url-equal": "0.1.2-1" } }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, "hosted-git-info": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", @@ -4424,12 +4510,6 @@ "repeating": "^2.0.0" } }, - "individual": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/individual/-/individual-3.0.0.tgz", - "integrity": "sha1-58pPhfiVewGHNPKFdQ3CLsL5hi0=", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4702,12 +4782,6 @@ "integrity": "sha1-8mWrian0RQNO9q/xWo8AsA9VF5k=", "dev": true }, - "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", - "dev": true - }, "is-odd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", @@ -4967,6 +5041,15 @@ "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", "dev": true }, + "klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11" + } + }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -4976,32 +5059,6 @@ "invert-kv": "^1.0.0" } }, - "less": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/less/-/less-3.8.1.tgz", - "integrity": "sha512-8HFGuWmL3FhQR0aH89escFNBQH/nEiYPP2ltDFdQw2chE28Yx2E3lhAIq9Y2saYwLSwa699s4dBVEfCY8Drf7Q==", - "dev": true, - "requires": { - "clone": "^2.1.2", - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "mime": "^1.4.1", - "mkdirp": "^0.5.0", - "promise": "^7.1.1", - "request": "^2.83.0", - "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } - } - }, "level-codec": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-9.0.0.tgz", @@ -5161,6 +5218,46 @@ "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "lolex": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lolex/-/lolex-3.1.0.tgz", @@ -5203,6 +5300,15 @@ } } }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -5395,15 +5501,6 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" }, - "min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "dev": true, - "requires": { - "dom-walk": "^0.1.0" - } - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -5478,55 +5575,34 @@ } }, "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.0.2.tgz", + "integrity": "sha512-RtTJsmmToGyeTznSOMoM6TPEk1A84FQaHIciKrRqARZx+B5ccJ5tXlmJzEKGBxZdqk9UjpRsesZTUkZmR5YnuQ==", "dev": true, "requires": { + "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", + "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", - "glob": "7.1.2", + "findup-sync": "2.0.0", + "glob": "7.1.3", "growl": "1.10.5", - "he": "1.1.1", + "he": "1.2.0", + "js-yaml": "3.12.0", + "log-symbols": "2.2.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", - "supports-color": "5.4.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "mocha-junit-reporter": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/mocha-junit-reporter/-/mocha-junit-reporter-1.18.0.tgz", - "integrity": "sha512-y3XuqKa2+HRYtg0wYyhW/XsLm2Ps+pqf9HaTAt7+MVUAKFJaNAHOrNseTZo9KCxjfIbxUWwckP5qCDDPUmjSWA==", - "dev": true, - "requires": { - "debug": "^2.2.0", - "md5": "^2.1.0", - "mkdirp": "~0.5.1", - "strip-ansi": "^4.0.0", - "xml": "^1.0.0" + "ms": "2.1.1", + "node-environment-flags": "1.0.4", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "12.0.5", + "yargs-parser": "11.1.1", + "yargs-unparser": "1.5.0" }, "dependencies": { "ansi-regex": { @@ -5535,34 +5611,295 @@ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" } - } - } - }, - "mocha-multi-reporters": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/mocha-multi-reporters/-/mocha-multi-reporters-1.1.7.tgz", - "integrity": "sha1-zH8/TTL0eFIJQdhSq7ZNmYhYfYI=", - "dev": true, - "requires": { - "debug": "^3.1.0", - "lodash": "^4.16.4" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "ms": "2.0.0" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", + "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^2.0.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "mocha-junit-reporter": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/mocha-junit-reporter/-/mocha-junit-reporter-1.18.0.tgz", + "integrity": "sha512-y3XuqKa2+HRYtg0wYyhW/XsLm2Ps+pqf9HaTAt7+MVUAKFJaNAHOrNseTZo9KCxjfIbxUWwckP5qCDDPUmjSWA==", + "dev": true, + "requires": { + "debug": "^2.2.0", + "md5": "^2.1.0", + "mkdirp": "~0.5.1", + "strip-ansi": "^4.0.0", + "xml": "^1.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "mocha-multi-reporters": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/mocha-multi-reporters/-/mocha-multi-reporters-1.1.7.tgz", + "integrity": "sha1-zH8/TTL0eFIJQdhSq7ZNmYhYfYI=", + "dev": true, + "requires": { + "debug": "^3.1.0", + "lodash": "^4.16.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" } } } @@ -5655,12 +5992,6 @@ "semver": "^5.4.1" } }, - "next-tick": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-0.2.2.tgz", - "integrity": "sha1-ddpKkn7liH45BliABltzNkE7MQ0=", - "dev": true - }, "nice-try": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", @@ -5705,6 +6036,15 @@ "lodash.toarray": "^4.4.0" } }, + "node-environment-flags": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.4.tgz", + "integrity": "sha512-M9rwCnWVLW7PX+NUWe3ejEdiLYinRpsEre9hMkU/6NS4h+EEulYaDH1gCEZ2gyXsmw+RXYDaV2JkkTNcsPDJ0Q==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, "node-fetch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", @@ -6948,6 +7288,16 @@ "has": "^1.0.1" } }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -7038,12 +7388,24 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, + "p-is-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", + "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", + "dev": true + }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -7086,6 +7448,12 @@ "error-ex": "^1.2.0" } }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, "parse5": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", @@ -7256,12 +7624,6 @@ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=" }, - "process": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", - "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=", - "dev": true - }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", @@ -7846,6 +8208,16 @@ "path-parse": "^1.0.6" } }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -8337,12 +8709,6 @@ } } }, - "string-template": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", - "dev": true - }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -8799,15 +9165,6 @@ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" }, - "tmp": { - "version": "0.0.31", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", - "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.1" - } - }, "to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", @@ -9156,22 +9513,6 @@ "extsprintf": "^1.2.0" } }, - "virtual-dom": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/virtual-dom/-/virtual-dom-2.1.1.tgz", - "integrity": "sha1-gO2i1IG57eDASRGM78tKBfIdE3U=", - "dev": true, - "requires": { - "browser-split": "0.0.1", - "error": "^4.3.0", - "ev-store": "^7.0.0", - "global": "^4.3.0", - "is-object": "^1.0.1", - "next-tick": "^0.2.2", - "x-is-array": "0.1.0", - "x-is-string": "0.1.0" - } - }, "what-the-diff": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/what-the-diff/-/what-the-diff-0.5.0.tgz", @@ -9260,18 +9601,6 @@ "mkdirp": "^0.5.1" } }, - "x-is-array": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/x-is-array/-/x-is-array-0.1.0.tgz", - "integrity": "sha1-3lIBcdR7P0FvVYfWKbidJrEtwp0=", - "dev": true - }, - "x-is-string": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", - "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", - "dev": true - }, "xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", @@ -9324,6 +9653,208 @@ "camelcase": "^4.1.0" } }, + "yargs-unparser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", + "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.11", + "yargs": "^12.0.5" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", + "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^2.0.0" + } + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, "yauzl": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", diff --git a/package.json b/package.json index 3bce85d377..5cca104dbc 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "yubikiri": "1.0.0" }, "devDependencies": { - "@smashwilson/atom-mocha-test-runner": "1.4.0", + "@atom/mocha-test-runner": "1.5.0", "babel-plugin-istanbul": "5.1.1", "chai": "4.2.0", "chai-as-promised": "7.1.1", @@ -95,7 +95,7 @@ "hock": "1.3.3", "lodash.isequalwith": "4.4.0", "mkdirp": "0.5.1", - "mocha": "5.2.0", + "mocha": "6.0.2", "mocha-junit-reporter": "1.18.0", "mocha-multi-reporters": "1.1.7", "mocha-stress": "1.0.0", From 641164dfed5142c39b0a865ae3aebc6524aa815e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Feb 2019 12:05:40 -0500 Subject: [PATCH 2937/4847] Correct the import --- test/runner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runner.js b/test/runner.js index 431f8f4036..af37ac161a 100644 --- a/test/runner.js +++ b/test/runner.js @@ -1,4 +1,4 @@ -import {createRunner} from '@smashwilson/atom-mocha-test-runner'; +import {createRunner} from '@atom/mocha-test-runner'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; import path from 'path'; From c2041e1f38e45b3eb6cd751fc7acfe8de8c79a14 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Feb 2019 13:27:19 -0500 Subject: [PATCH 2938/4847] Regenerate package-lock --- package-lock.json | 3786 +++++++++++++++------------------------------ 1 file changed, 1238 insertions(+), 2548 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4944fe8e6a..b0dc9c9763 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,53 +40,6 @@ "mocha": "6.0.2", "temp": "0.9.0", "tmp": "0.0.33" - }, - "dependencies": { - "diff": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", - "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", - "dev": true - }, - "etch": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/etch/-/etch-0.14.0.tgz", - "integrity": "sha512-puqbFxz7lSm+YK6Q+bvRkNndRv6PRvGscSEhcFjmtL4nX/Az5rRCNPvK3aVTde85c/L5X0vI5kqfnpYddRalJQ==", - "dev": true - }, - "less": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz", - "integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==", - "dev": true, - "requires": { - "clone": "^2.1.2", - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "mime": "^1.4.1", - "mkdirp": "^0.5.0", - "promise": "^7.1.1", - "request": "^2.83.0", - "source-map": "~0.6.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - } } }, "@babel/code-frame": { @@ -116,62 +69,6 @@ "resolve": "^1.3.2", "semver": "^5.4.1", "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/parser": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", - "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==" - }, - "@babel/traverse": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", - "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.3.4", - "@babel/types": "^7.3.4", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.11" - } - }, - "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==" - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } } }, "@babel/generator": { @@ -184,23 +81,6 @@ "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } } }, "@babel/helper-annotate-as-pure": { @@ -227,23 +107,6 @@ "requires": { "@babel/types": "^7.3.0", "esutils": "^2.0.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.3.tgz", - "integrity": "sha512-2tACZ80Wg09UnPg5uGAOUvvInaqLk3l/IAhQzlxLQOIXacr6bMsra5SH6AWw/hIDRCSbCdHP2KzSOD+cT7TzMQ==", - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } } }, "@babel/helper-call-delegate": { @@ -267,73 +130,6 @@ "@babel/helper-plugin-utils": "^7.0.0", "@babel/helper-replace-supers": "^7.3.4", "@babel/helper-split-export-declaration": "^7.0.0" - }, - "dependencies": { - "@babel/helper-replace-supers": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz", - "integrity": "sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A==", - "requires": { - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.3.4", - "@babel/types": "^7.3.4" - } - }, - "@babel/parser": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", - "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==" - }, - "@babel/traverse": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", - "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.3.4", - "@babel/types": "^7.3.4", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.11" - } - }, - "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==" - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } } }, "@babel/helper-define-map": { @@ -344,13 +140,6 @@ "@babel/helper-function-name": "^7.1.0", "@babel/types": "^7.0.0", "lodash": "^4.17.10" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } } }, "@babel/helper-explode-assignable-expression": { @@ -415,13 +204,6 @@ "@babel/template": "^7.2.2", "@babel/types": "^7.2.2", "lodash": "^4.17.10" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } } }, "@babel/helper-optimise-call-expression": { @@ -443,13 +225,6 @@ "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", "requires": { "lodash": "^4.17.10" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } } }, "@babel/helper-remap-async-to-generator": { @@ -465,14 +240,14 @@ } }, "@babel/helper-replace-supers": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz", - "integrity": "sha512-GyieIznGUfPXPWu0yLS6U55Mz67AZD9cUk0BfirOWlPrXlBcan9Gz+vHGz+cPfuoweZSnPzPIm67VtQM0OWZbA==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz", + "integrity": "sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A==", "requires": { "@babel/helper-member-expression-to-functions": "^7.0.0", "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.2.3", - "@babel/types": "^7.0.0" + "@babel/traverse": "^7.3.4", + "@babel/types": "^7.3.4" } }, "@babel/helper-simple-access": { @@ -511,23 +286,6 @@ "@babel/template": "^7.1.2", "@babel/traverse": "^7.1.5", "@babel/types": "^7.3.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } } }, "@babel/highlight": { @@ -538,45 +296,12 @@ "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } } }, "@babel/parser": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.2.3.tgz", - "integrity": "sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA==" + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", + "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==" }, "@babel/plugin-proposal-async-generator-functions": { "version": "7.2.0", @@ -719,45 +444,27 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.2.0.tgz", - "integrity": "sha512-vDTgf19ZEV6mx35yiPJe4fS02mPQUUcBNwWQSZFXSzTSbsJFQvHt7DqyS3LK8oOWALFOsJ+8bbqBgkirZteD5Q==", - "dev": true, + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.3.4.tgz", + "integrity": "sha512-blRr2O8IOZLAOJklXLV4WhcEzpYafYQKSGT3+R26lWG41u/FODJuBggehtOwilVAcFu393v3OFj+HmaE6tVjhA==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.10" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - } + "lodash": "^4.17.11" } }, "@babel/plugin-transform-classes": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.3.tgz", - "integrity": "sha512-n0CLbsg7KOXsMF4tSTLCApNMoXk0wOPb0DYfsOO1e7SfIb9gOyfbpKI2MZ+AXfqvlfzq2qsflJ1nEns48Caf2w==", - "dev": true, + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.4.tgz", + "integrity": "sha512-J9fAvCFBkXEvBimgYxCjvaVDzL6thk0j0dBvCeZmIUDBwyt+nv6HfbImsSrWsYXfDNDivyANgJlFXDUWRTZBuA==", "requires": { "@babel/helper-annotate-as-pure": "^7.0.0", "@babel/helper-define-map": "^7.1.0", "@babel/helper-function-name": "^7.1.0", "@babel/helper-optimise-call-expression": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", + "@babel/helper-replace-supers": "^7.3.4", "@babel/helper-split-export-declaration": "^7.0.0", "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", - "dev": true - } } }, "@babel/plugin-transform-computed-properties": { @@ -804,9 +511,9 @@ } }, "@babel/plugin-transform-flow-strip-types": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.2.3.tgz", - "integrity": "sha512-xnt7UIk9GYZRitqCnsVMjQK1O2eKZwFB3CvvHjf5SGx6K6vr/MScCKQDnf1DxRaj501e3pXjti+inbSXX2ZUoQ==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.3.4.tgz", + "integrity": "sha512-PmQC9R7DwpBFA+7ATKMyzViz3zCaMNouzZMPZN2K5PnbBbtL3AXFYTkDk+Hey5crQq2A90UG5Uthz0mel+XZrA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -1032,20 +739,6 @@ "requires": { "core-js": "^2.5.7", "regenerator-runtime": "^0.12.0" - }, - "dependencies": { - "core-js": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", - "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", - "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", - "dev": true - } } }, "@babel/preset-env": { @@ -1096,106 +789,6 @@ "invariant": "^2.2.2", "js-levenshtein": "^1.1.3", "semver": "^5.3.0" - }, - "dependencies": { - "@babel/helper-replace-supers": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz", - "integrity": "sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A==", - "requires": { - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.3.4", - "@babel/types": "^7.3.4" - } - }, - "@babel/parser": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", - "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==" - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.4.tgz", - "integrity": "sha512-j7VQmbbkA+qrzNqbKHrBsW3ddFnOeva6wzSe/zB7T+xaxGc+RCpwo44wCmRixAIGRoIpmVgvzFzNJqQcO3/9RA==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.3.4.tgz", - "integrity": "sha512-blRr2O8IOZLAOJklXLV4WhcEzpYafYQKSGT3+R26lWG41u/FODJuBggehtOwilVAcFu393v3OFj+HmaE6tVjhA==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.11" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.4.tgz", - "integrity": "sha512-J9fAvCFBkXEvBimgYxCjvaVDzL6thk0j0dBvCeZmIUDBwyt+nv6HfbImsSrWsYXfDNDivyANgJlFXDUWRTZBuA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.1.0", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.3.4", - "@babel/helper-split-export-declaration": "^7.0.0", - "globals": "^11.1.0" - } - }, - "@babel/traverse": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", - "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.3.4", - "@babel/types": "^7.3.4", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.11" - } - }, - "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==" - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } } }, "@babel/preset-react": { @@ -1211,18 +804,11 @@ } }, "@babel/runtime": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz", - "integrity": "sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.4.tgz", + "integrity": "sha512-IvfvnMdSaLBateu0jfsYIpZTxAc2cKEXEMiezGGN75QcBcecDUKd3PgLAncT0oOgxKy8dd8hrJKj9MfzgfZd6g==", "requires": { "regenerator-runtime": "^0.12.0" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", - "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" - } } }, "@babel/template": { @@ -1236,61 +822,29 @@ } }, "@babel/traverse": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", - "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.2", + "@babel/generator": "^7.3.4", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.2.3", - "@babel/types": "^7.2.2", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.10" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "globals": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", - "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==" - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } + "lodash": "^4.17.11" } }, "@babel/types": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.2.2.tgz", - "integrity": "sha512-fKCuD6UFUMkR541eDWL+2ih/xFZBXPOg/7EQFeTluMDebfqR4jrpaCjLhkWlQS4hT6nRa2PMEgXKbRB5/H2fpg==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - } } }, "@mrmlnc/readdir-enhanced": { @@ -1345,9 +899,9 @@ "dev": true }, "@types/node": { - "version": "10.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.12.tgz", - "integrity": "sha512-Pr+6JRiKkfsFvmU/LK68oBRCQeEg36TyAbPhc2xpez24OOZZCuoIhWGTd39VZy6nGafSbxzGouFPTFD/rR1A0A==", + "version": "11.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.5.tgz", + "integrity": "sha512-vVjM0SVzgaOUpflq4GYBvCpozes8OgIIS5gVXVka+OfK3hvnkC1i93U8WiY2OtNE4XUWyyy/86Kf6e0IHTQw1Q==", "dev": true }, "abstract-leveldown": { @@ -1360,9 +914,9 @@ } }, "acorn": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.0.tgz", - "integrity": "sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", "dev": true }, "acorn-jsx": { @@ -1381,15 +935,14 @@ } }, "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz", + "integrity": "sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg==", "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", + "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "ansi-colors": { @@ -1410,15 +963,17 @@ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=" + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "are-we-there-yet": { "version": "1.1.5", @@ -1462,7 +1017,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, "arr-union": { @@ -1547,9 +1102,12 @@ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } }, "assert-plus": { "version": "1.0.0", @@ -1602,9 +1160,9 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "atob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, "aws-sign2": { @@ -1613,10 +1171,9 @@ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha1-1NDpudv8p3vwjusKikcVUP454ok=", - "dev": true + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "axobject-query": { "version": "2.0.2", @@ -1636,9 +1193,42 @@ "chalk": "^1.1.3", "esutils": "^2.0.2", "js-tokens": "^3.0.2" - } - }, - "babel-eslint": { + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-eslint": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-7.2.3.tgz", "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=", @@ -1668,51 +1258,6 @@ "find-up": "^3.0.0", "istanbul-lib-instrument": "^3.0.0", "test-exclude": "^5.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", - "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", - "dev": true - } } }, "babel-plugin-macros": { @@ -1774,13 +1319,21 @@ } }, "babel-runtime": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.25.0.tgz", - "integrity": "sha1-M7mOql1IK7AajRqmtDetKwGuxBw=", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { "core-js": "^2.4.0", - "regenerator-runtime": "^0.10.0" + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + } } }, "babel-traverse": { @@ -1800,58 +1353,39 @@ "lodash": "^4.17.4" }, "dependencies": { - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "ms": "2.0.0" } }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } } }, "babel-types": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", - "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", + "babel-runtime": "^6.26.0", "esutils": "^2.0.2", - "lodash": "^4.2.0", - "to-fast-properties": "^1.0.1" + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" }, "dependencies": { "to-fast-properties": { @@ -1863,9 +1397,9 @@ } }, "babylon": { - "version": "6.17.4", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz", - "integrity": "sha512-kChlV+0SXkjE0vUn9OZ7pBMWRFd8uq3mZe8x1K6jhuNcAFAtEnjchFAqB+dYEXKyd+JpT6eppRR78QAr5gTsUw==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "dev": true }, "balanced-match": { @@ -1876,7 +1410,7 @@ "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { "cache-base": "^1.0.1", @@ -1929,10 +1463,9 @@ } }, "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "requires": { "tweetnacl": "^0.14.3" } @@ -1951,39 +1484,10 @@ "bl": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha1-oWCRFxcQPAdBDO9j71Gzl8Alr5w=", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } } }, "boolbase": { @@ -1993,9 +1497,9 @@ "dev": true }, "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2080,12 +1584,6 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -2094,7 +1592,7 @@ "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { "collection-visit": "^1.0.0", @@ -2120,13 +1618,6 @@ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", "requires": { "callsites": "^2.0.0" - }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" - } } }, "caller-path": { @@ -2138,15 +1629,14 @@ } }, "callsites": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", - "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" }, "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", "dev": true }, "camelcase-keys": { @@ -2194,23 +1684,20 @@ "chai-as-promised": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", - "integrity": "sha1-CGRdgl3rhpbuYXJdv1kMAS6wDKA=", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", "dev": true, "requires": { "check-error": "^1.0.2" } }, "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "chardet": { @@ -2254,14 +1741,14 @@ } }, "chownr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -2302,25 +1789,45 @@ "dev": true }, "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", "wrap-ansi": "^2.0.0" }, "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -2331,12 +1838,6 @@ "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", "dev": true }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -2378,24 +1879,18 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, - "colors": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", - "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=", - "dev": true - }, "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "requires": { "delayed-stream": "~1.0.0" } }, "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", "dev": true }, "compare-sets": { @@ -2446,9 +1941,9 @@ "dev": true }, "core-js": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.0.tgz", - "integrity": "sha1-VpwFCRi+ZIazg3VSAorgRmtxcIY=" + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", + "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==" }, "core-util-is": { "version": "1.0.2", @@ -2465,31 +1960,6 @@ "js-yaml": "^3.9.0", "lodash.get": "^4.4.2", "parse-json": "^4.0.0" - }, - "dependencies": { - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" - } } }, "cross-env": { @@ -2500,30 +1970,17 @@ "requires": { "cross-spawn": "^6.0.5", "is-windows": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - } } }, "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "lru-cache": "^4.0.1", + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" } @@ -2553,9 +2010,9 @@ } }, "css-what": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.2.tgz", - "integrity": "sha512-wan8dMWQ0GUeF7DGEPVjhHemVW/vy6xUYmFzRY8RYqgA0JtXC9rJmbScBjqSu6dg9q0lwPQy6ZAmJVr3PPTvqQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", "dev": true }, "currently-unhandled": { @@ -2582,12 +2039,11 @@ } }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "decamelize": { @@ -2653,19 +2109,18 @@ } }, "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" + "object-keys": "^1.0.12" } }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { "is-descriptor": "^1.0.2", @@ -2725,9 +2180,9 @@ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" }, "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", "dev": true }, "dir-glob": { @@ -2737,23 +2192,6 @@ "dev": true, "requires": { "path-type": "^3.0.0" - }, - "dependencies": { - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } } }, "discontinuous-range": { @@ -2763,39 +2201,22 @@ "dev": true }, "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } + "esutils": "^2.0.2" } }, "dom-serializer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", "dev": true, "requires": { - "domelementtype": "~1.1.1", - "entities": "~1.1.1" - }, - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", - "dev": true - } + "domelementtype": "^1.3.0", + "entities": "^1.1.1" } }, "domelementtype": { @@ -2834,126 +2255,15 @@ "request": "^2.88.0", "rimraf": "^2.5.4", "tar": "^4.4.7" - }, - "dependencies": { - "ajv": { - "version": "6.9.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz", - "integrity": "sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg==", - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "mime-db": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", - "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" - }, - "mime-types": { - "version": "2.1.22", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", - "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", - "requires": { - "mime-db": "~1.38.0" - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - } } }, "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "requires": { - "jsbn": "~0.1.0" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "electron-devtools-installer": { @@ -3001,12 +2311,6 @@ "requires": { "ms": "^2.1.1" } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true } } }, @@ -3024,14 +2328,6 @@ "recast": "^0.12.6", "resolve": "^1.5.0", "source-map": "^0.5.6" - }, - "dependencies": { - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - } } }, "electron-mksnapshot": { @@ -3079,7 +2375,7 @@ "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "requires": { "once": "^1.4.0" } @@ -3121,23 +2417,6 @@ "raf": "^3.4.0", "rst-selector-parser": "^2.2.3", "string.prototype.trim": "^1.1.2" - }, - "dependencies": { - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - } } }, "enzyme-adapter-react-16": { @@ -3156,13 +2435,14 @@ } }, "enzyme-adapter-utils": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.9.0.tgz", - "integrity": "sha512-uMe4xw4l/Iloh2Fz+EO23XUYMEQXj5k/5ioLUXCNOUCI8Dml5XQMO9+QwUq962hBsY5qftfHHns+d990byWHvg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.10.0.tgz", + "integrity": "sha512-VnIXJDYVTzKGbdW+lgK8MQmYHJquTQZiGzu/AseCZ7eHtOMAj4Rtvk8ZRopodkfPves0EXaHkXBDkVhPa3t0jA==", "dev": true, "requires": { "function.prototype.name": "^1.1.0", "object.assign": "^4.1.0", + "object.fromentries": "^2.0.0", "prop-types": "^15.6.2", "semver": "^5.6.0" } @@ -3177,46 +2457,47 @@ } }, "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "requires": { "is-arrayish": "^0.2.1" } }, "es-abstract": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.11.0.tgz", - "integrity": "sha1-zOh9UY8Elok7GjDNhGGDVTVIBoE=", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", + "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" } }, "es-to-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", - "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "dev": true, "requires": { - "is-callable": "^1.1.1", + "is-callable": "^1.1.4", "is-date-object": "^1.0.1", - "is-symbol": "^1.0.1" + "is-symbol": "^1.0.2" } }, "es6-promise": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", - "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", + "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==", "dev": true }, "es6-promisify": { "version": "5.0.0", - "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "dev": true, "requires": { @@ -3272,103 +2553,26 @@ "text-table": "^0.2.0" }, "dependencies": { - "ajv": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", - "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "doctrine": { + "import-fresh": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", + "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", "dev": true, "requires": { - "esutils": "^2.0.2" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" } }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "strip-ansi": { @@ -3379,15 +2583,6 @@ "requires": { "ansi-regex": "^3.0.0" } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -3413,18 +2608,18 @@ "dev": true }, "eslint-plugin-flowtype": { - "version": "2.46.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.46.3.tgz", - "integrity": "sha1-foQTHYfvGLSWsYEESFkzdIYLTo4=", + "version": "2.50.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.50.3.tgz", + "integrity": "sha512-X+AoKVOr7Re0ko/yEXyM5SSZ0tazc6ffdIOocp2fFUlWoDt7DV0Bz99mngOkAFLOAWjqRA5jPwqUCbrx13XoxQ==", "dev": true, "requires": { - "lodash": "^4.15.0" + "lodash": "^4.17.10" } }, "eslint-plugin-jasmine": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jasmine/-/eslint-plugin-jasmine-2.9.3.tgz", - "integrity": "sha1-Bb86uCfXkWkc7ujCGVm5wNVqaww=", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jasmine/-/eslint-plugin-jasmine-2.10.1.tgz", + "integrity": "sha1-VzO3CedR9LxA4x4cFpib0s377Jc=", "dev": true }, "eslint-plugin-jsx-a11y": { @@ -3443,15 +2638,6 @@ "jsx-ast-utils": "^2.0.1" }, "dependencies": { - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, "jsx-ast-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", @@ -3480,6 +2666,18 @@ "has": "^1.0.1", "jsx-ast-utils": "^1.3.4", "object.assign": "^4.0.4" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + } } }, "eslint-scope": { @@ -3516,9 +2714,9 @@ } }, "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esquery": { "version": "1.0.1", @@ -3549,19 +2747,25 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "etch": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/etch/-/etch-0.14.0.tgz", + "integrity": "sha512-puqbFxz7lSm+YK6Q+bvRkNndRv6PRvGscSEhcFjmtL4nX/Az5rRCNPvK3aVTde85c/L5X0vI5kqfnpYddRalJQ==", + "dev": true + }, "event-kit": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.3.tgz", "integrity": "sha512-b7Qi1JNzY4BfAYfnIRanLk0DOD1gdkWHT4GISIn8Q2tAf3LpU8SP2CMwWaq40imYoKWbtN4ZhbSRxvsnikooZQ==" }, "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", @@ -3584,6 +2788,15 @@ "to-regex": "^3.0.1" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", @@ -3601,14 +2814,19 @@ "requires": { "is-extendable": "^0.1.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, "expand-template": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz", - "integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==", - "dev": true + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" }, "expand-tilde": { "version": "2.0.2", @@ -3620,10 +2838,9 @@ } }, "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", @@ -3638,7 +2855,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -3655,32 +2872,12 @@ "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - } } }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { "array-unique": "^0.3.2", @@ -3752,6 +2949,23 @@ "debug": "2.6.9", "mkdirp": "0.5.1", "yauzl": "2.4.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, "extsprintf": { @@ -3760,10 +2974,9 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-future": { "version": "1.0.2", @@ -3783,6 +2996,17 @@ "is-glob": "^4.0.0", "merge2": "^1.2.3", "micromatch": "^3.1.10" + }, + "dependencies": { + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + } } }, "fast-json-stable-stringify": { @@ -3882,12 +3106,12 @@ } }, "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "locate-path": "^2.0.0" + "locate-path": "^3.0.0" } }, "findup-sync": { @@ -3900,17 +3124,6 @@ "is-glob": "^3.1.0", "micromatch": "^3.0.4", "resolve-dir": "^1.0.1" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } } }, "flat": { @@ -3939,31 +3152,6 @@ "flatted": "^2.0.0", "rimraf": "2.6.3", "write": "1.0.3" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } } }, "flatted": { @@ -3978,24 +3166,18 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { "asynckit": "^0.4.0", - "combined-stream": "1.0.6", + "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, @@ -4011,7 +3193,7 @@ "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=" + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "fs-extra": { "version": "4.0.3", @@ -4072,18 +3254,6 @@ "string-width": "^1.0.1", "strip-ansi": "^3.0.1", "wide-align": "^1.1.0" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } } }, "get-caller-file": { @@ -4105,10 +3275,25 @@ "dev": true }, "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + }, + "dependencies": { + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } }, "get-value": { "version": "2.0.6", @@ -4130,9 +3315,9 @@ "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4150,17 +3335,6 @@ "requires": { "is-glob": "^3.1.0", "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } } }, "glob-to-regexp": { @@ -4194,10 +3368,9 @@ } }, "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==" }, "globby": { "version": "9.0.0", @@ -4214,20 +3387,6 @@ "slash": "^2.0.0" }, "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -4237,9 +3396,9 @@ } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, "graphql": { "version": "14.1.1", @@ -4270,22 +3429,21 @@ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "dev": true, + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { - "ajv": "^5.1.0", + "ajv": "^6.5.5", "har-schema": "^2.0.0" } }, "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "function-bind": "^1.0.2" + "function-bind": "^1.1.1" } }, "has-ansi": { @@ -4371,44 +3529,35 @@ } }, "hosted-git-info": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, "htmlparser2": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.0.tgz", - "integrity": "sha512-J1nEUGv+MkXS0weHNWVKJJ+UrLfePxRWpN3C9bEi9fLxL2+ggW94DQvgYVXsaT30PGwYRIZKNZXuyMhp3Di4bQ==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", "dev": true, "requires": { - "domelementtype": "^1.3.0", + "domelementtype": "^1.3.1", "domhandler": "^2.3.0", "domutils": "^1.5.1", "entities": "^1.1.1", "inherits": "^2.0.1", - "readable-stream": "^3.0.6" + "readable-stream": "^3.1.1" }, "dependencies": { "readable-stream": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.0.6.tgz", - "integrity": "sha512-9E1oLoOWfhSXHGv6QlwXJim7uNzd9EVlWK+21tCU9Ju/kR0/p2AZYPz4qSchgO8PlLIH4FpZYfzwS+rEksZjIg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", + "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } - }, - "string_decoder": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", - "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } } } }, @@ -4440,12 +3589,6 @@ "requires": { "ms": "^2.1.1" } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true } } }, @@ -4486,13 +3629,12 @@ "dev": true }, "import-fresh": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", - "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" } }, "imurmurhash": { @@ -4502,13 +3644,10 @@ "dev": true }, "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true }, "inflight": { "version": "1.0.6", @@ -4527,7 +3666,7 @@ "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=" + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { "version": "6.2.2", @@ -4551,37 +3690,38 @@ }, "dependencies": { "ansi-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", - "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, "strip-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", @@ -4589,15 +3729,14 @@ "dev": true, "requires": { "ansi-regex": "^4.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", + "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "dev": true + } } } } @@ -4605,15 +3744,15 @@ "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "requires": { "loose-envify": "^1.0.0" } }, "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, "is-accessor-descriptor": { @@ -4650,22 +3789,13 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, "is-callable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", - "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", "dev": true }, "is-data-descriptor": { @@ -4748,12 +3878,12 @@ } }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "^2.1.1" + "is-extglob": "^2.1.0" } }, "is-number": { @@ -4782,27 +3912,11 @@ "integrity": "sha1-8mWrian0RQNO9q/xWo8AsA9VF5k=", "dev": true }, - "is-odd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", - "integrity": "sha1-dkZiRnH9fqVYzNmieVGC8pWPGyQ=", - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", - "dev": true - } - } - }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, "requires": { "isobject": "^3.0.1" } @@ -4840,10 +3954,13 @@ "dev": true }, "is-symbol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", - "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", - "dev": true + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } }, "is-typedarray": { "version": "1.0.0", @@ -4859,14 +3976,13 @@ "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -4877,7 +3993,8 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true }, "isomorphic-fetch": { "version": "2.2.1", @@ -4936,14 +4053,14 @@ "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==" }, "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "version": "3.12.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.2.tgz", + "integrity": "sha512-QHn/Lh/7HhZ/Twc7vJYQTkjuCa0kaCcDcjK5Zlk2rvnUpy7DxMJ23+Jc2dcyvltwQVg1nygAVlB2oRDFHoRS5Q==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -4952,8 +4069,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsesc": { "version": "2.5.2", @@ -4971,10 +4087,9 @@ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -5038,7 +4153,7 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true }, "klaw-sync": { @@ -5051,12 +4166,38 @@ } }, "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "less": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz", + "integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==", "dev": true, "requires": { - "invert-kv": "^1.0.0" + "clone": "^2.1.2", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.4.1", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", + "request": "^2.83.0", + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } } }, "level-codec": { @@ -5098,9 +4239,15 @@ "prebuild-install": "^4.0.0" }, "dependencies": { + "expand-template": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz", + "integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==", + "dev": true + }, "nan": { "version": "2.10.0", - "resolved": "http://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", "dev": true }, @@ -5152,32 +4299,31 @@ } }, "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", + "parse-json": "^4.0.0", + "pify": "^3.0.0", "strip-bom": "^3.0.0" } }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "^2.0.0", + "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash.escape": { "version": "4.0.1", @@ -5225,37 +4371,6 @@ "dev": true, "requires": { "chalk": "^2.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } } }, "lolex": { @@ -5265,11 +4380,11 @@ "dev": true }, "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "requires": { - "js-tokens": "^3.0.0" + "js-tokens": "^3.0.0 || ^4.0.0" } }, "loud-rejection": { @@ -5342,12 +4457,14 @@ } }, "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", + "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^2.0.0" } }, "meow": { @@ -5380,7 +4497,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -5391,6 +4508,15 @@ "strip-bom": "^2.0.0" } }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -5411,6 +4537,12 @@ "pinkie-promise": "^2.0.0" } }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -5478,22 +4610,22 @@ "optional": true }, "mime-db": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz", - "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg=" + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" }, "mime-types": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", - "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=", + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", "requires": { - "mime-db": "~1.29.0" + "mime-db": "~1.38.0" } }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "mimic-response": { @@ -5504,7 +4636,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" } @@ -5521,13 +4653,6 @@ "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } } }, "minizlib": { @@ -5541,7 +4666,7 @@ "mixin-deep": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "dev": true, "requires": { "for-in": "^1.0.2", @@ -5551,7 +4676,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -5605,42 +4730,6 @@ "yargs-unparser": "1.5.0" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "camelcase": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", - "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", - "dev": true - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", @@ -5650,57 +4739,10 @@ "ms": "^2.1.1" } }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, "js-yaml": { @@ -5713,163 +4755,49 @@ "esprima": "^4.0.0" } }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "dev": true, "requires": { - "invert-kv": "^2.0.0" + "has-flag": "^3.0.0" } - }, - "locate-path": { + } + } + }, + "mocha-junit-reporter": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/mocha-junit-reporter/-/mocha-junit-reporter-1.18.0.tgz", + "integrity": "sha512-y3XuqKa2+HRYtg0wYyhW/XsLm2Ps+pqf9HaTAt7+MVUAKFJaNAHOrNseTZo9KCxjfIbxUWwckP5qCDDPUmjSWA==", + "dev": true, + "requires": { + "debug": "^2.2.0", + "md5": "^2.1.0", + "mkdirp": "~0.5.1", + "strip-ansi": "^4.0.0", + "xml": "^1.0.0" + }, + "dependencies": { + "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true }, - "mem": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", - "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^1.0.0", - "p-is-promise": "^2.0.0" + "ms": "2.0.0" } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "p-limit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", - "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "mocha-junit-reporter": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/mocha-junit-reporter/-/mocha-junit-reporter-1.18.0.tgz", - "integrity": "sha512-y3XuqKa2+HRYtg0wYyhW/XsLm2Ps+pqf9HaTAt7+MVUAKFJaNAHOrNseTZo9KCxjfIbxUWwckP5qCDDPUmjSWA==", - "dev": true, - "requires": { - "debug": "^2.2.0", - "md5": "^2.1.0", - "mkdirp": "~0.5.1", - "strip-ansi": "^4.0.0", - "xml": "^1.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "strip-ansi": { @@ -5894,12 +4822,12 @@ }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } } } @@ -5907,7 +4835,7 @@ "mocha-stress": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/mocha-stress/-/mocha-stress-1.0.0.tgz", - "integrity": "sha1-cBx8fAQTvpn2QkvOUPxVFyIY1Kc=", + "integrity": "sha512-AeEgizAGFl+V6Bp3qzvjr9PcErlBw6qQOemDXKpbYIQaUvwKQscZmoBxq38ey0sLW9o3wwidbvaFSRQ3VApd+Q==", "dev": true }, "moment": { @@ -5922,10 +4850,9 @@ "dev": true }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" }, "mute-stream": { "version": "0.0.7", @@ -5939,9 +4866,9 @@ "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" }, "nanomatch": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", - "integrity": "sha1-h59xUMstq3pHElkGbBBO7m4Pp8I=", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -5949,23 +4876,12 @@ "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", "is-windows": "^1.0.2", "kind-of": "^6.0.2", "object.pick": "^1.3.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "requires": { - "is-plain-object": "^2.0.4" - } - } } }, "napi-build-utils": { @@ -5980,22 +4896,22 @@ "dev": true }, "nearley": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.15.1.tgz", - "integrity": "sha512-8IUY/rUrKz2mIynUGh8k+tul1awMKEjeHHC5G3FHvvyAW6oq4mQfNp2c0BMea+sYZJvYcrrM6GmZVIle/GRXGw==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.16.0.tgz", + "integrity": "sha512-Tr9XD3Vt/EujXbZBv6UAHYoLUSMQAxSsTnm9K3koXzjzNWY195NqALeyrzLZBKzAkL3gl92BcSogqrHjD8QuUg==", "dev": true, "requires": { + "commander": "^2.19.0", "moo": "^0.4.3", - "nomnom": "~1.6.2", "railroad-diagrams": "^1.0.0", "randexp": "0.4.6", "semver": "^5.4.1" } }, "nice-try": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", - "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "nise": { @@ -6020,10 +4936,9 @@ } }, "node-abi": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.5.tgz", - "integrity": "sha512-aa/UC6Nr3+tqhHGRsAuw/edz7/q9nnetBrKWxj6rpTtm+0X9T1qU7lIEHMS3yN9JwAbRiKUbRRFy1PLz/y3aaA==", - "dev": true, + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.7.1.tgz", + "integrity": "sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw==", "requires": { "semver": "^5.4.1" } @@ -6065,29 +4980,19 @@ "semver": "^5.3.0" } }, - "nomnom": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz", - "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", - "dev": true, - "requires": { - "colors": "0.5.x", - "underscore": "~1.4.4" - } - }, "noop-logger": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" }, "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", + "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } @@ -6104,7 +5009,7 @@ "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -6134,6 +5039,23 @@ "request": "^2.45.0", "single-line-log": "^1.1.2", "throttleit": "0.0.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, "nullthrows": { @@ -6513,21 +5435,6 @@ "append-transform": "^1.0.0" } }, - "istanbul-lib-instrument": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", - "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", - "dev": true, - "requires": { - "@babel/generator": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/template": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", - "istanbul-lib-coverage": "^2.0.3", - "semver": "^5.5.0" - } - }, "istanbul-lib-report": { "version": "2.0.4", "bundled": true, @@ -7196,10 +6103,9 @@ } }, "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "4.1.1", @@ -7250,9 +6156,9 @@ "dev": true }, "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", "dev": true }, "object-visit": { @@ -7267,7 +6173,7 @@ "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { "define-properties": "^1.1.2", @@ -7277,14 +6183,26 @@ } }, "object.entries": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", - "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz", + "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==", "dev": true, "requires": { "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", + "es-abstract": "^1.11.0", + "function-bind": "^1.1.1", "has": "^1.0.1" } }, @@ -7308,15 +6226,15 @@ } }, "object.values": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", - "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" } }, "once": { @@ -7372,14 +6290,14 @@ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" } }, "os-tmpdir": { @@ -7407,27 +6325,27 @@ "dev": true }, "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "^1.1.0" + "p-limit": "^2.0.0" } }, "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", "dev": true }, "parent-module": { @@ -7437,15 +6355,23 @@ "dev": true, "requires": { "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", + "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", + "dev": true + } } }, "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "requires": { - "error-ex": "^1.2.0" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" } }, "parse-passwd": { @@ -7510,15 +6436,23 @@ "dev": true, "requires": { "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } } }, "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "pify": "^2.0.0" + "pify": "^3.0.0" } }, "pathval": { @@ -7539,9 +6473,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, "pinkie": { @@ -7586,21 +6520,6 @@ "tar-fs": "^1.13.0", "tunnel-agent": "^0.6.0", "which-pm-runs": "^1.0.0" - }, - "dependencies": { - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" - }, - "node-abi": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.7.1.tgz", - "integrity": "sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw==", - "requires": { - "semver": "^5.4.1" - } - } } }, "prelude-ls": { @@ -7622,7 +6541,7 @@ "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=" + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" }, "process-nextick-args": { "version": "2.0.0", @@ -7647,7 +6566,7 @@ "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "requires": { "asap": "~2.0.3" } @@ -7660,21 +6579,6 @@ "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.8.1" - }, - "dependencies": { - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "react-is": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.1.tgz", - "integrity": "sha512-ioMCzVDWvCvKD8eeT+iukyWrBGrA3DiFYkXfBsVYIRdaREZuBjENG+KjrikavCLasozqRWTwFUagU/O4vPpRMA==" - } } }, "prr": { @@ -7697,22 +6601,21 @@ "pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=", - "dev": true + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "raf": { "version": "3.4.1", @@ -7759,17 +6662,6 @@ "object-assign": "^4.1.1", "prop-types": "^15.6.2", "scheduler": "^0.13.3" - }, - "dependencies": { - "scheduler": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.3.tgz", - "integrity": "sha512-UxN5QRYWtpR1egNWzJcVLk8jlegxAugswQc984lD3kU7NuobsO37/sRfbpTdBjtnD5TBNFA2Q2oLV5+UmPSmEQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - } } }, "react-dom": { @@ -7781,48 +6673,20 @@ "object-assign": "^4.1.1", "prop-types": "^15.6.2", "scheduler": "^0.13.3" - }, - "dependencies": { - "scheduler": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.3.tgz", - "integrity": "sha512-UxN5QRYWtpR1egNWzJcVLk8jlegxAugswQc984lD3kU7NuobsO37/sRfbpTdBjtnD5TBNFA2Q2oLV5+UmPSmEQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - } } }, "react-input-autosize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.1.tgz", - "integrity": "sha1-7EKPoVsVkplPtfmqFbsetrr0IPg=", + "integrity": "sha512-3+K4CD13iE4lQQ2WlF8PuV5htfmTRLH6MDnfndHM6LuBRszuXnuyIfE7nhSKt8AzRBZ50bu0sAhkNMeS5pxQQA==", "requires": { "prop-types": "^15.5.8" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" - }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - } } }, "react-is": { - "version": "16.6.3", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.3.tgz", - "integrity": "sha512-u7FDWtthB4rWibG/+mFbVd5FvdI20yde86qKGx4lVUTWmPlSWQ4QxbBIrrs+HnXGbxOUlUzTAP/VDmvCwaP2yA==", - "dev": true + "version": "16.8.3", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.3.tgz", + "integrity": "sha512-Y4rC1ZJmsxxkkPuMLwvKvlL1Zfpbcu+Bf4ZigkHup3v9EfdYhAlWAaVyA19olXq2o2mGn0w+dFKvk3pVVlYcIA==" }, "react-relay": { "version": "3.0.0", @@ -7839,27 +6703,11 @@ "react-select": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/react-select/-/react-select-1.2.1.tgz", - "integrity": "sha1-ov5YpWnrFNyqZUOBYmC5flOBINE=", + "integrity": "sha512-vaCgT2bEl+uTyE/uKOEgzE5Dc/wLtzhnBvoHCeuLoJWc4WuadN6WQDhoL42DW+TziniZK2Gaqe/wUXydI3NSaQ==", "requires": { "classnames": "^2.2.4", "prop-types": "^15.5.8", "react-input-autosize": "^2.1.2" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" - }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - } } }, "react-tabs": { @@ -7872,62 +6720,50 @@ } }, "react-test-renderer": { - "version": "16.6.3", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.6.3.tgz", - "integrity": "sha512-B5bCer+qymrQz/wN03lT0LppbZUDRq6AMfzMKrovzkGzfO81a9T+PWQW6MzkWknbwODQH/qpJno/yFQLX5IWrQ==", + "version": "16.8.3", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.8.3.tgz", + "integrity": "sha512-rjJGYebduKNZH0k1bUivVrRLX04JfIQ0FKJLPK10TAb06XWhfi4gTobooF9K/DEFNW98iGac3OSxkfIJUN9Mdg==", "dev": true, "requires": { "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "react-is": "^16.6.3", - "scheduler": "^0.11.2" + "react-is": "^16.8.3", + "scheduler": "^0.13.3" } }, "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { - "load-json-file": "^2.0.0", + "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "path-type": "^3.0.0" } }, "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" } }, "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", + "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", + "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" - } } }, "recast": { @@ -7965,6 +6801,17 @@ "requires": { "indent-string": "^2.1.0", "strip-indent": "^1.0.1" + }, + "dependencies": { + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + } } }, "regenerate": { @@ -7981,10 +6828,9 @@ } }, "regenerator-runtime": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w==", - "dev": true + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, "regenerator-transform": { "version": "0.13.4", @@ -7997,21 +6843,11 @@ "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "requires": { - "is-plain-object": "^2.0.4" - } - } } }, "regexp-tree": { @@ -8082,33 +6918,270 @@ "yargs": "^9.0.0" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { - "color-convert": "^1.9.0" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } } }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "has-flag": "^3.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz", + "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^7.0.0" + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" } } } @@ -8123,9 +7196,9 @@ } }, "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", "dev": true }, "repeat-string": { @@ -8144,48 +7217,30 @@ } }, "request": { - "version": "2.87.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", - "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", - "dev": true, + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "requires": { "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", + "aws4": "^1.8.0", "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "tough-cookie": "~2.3.3", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" - }, - "dependencies": { - "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha1-o0kgUKXLm2NFBUHjnZeI0icng9s=", - "dev": true - }, - "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha1-bzI/YKg9ERRvgx/xH9ZuL+VQO7g=", - "dev": true, - "requires": { - "mime-db": "~1.33.0" - } - } + "uuid": "^3.3.2" } }, "require-directory": { @@ -8201,9 +7256,9 @@ "dev": true }, "resolve": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz", - "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", "requires": { "path-parse": "^1.0.6" } @@ -8219,10 +7274,9 @@ } }, "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" }, "resolve-url": { "version": "0.2.1", @@ -8243,15 +7297,15 @@ "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "rst-selector-parser": { @@ -8283,9 +7337,9 @@ } }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -8302,10 +7356,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "scheduler": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.11.3.tgz", - "integrity": "sha512-i9X9VRRVZDd3xZw10NY5Z2cVMbdYg6gqFecfj79USv1CFN+YrJ3gIPRKf1qlY+Sxly4djoKdfx1T+m9dnRB8kQ==", - "dev": true, + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.3.tgz", + "integrity": "sha512-UxN5QRYWtpR1egNWzJcVLk8jlegxAugswQc984lD3kU7NuobsO37/sRfbpTdBjtnD5TBNFA2Q2oLV5+UmPSmEQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -8324,7 +7377,7 @@ "set-value": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -8383,7 +7436,7 @@ "simple-get": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", - "integrity": "sha1-DiLpHUV12HYgYgvJEwjVenf0S10=", + "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", "requires": { "decompress-response": "^3.3.0", "once": "^1.3.1", @@ -8397,19 +7450,6 @@ "dev": true, "requires": { "string-width": "^1.0.1" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } } }, "sinon": { @@ -8427,14 +7467,11 @@ "supports-color": "^5.5.0" }, "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true } } }, @@ -8455,15 +7492,6 @@ "is-fullwidth-code-point": "^2.0.0" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -8488,6 +7516,15 @@ "use": "^3.1.0" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", @@ -8505,13 +7542,19 @@ "requires": { "is-extendable": "^0.1.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { "define-property": "^1.0.0", @@ -8562,7 +7605,7 @@ "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { "kind-of": "^3.2.0" @@ -8585,12 +7628,12 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "source-map-resolve": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", - "integrity": "sha1-etD1k/IoFZjoVN+A8ZquS5LXoRo=", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "atob": "^2.0.0", + "atob": "^2.1.1", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", @@ -8604,9 +7647,9 @@ "dev": true }, "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -8614,9 +7657,9 @@ } }, "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", "dev": true }, "spdx-expression-parse": { @@ -8630,9 +7673,9 @@ } }, "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", "dev": true }, "speedometer": { @@ -8644,7 +7687,7 @@ "split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha1-YFvZvjA6pZ+zX5Ip++oN3snqB9k=", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", "requires": { "through": "2" } @@ -8652,20 +7695,10 @@ "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { "extend-shallow": "^3.0.0" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "requires": { - "is-plain-object": "^2.0.4" - } - } } }, "sprintf-js": { @@ -8674,9 +7707,9 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", - "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -8685,6 +7718,7 @@ "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" } }, @@ -8710,32 +7744,13 @@ } }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string.prototype.trim": { @@ -8750,9 +7765,9 @@ } }, "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } @@ -8798,13 +7813,32 @@ "dev": true, "requires": { "debug": "^2.2.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } }, "table": { "version": "5.2.3", @@ -8818,54 +7852,18 @@ "string-width": "^3.0.0" }, "dependencies": { - "ajv": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", - "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "ansi-regex": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", "dev": true }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, "string-width": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.0.0.tgz", @@ -8900,18 +7898,6 @@ "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", "yallist": "^3.0.2" - }, - "dependencies": { - "chownr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } } }, "tar-fs": { @@ -8959,14 +7945,6 @@ "https-proxy-agent": "^2.2.1", "node-fetch": "^2.2.0", "uuid": "^3.3.2" - }, - "dependencies": { - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - } } }, "temp": { @@ -8987,109 +7965,6 @@ "minimatch": "^3.0.4", "read-pkg-up": "^4.0.0", "require-main-filename": "^1.0.1" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", - "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", - "dev": true - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - } } }, "test-until": { @@ -9125,6 +8000,12 @@ "xtend": "~2.1.1" }, "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, "object-keys": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", @@ -9133,7 +8014,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -9165,10 +8046,19 @@ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=" + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" }, "to-fast-properties": { "version": "2.0.0", @@ -9198,23 +8088,13 @@ "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "requires": { - "is-plain-object": "^2.0.4" - } - } } }, "to-regex-range": { @@ -9228,12 +8108,19 @@ } }, "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha1-7GDO44rGdQY//JelwYlwV47oNlU=", - "dev": true, + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { + "psl": "^1.1.24", "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } } }, "tree-kill": { @@ -9269,8 +8156,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "type-check": { "version": "0.3.2", @@ -9299,10 +8185,9 @@ "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==" }, "underscore": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", - "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", - "dev": true + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" }, "underscore-plus": { "version": "1.6.8", @@ -9310,13 +8195,6 @@ "integrity": "sha512-88PrCeMKeAAC1L4xjSiiZ3Fg6kZOYrLpLGVPPeqKq/662DfQe/KTSKdSR/Q/tucKNnfW2MNAUGSCkDf8HmXC5Q==", "requires": { "underscore": "~1.8.3" - }, - "dependencies": { - "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" - } } }, "unicode-canonical-property-names-ecmascript": { @@ -9379,9 +8257,9 @@ } }, "universalify": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", - "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, "unset-value": { "version": "1.0.0", @@ -9420,12 +8298,6 @@ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true } } }, @@ -9435,13 +8307,6 @@ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "requires": { "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - } } }, "urix": { @@ -9474,13 +8339,10 @@ "dev": true }, "use": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true }, "util-deprecate": { "version": "1.0.2", @@ -9488,15 +8350,14 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", - "dev": true + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { "spdx-correct": "^3.0.0", @@ -9521,7 +8382,7 @@ "what-the-status": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/what-the-status/-/what-the-status-1.0.3.tgz", - "integrity": "sha1-lP3NAR/7U6Ijnnb6+NrL78mHdRA=", + "integrity": "sha512-6zNdYtQtHTpLVPomSrr+Eyt5Ci4H40ytwScwp7Moi2iqxztV6+juQV9Orj2szAo0ZrV9tphk6WtL+BY3ukCS/Q==", "requires": { "split": "^1.0.0" } @@ -9532,9 +8393,9 @@ "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" }, "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -9572,19 +8433,6 @@ "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } } }, "wrappy": { @@ -9613,9 +8461,9 @@ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, "yallist": { @@ -9624,44 +8472,23 @@ "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" }, "yargs": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz", - "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", "dev": true, "requires": { - "camelcase": "^4.1.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "read-pkg-up": "^2.0.0", + "os-locale": "^3.0.0", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", "string-width": "^2.0.0", "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^7.0.0" - } - }, - "yargs-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", - "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - }, - "yargs-unparser": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", - "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.11", - "yargs": "^12.0.5" + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" }, "dependencies": { "ansi-regex": { @@ -9670,148 +8497,20 @@ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, - "camelcase": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", - "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", - "dev": true - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "mem": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", - "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^1.0.0", - "p-is-promise": "^2.0.0" - } - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "p-limit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", - "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { + "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { @@ -9822,39 +8521,30 @@ "requires": { "ansi-regex": "^3.0.0" } - }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } } } }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", + "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.11", + "yargs": "^12.0.5" + } + }, "yauzl": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", From 2c261c8ba03b37f8cd9f67b48a0ec9d1c0dae96f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Feb 2019 13:41:48 -0500 Subject: [PATCH 2939/4847] Cover the last uncovered line in MultiFilePatchView --- test/views/multi-file-patch-view.test.js | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/views/multi-file-patch-view.test.js b/test/views/multi-file-patch-view.test.js index 8af61c38ff..eaabc059d6 100644 --- a/test/views/multi-file-patch-view.test.js +++ b/test/views/multi-file-patch-view.test.js @@ -236,6 +236,36 @@ describe('MultiFilePatchView', function() { assert.isFalse(wrapper.find('FilePatchHeaderView[relPath="1"]').prop('hasMultipleFileSelections')); }); + it('triggers a FilePatch collapse from file headers', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => fp.setOldFile(f => f.path('0'))) + .addFilePatch(fp => fp.setOldFile(f => f.path('1'))) + .build(); + const fp1 = multiFilePatch.getFilePatches()[1]; + + const wrapper = shallow(buildApp({multiFilePatch})); + + sinon.stub(multiFilePatch, 'collapseFilePatch'); + + wrapper.find('FilePatchHeaderView[relPath="1"]').prop('triggerCollapse')(); + assert.isTrue(multiFilePatch.collapseFilePatch.calledWith(fp1)); + }); + + it('triggers a FilePatch expansion from file headers', function() { + const {multiFilePatch} = multiFilePatchBuilder() + .addFilePatch(fp => fp.setOldFile(f => f.path('0'))) + .addFilePatch(fp => fp.setOldFile(f => f.path('1'))) + .build(); + const fp0 = multiFilePatch.getFilePatches()[0]; + + const wrapper = shallow(buildApp({multiFilePatch})); + + sinon.stub(multiFilePatch, 'expandFilePatch'); + + wrapper.find('FilePatchHeaderView[relPath="0"]').prop('triggerExpand')(); + assert.isTrue(multiFilePatch.expandFilePatch.calledWith(fp0)); + }); + it('renders a PullRequestsReviewsContainer if itemType is IssueishDetailItem', function() { const wrapper = shallow(buildApp({itemType: IssueishDetailItem})); assert.lengthOf(wrapper.find('ForwardRef(Relay(PullRequestReviewsController))'), 1); From 776a440207ccc18b1595980ea7ed690a6859f27f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Feb 2019 14:04:49 -0500 Subject: [PATCH 2940/4847] Manually test cache invalidation from FOCUS on Linux --- test/models/repository.test.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/models/repository.test.js b/test/models/repository.test.js index a0e68c9eb1..6f9ce245b8 100644 --- a/test/models/repository.test.js +++ b/test/models/repository.test.js @@ -11,6 +11,7 @@ import {LargeRepoError} from '../../lib/git-shell-out-strategy'; import {nullCommit} from '../../lib/models/commit'; import {nullOperationStates} from '../../lib/models/operation-states'; import Author from '../../lib/models/author'; +import {FOCUS} from '../../lib/models/workspace-change-observer'; import * as reporterProxy from '../../lib/reporter-proxy'; import { @@ -2306,6 +2307,37 @@ describe('Repository', function() { }); }); }); + + it('manually invalidates some keys when the WorkspaceChangeObserver indicates the window is focused', async function() { + const workdir = await cloneRepository('three-files'); + const repository = new Repository(workdir); + await repository.getLoadPromise(); + + const readerMethods = await getCacheReaderMethods({repository}); + function readerValues() { + return new Map( + Array.from(readerMethods.entries(), method => { + return [method[0], method[1]()]; + }), + ); + } + + const before = readerValues(); + repository.observeFilesystemChange([{special: FOCUS}]); + const after = readerValues(); + + const invalidated = Array.from(readerMethods.keys()).filter(key => before.get(key) !== after.get(key)); + + assert.sameMembers(invalidated, [ + 'getStatusBundle', + 'getFilePatchForPath {unstaged} a.txt', + 'getFilePatchForPath {unstaged} b.txt', + 'getFilePatchForPath {unstaged} c.txt', + 'getFilePatchForPath {unstaged} subdir-1/a.txt', + 'getFilePatchForPath {unstaged} subdir-1/b.txt', + 'getFilePatchForPath {unstaged} subdir-1/c.txt', + ]); + }); }); describe('commit message', function() { From 97720b03ccf3cf82671dfff7e0b179f59ded3bc0 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Feb 2019 14:06:18 -0500 Subject: [PATCH 2941/4847] That .catch on win32 is probably important? --- test/models/repository.test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/models/repository.test.js b/test/models/repository.test.js index 6f9ce245b8..7cd9b768b8 100644 --- a/test/models/repository.test.js +++ b/test/models/repository.test.js @@ -2316,8 +2316,12 @@ describe('Repository', function() { const readerMethods = await getCacheReaderMethods({repository}); function readerValues() { return new Map( - Array.from(readerMethods.entries(), method => { - return [method[0], method[1]()]; + Array.from(readerMethods.entries(), ([name, call]) => { + const promise = call(); + if (process.platform === 'win32') { + promise.catch(() => {}); + } + return [name, promise]; }), ); } From 893489b6c6620df8782acf81c54fbab2681cf4d2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Feb 2019 14:46:30 -0500 Subject: [PATCH 2942/4847] PatchBuffer :100: --- lib/models/patch/patch-buffer.js | 5 +- test/models/patch/patch-buffer.test.js | 86 ++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 7 deletions(-) diff --git a/lib/models/patch/patch-buffer.js b/lib/models/patch/patch-buffer.js index 44aa501989..e93a48f865 100644 --- a/lib/models/patch/patch-buffer.js +++ b/lib/models/patch/patch-buffer.js @@ -118,6 +118,7 @@ export default class PatchBuffer { return markerMap; } + /* istanbul ignore next */ inspect(opts = {}) { /* istanbul ignore next */ const options = { @@ -237,9 +238,7 @@ class Inserter { } } - if (opts.callback) { - this.markerMapCallbacks.push({markerMap: subMarkerMap, callback: opts.callback}); - } + this.markerMapCallbacks.push({markerMap: subMarkerMap, callback: opts.callback}); return this; } diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index 29bfc2379f..8289c2c55a 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -13,14 +13,16 @@ describe('PatchBuffer', function() { it('has simple accessors', function() { assert.strictEqual(patchBuffer.getBuffer().getText(), TEXT); assert.deepEqual(patchBuffer.getInsertionPoint().serialize(), [10, 0]); + assert.isDefined(patchBuffer.getLayer('patch')); }); it('creates and finds markers on specified layers', function() { const patchMarker = patchBuffer.markRange('patch', [[1, 0], [2, 4]]); const hunkMarker = patchBuffer.markRange('hunk', [[2, 0], [3, 4]]); - assert.deepEqual(patchBuffer.findMarkers('patch', {}), [patchMarker]); - assert.deepEqual(patchBuffer.findMarkers('hunk', {}), [hunkMarker]); + assert.sameDeepMembers(patchBuffer.findMarkers('patch', {}), [patchMarker]); + assert.sameDeepMembers(patchBuffer.findMarkers('hunk', {}), [hunkMarker]); + assert.sameDeepMembers(patchBuffer.findAllMarkers({}), [patchMarker, hunkMarker]); }); it('clears markers from all layers at once', function() { @@ -179,6 +181,67 @@ describe('PatchBuffer', function() { }); }); + describe('adopt', function() { + it('destroys existing content and markers and replaces them with those from the argument', function() { + const original = new PatchBuffer(); + original.getBuffer().setText(dedent` + before 0 + before 1 + before 2 + `); + + const originalMarkers = [ + original.markRange('patch', [[0, 0], [2, 3]]), + original.markRange('patch', [[1, 3], [2, 0]]), + original.markRange('hunk', [[0, 0], [0, 7]]), + ]; + + const adoptee = new PatchBuffer(); + adoptee.getBuffer().setText(dedent` + after 0 + after 1 + after 2 + after 3 + `); + + const adopteeMarkers = [ + adoptee.markRange('addition', [[2, 0], [3, 7]]), + adoptee.markRange('patch', [[1, 0], [2, 0]]), + ]; + + const map = original.adopt(adoptee); + + assert.strictEqual(original.getBuffer().getText(), dedent` + after 0 + after 1 + after 2 + after 3 + `); + + assert.sameDeepMembers( + original.findMarkers('patch', {}).map(m => m.getRange().serialize()), + [[[1, 0], [2, 0]]], + ); + assert.sameDeepMembers( + original.findMarkers('addition', {}).map(m => m.getRange().serialize()), + [[[2, 0], [3, 7]]], + ); + assert.lengthOf(original.findMarkers('hunk', {}), 0); + + for (const originalMarker of originalMarkers) { + assert.isFalse(map.has(originalMarker)); + assert.isTrue(originalMarker.isDestroyed()); + } + + for (const adopteeMarker of adopteeMarkers) { + assert.isTrue(map.has(adopteeMarker)); + assert.isFalse(adopteeMarker.isDestroyed()); + assert.isFalse(map.get(adopteeMarker).isDestroyed()); + assert.deepEqual(adopteeMarker.getRange().serialize(), map.get(adopteeMarker).getRange().serialize()); + } + }); + }); + describe('deferred-marking modifications', function() { it('performs multiple modifications and only creates markers at the end', function() { const inserter = patchBuffer.createInserterAtEnd(); @@ -263,13 +326,20 @@ describe('PatchBuffer', function() { }); it('preserves markers that should be before or after the modification region', function() { + const invalidBefore = patchBuffer.markRange('patch', [[1, 0], [1, 0]]); const before0 = patchBuffer.markRange('patch', [[1, 0], [4, 0]], {exclusive: true}); const before1 = patchBuffer.markRange('hunk', [[4, 0], [4, 0]], {exclusive: true}); + const before2 = patchBuffer.markRange('addition', [[3, 0], [4, 0]], {exclusive: true, reversed: true}); + const before3 = patchBuffer.markRange('nonewline', [[4, 0], [4, 0]], {exclusive: true, reversed: true}); const after0 = patchBuffer.markPosition('patch', [4, 0], {exclusive: true}); + const after1 = patchBuffer.markRange('patch', [[4, 0], [4, 3]], {exclusive: true}); + const after2 = patchBuffer.markRange('deletion', [[4, 0], [5, 0]], {exclusive: true, reversed: true}); + const after3 = patchBuffer.markRange('nonewline', [[4, 0], [4, 0]], {exclusive: true, reversed: true}); + const invalidAfter = patchBuffer.markRange('hunk', [[5, 0], [6, 0]]); const inserter = patchBuffer.createInserterAt([4, 0]); - inserter.keepBefore([before0, before1]); - inserter.keepAfter([after0]); + inserter.keepBefore([before0, before1, before2, before3, invalidBefore]); + inserter.keepAfter([after0, after1, after2, after3, invalidAfter]); let marker = null; const callback = m => { marker = m; }; @@ -279,8 +349,16 @@ describe('PatchBuffer', function() { assert.deepEqual(before0.getRange().serialize(), [[1, 0], [4, 0]]); assert.deepEqual(before1.getRange().serialize(), [[4, 0], [4, 0]]); + assert.deepEqual(before2.getRange().serialize(), [[3, 0], [4, 0]]); + assert.deepEqual(before3.getRange().serialize(), [[4, 0], [4, 0]]); assert.deepEqual(marker.getRange().serialize(), [[4, 0], [9, 0]]); assert.deepEqual(after0.getRange().serialize(), [[9, 0], [9, 0]]); + assert.deepEqual(after1.getRange().serialize(), [[9, 0], [9, 3]]); + assert.deepEqual(after2.getRange().serialize(), [[9, 0], [10, 0]]); + assert.deepEqual(after3.getRange().serialize(), [[9, 0], [9, 0]]); + + assert.deepEqual(invalidBefore.getRange().serialize(), [[1, 0], [1, 0]]); + assert.deepEqual(invalidAfter.getRange().serialize(), [[10, 0], [11, 0]]); }); it('appends another PatchBuffer at its insertion point', function() { From d58ca26d2785723e595f5ea269e39e7e171cfd1b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Feb 2019 14:54:15 -0500 Subject: [PATCH 2943/4847] AtomTextEditor :100: --- lib/atom/atom-text-editor.js | 2 +- test/atom/atom-text-editor.test.js | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/atom/atom-text-editor.js b/lib/atom/atom-text-editor.js index 3e4425c0d3..fb4e52e7db 100644 --- a/lib/atom/atom-text-editor.js +++ b/lib/atom/atom-text-editor.js @@ -97,7 +97,7 @@ export default class AtomTextEditor extends React.Component { }); } - componentDidUpdate(prevProps) { + componentDidUpdate() { const modelProps = extractProps(this.props, editorUpdateProps); this.getRefModel().map(editor => editor.update(modelProps)); this.observeEmptiness(); diff --git a/test/atom/atom-text-editor.test.js b/test/atom/atom-text-editor.test.js index 194cd5d9b0..ce2fc700cd 100644 --- a/test/atom/atom-text-editor.test.js +++ b/test/atom/atom-text-editor.test.js @@ -130,6 +130,31 @@ describe('AtomTextEditor', function() { }); }); + it('defaults to no-op handlers', function() { + mount( + , + ); + + const editor = refModel.get(); + + // Trigger didChangeCursorPosition + editor.setCursorBufferPosition([2, 3]); + + // Trigger didAddSelection + editor.addSelectionForBufferRange([[1, 0], [3, 3]]); + + // Trigger didChangeSelectionRange + const [selection] = editor.getSelections(); + selection.setBufferRange([[2, 2], [2, 3]]); + + // Trigger didDestroySelection + editor.setSelectedBufferRange([[1, 0], [1, 2]]); + }); + it('triggers didChangeCursorPosition when the cursor position changes', function() { mount( Date: Wed, 27 Feb 2019 15:35:54 -0500 Subject: [PATCH 2944/4847] State :100: --- lib/models/repository-states/present.js | 8 ++++++++ lib/models/repository-states/state.js | 9 ++++++++- test/models/repository.test.js | 26 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/models/repository-states/present.js b/lib/models/repository-states/present.js index 42d77844ce..233477e19c 100644 --- a/lib/models/repository-states/present.js +++ b/lib/models/repository-states/present.js @@ -875,6 +875,10 @@ export default class Present extends State { }); } + directGetConfig(key, options) { + return this.getConfig(key, options); + } + // Direct blob access getBlobContents(sha) { @@ -883,6 +887,10 @@ export default class Present extends State { }); } + directGetBlobContents(sha) { + return this.getBlobContents(sha); + } + // Discard history hasDiscardHistory(partialDiscardFilePath = null) { diff --git a/lib/models/repository-states/state.js b/lib/models/repository-states/state.js index d76548c6fb..2053cc4cfb 100644 --- a/lib/models/repository-states/state.js +++ b/lib/models/repository-states/state.js @@ -104,6 +104,7 @@ export default class State { return this.transitionTo('Destroyed'); } + /* istanbul ignore next */ refresh() { // No-op } @@ -112,9 +113,9 @@ export default class State { this.repository.refresh(); } + /* istanbul ignore next */ updateCommitMessageAfterFileSystemChange() { // this is only used in unit tests, we don't need no stinkin coverage - /* istanbul ignore next */ this.repository.refresh(); } @@ -440,6 +441,7 @@ export default class State { // Initiate a transition to another state. transitionTo(stateName, ...payload) { const StateConstructor = stateConstructors.get(stateName); + /* istanbul ignore if */ if (StateConstructor === undefined) { throw new Error(`Attempt to transition to unrecognized state ${stateName}`); } @@ -459,22 +461,27 @@ export default class State { // Direct git access // Non-delegated git operations for internal use within states. + /* istanbul ignore next */ directResolveDotGitDir() { return Promise.resolve(null); } + /* istanbul ignore next */ directGetConfig(key, options = {}) { return Promise.resolve(null); } + /* istanbul ignore next */ directGetBlobContents() { return Promise.reject(new Error('Not a valid object name')); } + /* istanbul ignore next */ directInit() { return Promise.resolve(); } + /* istanbul ignore next */ directClone(remoteUrl, options) { return Promise.resolve(); } diff --git a/test/models/repository.test.js b/test/models/repository.test.js index 7cd9b768b8..7ea6c8a8f6 100644 --- a/test/models/repository.test.js +++ b/test/models/repository.test.js @@ -124,6 +124,7 @@ describe('Repository', function() { 'push', 'setConfig', 'unsetConfig', 'createBlob', 'expandBlobToFile', 'createDiscardHistoryBlob', 'updateDiscardHistory', 'storeBeforeAndAfterBlobs', 'restoreLastDiscardInTempFiles', 'popDiscardHistory', 'clearDiscardHistory', 'discardWorkDirChangesForPaths', 'addRemote', 'setCommitMessage', + 'fetchCommitMessageTemplate', ]) { await assert.isRejected(repository[method](), new RegExp(`${method} is not available in Destroyed state`)); } @@ -1603,6 +1604,31 @@ describe('Repository', function() { const repo2 = new Repository(workingDirPath); await repo2.getLoadPromise(); }); + + it('passes unexpected git errors to the caller', async function() { + const workingDirPath = await cloneRepository('three-files'); + const repo = new Repository(workingDirPath); + await repo.getLoadPromise(); + await repo.setConfig('atomGithub.historySha', '1111111111111111111111111111111111111111'); + + repo.refresh(); + sinon.stub(repo.git, 'getBlobContents').rejects(new Error('oh no')); + + await assert.isRejected(repo.updateDiscardHistory(), /oh no/); + }); + + it('is resilient to malformed history blobs', async function() { + const workingDirPath = await cloneRepository('three-files'); + const repo = new Repository(workingDirPath); + await repo.getLoadPromise(); + await repo.setConfig('atomGithub.historySha', '1111111111111111111111111111111111111111'); + + repo.refresh(); + sinon.stub(repo.git, 'getBlobContents').resolves('lol not JSON'); + + // Should not throw + await repo.updateDiscardHistory(); + }); }); describe('cache invalidation', function() { From 0d1860157eca46d04d7267e992078e8997c6580a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 27 Feb 2019 16:04:37 -0500 Subject: [PATCH 2945/4847] Maybe it's the path separators? --- test/models/repository.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/models/repository.test.js b/test/models/repository.test.js index 7ea6c8a8f6..28988ed9ea 100644 --- a/test/models/repository.test.js +++ b/test/models/repository.test.js @@ -2363,9 +2363,9 @@ describe('Repository', function() { 'getFilePatchForPath {unstaged} a.txt', 'getFilePatchForPath {unstaged} b.txt', 'getFilePatchForPath {unstaged} c.txt', - 'getFilePatchForPath {unstaged} subdir-1/a.txt', - 'getFilePatchForPath {unstaged} subdir-1/b.txt', - 'getFilePatchForPath {unstaged} subdir-1/c.txt', + `getFilePatchForPath {unstaged} ${path.join('subdir-1/a.txt')}`, + `getFilePatchForPath {unstaged} ${path.join('subdir-1/b.txt')}`, + `getFilePatchForPath {unstaged} ${path.join('subdir-1/c.txt')}`, ]); }); }); From 33c88af095fe7e6ff4432fbaa72e353d3e157b7c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Feb 2019 07:50:26 -0500 Subject: [PATCH 2946/4847] Actually :100: State --- lib/models/repository-states/state.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/models/repository-states/state.js b/lib/models/repository-states/state.js index 2053cc4cfb..b364d85dde 100644 --- a/lib/models/repository-states/state.js +++ b/lib/models/repository-states/state.js @@ -109,6 +109,7 @@ export default class State { // No-op } + /* istanbul ignore next */ observeFilesystemChange(events) { this.repository.refresh(); } From 03b47156ac05d0b4966f3845e2b8fdf96a13da6c Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Thu, 28 Feb 2019 16:25:47 +0000 Subject: [PATCH 2947/4847] fix(package): update dugite to version 1.85.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5cca104dbc..d9ab506843 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "bytes": "3.1.0", "classnames": "2.2.6", "compare-sets": "1.0.1", - "dugite": "1.84.0", + "dugite": "1.85.0", "event-kit": "2.5.3", "fs-extra": "4.0.3", "graphql": "14.1.1", From 52ba1b5559cd40e8888e1e15c287e7ce74cb0143 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Thu, 28 Feb 2019 16:25:51 +0000 Subject: [PATCH 2948/4847] chore(package): update lockfile package-lock.json --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b0dc9c9763..3a33c7b5a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2245,9 +2245,9 @@ } }, "dugite": { - "version": "1.84.0", - "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.84.0.tgz", - "integrity": "sha512-TKBfeQAq4f4bcrPRtb9k1LnI/dssl8K85A5LxnJIaKdhGUbOtmcJacSzNSiokz0OFbSOEIYxtgZMRnkVONIURg==", + "version": "1.85.0", + "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.85.0.tgz", + "integrity": "sha512-33YIKzzuSIoB8cRDrIPozvvIJiPs4+XQJGcb9g48O99Q0GkPb1ipy3YjknJTTU0TwTB+NyGjA6m1jBRoR3XvuQ==", "requires": { "checksum": "^0.1.1", "mkdirp": "^0.5.1", From a316c1b6534b94b8531d890711fb000a79f773e1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Feb 2019 14:51:31 -0500 Subject: [PATCH 2949/4847] Our daily Nietzsche --- lib/atom/atom-text-editor.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/atom/atom-text-editor.js b/lib/atom/atom-text-editor.js index fb4e52e7db..aedfe29971 100644 --- a/lib/atom/atom-text-editor.js +++ b/lib/atom/atom-text-editor.js @@ -100,6 +100,8 @@ export default class AtomTextEditor extends React.Component { componentDidUpdate() { const modelProps = extractProps(this.props, editorUpdateProps); this.getRefModel().map(editor => editor.update(modelProps)); + + // When you look into the abyss, the abyss also looks into you this.observeEmptiness(); } From ceda6ef135f43a9d1c6478f723a0ff788f4757da Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Feb 2019 14:52:43 -0500 Subject: [PATCH 2950/4847] :fire: obsolete TODO --- lib/models/patch/builder.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/models/patch/builder.js b/lib/models/patch/builder.js index aecd09aca0..b328a4da35 100644 --- a/lib/models/patch/builder.js +++ b/lib/models/patch/builder.js @@ -8,7 +8,6 @@ import MultiFilePatch from './multi-file-patch'; export const DEFAULT_OPTIONS = { // Number of lines after which we consider the diff "large" - // TODO: Set this based on performance measurements largeDiffThreshold: 800, // Map of file path (relative to repository root) to Patch render status (EXPANDED, COLLAPSED, TOO_LARGE) From 355ade8868f93054b442deca748a025b7b5a4659 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Feb 2019 14:54:11 -0500 Subject: [PATCH 2951/4847] Rename getLayeredBuffer() to getPatchBuffer() --- lib/models/patch/multi-file-patch.js | 18 +++++++++--------- lib/views/multi-file-patch-view.js | 4 ++-- test/models/patch/multi-file-patch.test.js | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/models/patch/multi-file-patch.js b/lib/models/patch/multi-file-patch.js index 47e7e635e0..8cf13824a4 100644 --- a/lib/models/patch/multi-file-patch.js +++ b/lib/models/patch/multi-file-patch.js @@ -44,41 +44,41 @@ export default class MultiFilePatch { clone(opts = {}) { return new this.constructor({ - patchBuffer: opts.patchBuffer !== undefined ? opts.patchBuffer : this.getLayeredBuffer(), + patchBuffer: opts.patchBuffer !== undefined ? opts.patchBuffer : this.getPatchBuffer(), filePatches: opts.filePatches !== undefined ? opts.filePatches : this.getFilePatches(), }); } - getLayeredBuffer() { + getPatchBuffer() { return this.patchBuffer; } getBuffer() { - return this.getLayeredBuffer().getBuffer(); + return this.getPatchBuffer().getBuffer(); } getPatchLayer() { - return this.getLayeredBuffer().getLayer('patch'); + return this.getPatchBuffer().getLayer('patch'); } getHunkLayer() { - return this.getLayeredBuffer().getLayer('hunk'); + return this.getPatchBuffer().getLayer('hunk'); } getUnchangedLayer() { - return this.getLayeredBuffer().getLayer('unchanged'); + return this.getPatchBuffer().getLayer('unchanged'); } getAdditionLayer() { - return this.getLayeredBuffer().getLayer('addition'); + return this.getPatchBuffer().getLayer('addition'); } getDeletionLayer() { - return this.getLayeredBuffer().getLayer('deletion'); + return this.getPatchBuffer().getLayer('deletion'); } getNoNewlineLayer() { - return this.getLayeredBuffer().getLayer('nonewline'); + return this.getPatchBuffer().getLayer('nonewline'); } getFilePatches() { diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index c86aad5906..ebbbc9f7fd 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -269,7 +269,7 @@ export default class MultiFilePatchView extends React.Component { {/* istanbul ignore next */ atom.inDevMode() && { // eslint-disable-next-line no-console - console.log(this.props.multiFilePatch.getLayeredBuffer().inspect({ + console.log(this.props.multiFilePatch.getPatchBuffer().inspect({ layerNames: ['patch', 'hunk'], })); }} @@ -278,7 +278,7 @@ export default class MultiFilePatchView extends React.Component { {/* istanbul ignore next */ atom.inDevMode() && { // eslint-disable-next-line no-console - console.log(this.props.multiFilePatch.getLayeredBuffer().inspect({ + console.log(this.props.multiFilePatch.getPatchBuffer().inspect({ layerNames: ['unchanged', 'deletion', 'addition', 'nonewline'], })); }} diff --git a/test/models/patch/multi-file-patch.test.js b/test/models/patch/multi-file-patch.test.js index 580da3ddd5..dc61a7dccd 100644 --- a/test/models/patch/multi-file-patch.test.js +++ b/test/models/patch/multi-file-patch.test.js @@ -53,7 +53,7 @@ describe('MultiFilePatch', function() { it('creates a copy with a new PatchBuffer', function() { const {multiFilePatch} = multiFilePatchBuilder().build(); - const dup = original.clone({patchBuffer: multiFilePatch.getLayeredBuffer()}); + const dup = original.clone({patchBuffer: multiFilePatch.getPatchBuffer()}); assert.strictEqual(dup.getBuffer(), multiFilePatch.getBuffer()); assert.strictEqual(dup.getPatchLayer(), multiFilePatch.getPatchLayer()); From fd990ed563a92591bfacc3414807a7c93212a6ee Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Feb 2019 14:56:12 -0500 Subject: [PATCH 2952/4847] Use defaultProps for on(Will|Did)UpdatePatch handlers --- lib/views/multi-file-patch-view.js | 89 +++++++++++++++--------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index ebbbc9f7fd..76fa7e199f 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -2,7 +2,7 @@ import React, {Fragment} from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; import {Range} from 'atom'; -import {CompositeDisposable} from 'event-kit'; +import {CompositeDisposable, Disposable} from 'event-kit'; import {autobind} from '../helpers'; import {addEvent} from '../reporter-proxy'; @@ -71,6 +71,11 @@ export default class MultiFilePatchView extends React.Component { itemType: ItemTypePropType.isRequired, } + static defaultProps = { + onWillUpdatePatch: () => new Disposable(), + onDidUpdatePatch: () => new Disposable(), + } + constructor(props) { super(props); autobind( @@ -108,53 +113,51 @@ export default class MultiFilePatchView extends React.Component { let lastScrollTop = null; let lastScrollLeft = null; let lastSelectionIndex = null; - if (this.props.onWillUpdatePatch && this.props.onDidUpdatePatch) { - this.subs.add( - this.props.onWillUpdatePatch(() => { - this.suppressChanges = true; - this.refEditor.map(editor => { - lastSelectionIndex = this.props.multiFilePatch.getMaxSelectionIndex(this.props.selectedRows); - lastScrollTop = editor.getElement().getScrollTop(); - lastScrollLeft = editor.getElement().getScrollLeft(); - return null; - }); - }), - this.props.onDidUpdatePatch(nextPatch => { - this.refEditor.map(editor => { - /* istanbul ignore else */ - if (lastSelectionIndex !== null) { - const nextSelectionRange = nextPatch.getSelectionRangeForIndex(lastSelectionIndex); - if (this.props.selectionMode === 'line') { - this.nextSelectionMode = 'line'; - editor.setSelectedBufferRange(nextSelectionRange); - } else { - const nextHunks = new Set( - Range.fromObject(nextSelectionRange).getRows() - .map(row => nextPatch.getHunkAt(row)) - .filter(Boolean), - ); + this.subs.add( + this.props.onWillUpdatePatch(() => { + this.suppressChanges = true; + this.refEditor.map(editor => { + lastSelectionIndex = this.props.multiFilePatch.getMaxSelectionIndex(this.props.selectedRows); + lastScrollTop = editor.getElement().getScrollTop(); + lastScrollLeft = editor.getElement().getScrollLeft(); + return null; + }); + }), + this.props.onDidUpdatePatch(nextPatch => { + this.refEditor.map(editor => { + /* istanbul ignore else */ + if (lastSelectionIndex !== null) { + const nextSelectionRange = nextPatch.getSelectionRangeForIndex(lastSelectionIndex); + if (this.props.selectionMode === 'line') { + this.nextSelectionMode = 'line'; + editor.setSelectedBufferRange(nextSelectionRange); + } else { + const nextHunks = new Set( + Range.fromObject(nextSelectionRange).getRows() + .map(row => nextPatch.getHunkAt(row)) + .filter(Boolean), + ); /* istanbul ignore next */ - const nextRanges = nextHunks.size > 0 - ? Array.from(nextHunks, hunk => hunk.getRange()) - : [[[0, 0], [0, 0]]]; + const nextRanges = nextHunks.size > 0 + ? Array.from(nextHunks, hunk => hunk.getRange()) + : [[[0, 0], [0, 0]]]; - this.nextSelectionMode = 'hunk'; - editor.setSelectedBufferRanges(nextRanges); - } + this.nextSelectionMode = 'hunk'; + editor.setSelectedBufferRanges(nextRanges); } + } - /* istanbul ignore else */ - if (lastScrollTop !== null) { editor.getElement().setScrollTop(lastScrollTop); } + /* istanbul ignore else */ + if (lastScrollTop !== null) { editor.getElement().setScrollTop(lastScrollTop); } - /* istanbul ignore else */ - if (lastScrollLeft !== null) { editor.getElement().setScrollLeft(lastScrollLeft); } - return null; - }); - this.suppressChanges = false; - this.didChangeSelectedRows(); - }), - ); - } + /* istanbul ignore else */ + if (lastScrollLeft !== null) { editor.getElement().setScrollLeft(lastScrollLeft); } + return null; + }); + this.suppressChanges = false; + this.didChangeSelectedRows(); + }), + ); } componentDidMount() { From 2ea5184e797f2a21c6060ba56771d2cc0802924c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Feb 2019 14:57:09 -0500 Subject: [PATCH 2953/4847] :fire: unused propTypes --- lib/views/pr-review-comments-view.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comments-view.js index dfdefff8df..636b88d4b1 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comments-view.js @@ -11,13 +11,7 @@ import GithubDotcomMarkdown from './github-dotcom-markdown'; import Timeago from './timeago'; export default class PullRequestCommentsView extends React.Component { - // do we even need the relay props here? does not look like they are used static propTypes = { - relay: PropTypes.shape({ - hasMore: PropTypes.func.isRequired, - loadMore: PropTypes.func.isRequired, - isLoading: PropTypes.func.isRequired, - }).isRequired, commentThreads: PropTypes.arrayOf(PropTypes.shape({ rootCommentId: PropTypes.string.isRequired, comments: PropTypes.arrayOf(PropTypes.object).isRequired, @@ -63,7 +57,6 @@ export default class PullRequestCommentsView extends React.Component { } export class PullRequestCommentView extends React.Component { - static propTypes = { switchToIssueish: PropTypes.func.isRequired, comment: PropTypes.shape({ From 6b4c770f040536390786ea29017bfc3a94ba5ab3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Feb 2019 14:57:51 -0500 Subject: [PATCH 2954/4847] Touch up builder method spelling --- test/builder/pr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/builder/pr.js b/test/builder/pr.js index 52c72a95dc..4b2a0d3613 100644 --- a/test/builder/pr.js +++ b/test/builder/pr.js @@ -17,7 +17,7 @@ class CommentBuilder { return this; } - minmized(m) { + minimized(m) { this._isMinimized = m; return this; } From 3b65cfe3ab367b869f7f5b92fb32a3823b35c776 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 28 Feb 2019 15:01:43 -0500 Subject: [PATCH 2955/4847] Rename ...LayeredBuffer variables to ...PatchBuffer --- test/models/patch/file-patch.test.js | 54 +++++++++++----------- test/models/patch/patch-buffer.test.js | 2 +- test/models/patch/patch.test.js | 62 +++++++++++++------------- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/test/models/patch/file-patch.test.js b/test/models/patch/file-patch.test.js index 4ee102cd27..aa7e8eed52 100644 --- a/test/models/patch/file-patch.test.js +++ b/test/models/patch/file-patch.test.js @@ -180,10 +180,10 @@ describe('FilePatch', function() { }); describe('buildStagePatchForLines()', function() { - let stagedLayeredBuffer; + let stagedPatchBuffer; beforeEach(function() { - stagedLayeredBuffer = new PatchBuffer(); + stagedPatchBuffer = new PatchBuffer(); }); it('returns a new FilePatch that applies only the selected lines', function() { @@ -207,12 +207,12 @@ describe('FilePatch', function() { const newFile = new File({path: 'file.txt', mode: '100644'}); const filePatch = new FilePatch(oldFile, newFile, patch); - const stagedPatch = filePatch.buildStagePatchForLines(buffer, stagedLayeredBuffer, new Set([1, 3])); + const stagedPatch = filePatch.buildStagePatchForLines(buffer, stagedPatchBuffer, new Set([1, 3])); assert.strictEqual(stagedPatch.getStatus(), 'modified'); assert.strictEqual(stagedPatch.getOldFile(), oldFile); assert.strictEqual(stagedPatch.getNewFile(), newFile); - assert.strictEqual(stagedLayeredBuffer.buffer.getText(), '0000\n0001\n0003\n0004\n'); - assertInFilePatch(stagedPatch, stagedLayeredBuffer.buffer).hunks( + assert.strictEqual(stagedPatchBuffer.buffer.getText(), '0000\n0001\n0003\n0004\n'); + assertInFilePatch(stagedPatch, stagedPatchBuffer.buffer).hunks( { startRow: 0, endRow: 3, @@ -250,13 +250,13 @@ describe('FilePatch', function() { }); it('handles staging part of the file', function() { - const stagedPatch = deletionPatch.buildStagePatchForLines(buffer, stagedLayeredBuffer, new Set([1, 2])); + const stagedPatch = deletionPatch.buildStagePatchForLines(buffer, stagedPatchBuffer, new Set([1, 2])); assert.strictEqual(stagedPatch.getStatus(), 'modified'); assert.strictEqual(stagedPatch.getOldFile(), oldFile); assert.strictEqual(stagedPatch.getNewFile(), oldFile); - assert.strictEqual(stagedLayeredBuffer.buffer.getText(), '0000\n0001\n0002\n'); - assertInFilePatch(stagedPatch, stagedLayeredBuffer.buffer).hunks( + assert.strictEqual(stagedPatchBuffer.buffer.getText(), '0000\n0001\n0002\n'); + assertInFilePatch(stagedPatch, stagedPatchBuffer.buffer).hunks( { startRow: 0, endRow: 2, @@ -270,12 +270,12 @@ describe('FilePatch', function() { }); it('handles staging all lines, leaving nothing unstaged', function() { - const stagedPatch = deletionPatch.buildStagePatchForLines(buffer, stagedLayeredBuffer, new Set([0, 1, 2])); + const stagedPatch = deletionPatch.buildStagePatchForLines(buffer, stagedPatchBuffer, new Set([0, 1, 2])); assert.strictEqual(stagedPatch.getStatus(), 'deleted'); assert.strictEqual(stagedPatch.getOldFile(), oldFile); assert.isFalse(stagedPatch.getNewFile().isPresent()); - assert.strictEqual(stagedLayeredBuffer.buffer.getText(), '0000\n0001\n0002\n'); - assertInFilePatch(stagedPatch, stagedLayeredBuffer.buffer).hunks( + assert.strictEqual(stagedPatchBuffer.buffer.getText(), '0000\n0001\n0002\n'); + assertInFilePatch(stagedPatch, stagedPatchBuffer.buffer).hunks( { startRow: 0, endRow: 2, @@ -305,7 +305,7 @@ describe('FilePatch', function() { const newFile = new File({path: 'file.txt', mode: '120000'}); const replacePatch = new FilePatch(oldFile, newFile, patch); - const stagedPatch = replacePatch.buildStagePatchForLines(nBuffer, stagedLayeredBuffer, new Set([0, 1, 2])); + const stagedPatch = replacePatch.buildStagePatchForLines(nBuffer, stagedPatchBuffer, new Set([0, 1, 2])); assert.strictEqual(stagedPatch.getOldFile(), oldFile); assert.isFalse(stagedPatch.getNewFile().isPresent()); }); @@ -313,10 +313,10 @@ describe('FilePatch', function() { }); describe('getUnstagePatchForLines()', function() { - let unstageLayeredBuffer; + let unstagePatchBuffer; beforeEach(function() { - unstageLayeredBuffer = new PatchBuffer(); + unstagePatchBuffer = new PatchBuffer(); }); it('returns a new FilePatch that unstages only the specified lines', function() { @@ -340,12 +340,12 @@ describe('FilePatch', function() { const newFile = new File({path: 'file.txt', mode: '100644'}); const filePatch = new FilePatch(oldFile, newFile, patch); - const unstagedPatch = filePatch.buildUnstagePatchForLines(buffer, unstageLayeredBuffer, new Set([1, 3])); + const unstagedPatch = filePatch.buildUnstagePatchForLines(buffer, unstagePatchBuffer, new Set([1, 3])); assert.strictEqual(unstagedPatch.getStatus(), 'modified'); assert.strictEqual(unstagedPatch.getOldFile(), newFile); assert.strictEqual(unstagedPatch.getNewFile(), newFile); - assert.strictEqual(unstageLayeredBuffer.buffer.getText(), '0000\n0001\n0002\n0003\n0004\n'); - assertInFilePatch(unstagedPatch, unstageLayeredBuffer.buffer).hunks( + assert.strictEqual(unstagePatchBuffer.buffer.getText(), '0000\n0001\n0002\n0003\n0004\n'); + assertInFilePatch(unstagedPatch, unstagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 4, @@ -384,11 +384,11 @@ describe('FilePatch', function() { }); it('handles unstaging part of the file', function() { - const unstagePatch = addedFilePatch.buildUnstagePatchForLines(buffer, unstageLayeredBuffer, new Set([2])); + const unstagePatch = addedFilePatch.buildUnstagePatchForLines(buffer, unstagePatchBuffer, new Set([2])); assert.strictEqual(unstagePatch.getStatus(), 'modified'); assert.strictEqual(unstagePatch.getOldFile(), newFile); assert.strictEqual(unstagePatch.getNewFile(), newFile); - assertInFilePatch(unstagePatch, unstageLayeredBuffer.buffer).hunks( + assertInFilePatch(unstagePatch, unstagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 2, @@ -402,11 +402,11 @@ describe('FilePatch', function() { }); it('handles unstaging all lines, leaving nothing staged', function() { - const unstagePatch = addedFilePatch.buildUnstagePatchForLines(buffer, unstageLayeredBuffer, new Set([0, 1, 2])); + const unstagePatch = addedFilePatch.buildUnstagePatchForLines(buffer, unstagePatchBuffer, new Set([0, 1, 2])); assert.strictEqual(unstagePatch.getStatus(), 'deleted'); assert.strictEqual(unstagePatch.getOldFile(), newFile); assert.isFalse(unstagePatch.getNewFile().isPresent()); - assertInFilePatch(unstagePatch, unstageLayeredBuffer.buffer).hunks( + assertInFilePatch(unstagePatch, unstagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 2, @@ -421,10 +421,10 @@ describe('FilePatch', function() { it('unsets the newFile when a symlink is deleted and a file is created in its place', function() { const oldSymlink = new File({path: 'file.txt', mode: '120000', symlink: 'wat.txt'}); const patch = new FilePatch(oldSymlink, newFile, addedPatch); - const unstagePatch = patch.buildUnstagePatchForLines(buffer, unstageLayeredBuffer, new Set([0, 1, 2])); + const unstagePatch = patch.buildUnstagePatchForLines(buffer, unstagePatchBuffer, new Set([0, 1, 2])); assert.strictEqual(unstagePatch.getOldFile(), newFile); assert.isFalse(unstagePatch.getNewFile().isPresent()); - assertInFilePatch(unstagePatch, unstageLayeredBuffer.buffer).hunks( + assertInFilePatch(unstagePatch, unstagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 2, @@ -459,11 +459,11 @@ describe('FilePatch', function() { }); it('handles unstaging part of the file', function() { - const discardPatch = removedFilePatch.buildUnstagePatchForLines(buffer, unstageLayeredBuffer, new Set([1])); + const discardPatch = removedFilePatch.buildUnstagePatchForLines(buffer, unstagePatchBuffer, new Set([1])); assert.strictEqual(discardPatch.getStatus(), 'added'); assert.strictEqual(discardPatch.getOldFile(), nullFile); assert.strictEqual(discardPatch.getNewFile(), oldFile); - assertInFilePatch(discardPatch, unstageLayeredBuffer.buffer).hunks( + assertInFilePatch(discardPatch, unstagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 0, @@ -478,13 +478,13 @@ describe('FilePatch', function() { it('handles unstaging the entire file', function() { const discardPatch = removedFilePatch.buildUnstagePatchForLines( buffer, - unstageLayeredBuffer, + unstagePatchBuffer, new Set([0, 1, 2]), ); assert.strictEqual(discardPatch.getStatus(), 'added'); assert.strictEqual(discardPatch.getOldFile(), nullFile); assert.strictEqual(discardPatch.getNewFile(), oldFile); - assertInFilePatch(discardPatch, unstageLayeredBuffer.buffer).hunks( + assertInFilePatch(discardPatch, unstagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 2, diff --git a/test/models/patch/patch-buffer.test.js b/test/models/patch/patch-buffer.test.js index 8289c2c55a..44d9e8f48b 100644 --- a/test/models/patch/patch-buffer.test.js +++ b/test/models/patch/patch-buffer.test.js @@ -36,7 +36,7 @@ describe('PatchBuffer', function() { }); describe('extractPatchBuffer', function() { - it('extracts a subset of the buffer and layers as a new LayeredBuffer', function() { + it('extracts a subset of the buffer and layers as a new PatchBuffer', function() { const m0 = patchBuffer.markRange('patch', [[1, 0], [3, 0]]); // before const m1 = patchBuffer.markRange('hunk', [[2, 0], [4, 2]]); // before, ending at the extraction point const m2 = patchBuffer.markRange('hunk', [[4, 2], [5, 0]]); // within diff --git a/test/models/patch/patch.test.js b/test/models/patch/patch.test.js index 5fe2e3050e..796bf2f12a 100644 --- a/test/models/patch/patch.test.js +++ b/test/models/patch/patch.test.js @@ -163,19 +163,19 @@ describe('Patch', function() { }); describe('stage patch generation', function() { - let stageLayeredBuffer; + let stagePatchBuffer; beforeEach(function() { - stageLayeredBuffer = new PatchBuffer(); + stagePatchBuffer = new PatchBuffer(); }); it('creates a patch that applies selected lines from only the first hunk', function() { const {patch, buffer: originalBuffer} = buildPatchFixture(); - const stagePatch = patch.buildStagePatchForLines(originalBuffer, stageLayeredBuffer, new Set([2, 3, 4, 5])); + const stagePatch = patch.buildStagePatchForLines(originalBuffer, stagePatchBuffer, new Set([2, 3, 4, 5])); // buffer rows: 0 1 2 3 4 5 6 const expectedBufferText = '0000\n0001\n0002\n0003\n0004\n0005\n0006\n'; - assert.strictEqual(stageLayeredBuffer.buffer.getText(), expectedBufferText); - assertInPatch(stagePatch, stageLayeredBuffer.buffer).hunks( + assert.strictEqual(stagePatchBuffer.buffer.getText(), expectedBufferText); + assertInPatch(stagePatch, stagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 6, @@ -192,11 +192,11 @@ describe('Patch', function() { it('creates a patch that applies selected lines from a single non-first hunk', function() { const {patch, buffer: originalBuffer} = buildPatchFixture(); - const stagePatch = patch.buildStagePatchForLines(originalBuffer, stageLayeredBuffer, new Set([8, 13, 14, 16])); + const stagePatch = patch.buildStagePatchForLines(originalBuffer, stagePatchBuffer, new Set([8, 13, 14, 16])); // buffer rows: 0 1 2 3 4 5 6 7 8 9 const expectedBufferText = '0007\n0008\n0010\n0011\n0012\n0013\n0014\n0015\n0016\n0018\n'; - assert.strictEqual(stageLayeredBuffer.buffer.getText(), expectedBufferText); - assertInPatch(stagePatch, stageLayeredBuffer.buffer).hunks( + assert.strictEqual(stagePatchBuffer.buffer.getText(), expectedBufferText); + assertInPatch(stagePatch, stagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 9, @@ -216,7 +216,7 @@ describe('Patch', function() { it('creates a patch that applies selected lines from several hunks', function() { const {patch, buffer: originalBuffer} = buildPatchFixture(); - const stagePatch = patch.buildStagePatchForLines(originalBuffer, stageLayeredBuffer, new Set([1, 5, 15, 16, 17, 25])); + const stagePatch = patch.buildStagePatchForLines(originalBuffer, stagePatchBuffer, new Set([1, 5, 15, 16, 17, 25])); const expectedBufferText = // buffer rows // 0 1 2 3 4 @@ -225,8 +225,8 @@ describe('Patch', function() { '0007\n0010\n0011\n0012\n0013\n0014\n0015\n0016\n0017\n0018\n' + // 15 16 17 '0024\n0025\n No newline at end of file\n'; - assert.strictEqual(stageLayeredBuffer.buffer.getText(), expectedBufferText); - assertInPatch(stagePatch, stageLayeredBuffer.buffer).hunks( + assert.strictEqual(stagePatchBuffer.buffer.getText(), expectedBufferText); + assertInPatch(stagePatch, stagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 4, @@ -265,12 +265,12 @@ describe('Patch', function() { it('marks ranges for each change region on the correct marker layer', function() { const {patch, buffer: originalBuffer} = buildPatchFixture(); - patch.buildStagePatchForLines(originalBuffer, stageLayeredBuffer, new Set([1, 5, 15, 16, 17, 25])); + patch.buildStagePatchForLines(originalBuffer, stagePatchBuffer, new Set([1, 5, 15, 16, 17, 25])); const layerRanges = [ Hunk.layerName, Unchanged.layerName, Addition.layerName, Deletion.layerName, NoNewline.layerName, ].reduce((obj, layerName) => { - obj[layerName] = stageLayeredBuffer.findMarkers(layerName, {}).map(marker => marker.getRange().serialize()); + obj[layerName] = stagePatchBuffer.findMarkers(layerName, {}).map(marker => marker.getRange().serialize()); return obj; }, {}); @@ -320,9 +320,9 @@ describe('Patch', function() { const patch = new Patch({status: 'deleted', hunks, marker}); - const stagedPatch = patch.buildStagePatchForLines(buffer, stageLayeredBuffer, new Set([1, 3, 4])); + const stagedPatch = patch.buildStagePatchForLines(buffer, stagePatchBuffer, new Set([1, 3, 4])); assert.strictEqual(stagedPatch.getStatus(), 'modified'); - assertInPatch(stagedPatch, stageLayeredBuffer.buffer).hunks( + assertInPatch(stagedPatch, stagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 5, @@ -353,7 +353,7 @@ describe('Patch', function() { const marker = markRange(layers.patch, 0, 2); const patch = new Patch({status: 'deleted', hunks, marker}); - const stagePatch0 = patch.buildStagePatchForLines(buffer, stageLayeredBuffer, new Set([0, 1, 2])); + const stagePatch0 = patch.buildStagePatchForLines(buffer, stagePatchBuffer, new Set([0, 1, 2])); assert.strictEqual(stagePatch0.getStatus(), 'deleted'); }); @@ -364,21 +364,21 @@ describe('Patch', function() { }); describe('unstage patch generation', function() { - let unstageLayeredBuffer; + let unstagePatchBuffer; beforeEach(function() { - unstageLayeredBuffer = new PatchBuffer(); + unstagePatchBuffer = new PatchBuffer(); }); it('creates a patch that updates the index to unapply selected lines from a single hunk', function() { const {patch, buffer: originalBuffer} = buildPatchFixture(); - const unstagePatch = patch.buildUnstagePatchForLines(originalBuffer, unstageLayeredBuffer, new Set([8, 12, 13])); + const unstagePatch = patch.buildUnstagePatchForLines(originalBuffer, unstagePatchBuffer, new Set([8, 12, 13])); assert.strictEqual( - unstageLayeredBuffer.buffer.getText(), + unstagePatchBuffer.buffer.getText(), // 0 1 2 3 4 5 6 7 8 '0007\n0008\n0009\n0010\n0011\n0012\n0013\n0017\n0018\n', ); - assertInPatch(unstagePatch, unstageLayeredBuffer.buffer).hunks( + assertInPatch(unstagePatch, unstagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 8, @@ -396,9 +396,9 @@ describe('Patch', function() { it('creates a patch that updates the index to unapply lines from several hunks', function() { const {patch, buffer: originalBuffer} = buildPatchFixture(); - const unstagePatch = patch.buildUnstagePatchForLines(originalBuffer, unstageLayeredBuffer, new Set([1, 4, 5, 16, 17, 20, 25])); + const unstagePatch = patch.buildUnstagePatchForLines(originalBuffer, unstagePatchBuffer, new Set([1, 4, 5, 16, 17, 20, 25])); assert.strictEqual( - unstageLayeredBuffer.buffer.getText(), + unstagePatchBuffer.buffer.getText(), // 0 1 2 3 4 5 '0000\n0001\n0003\n0004\n0005\n0006\n' + // 6 7 8 9 10 11 12 13 @@ -408,7 +408,7 @@ describe('Patch', function() { // 17 18 19 '0024\n0025\n No newline at end of file\n', ); - assertInPatch(unstagePatch, unstageLayeredBuffer.buffer).hunks( + assertInPatch(unstagePatch, unstagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 5, @@ -457,11 +457,11 @@ describe('Patch', function() { it('marks ranges for each change region on the correct marker layer', function() { const {patch, buffer: originalBuffer} = buildPatchFixture(); - patch.buildUnstagePatchForLines(originalBuffer, unstageLayeredBuffer, new Set([1, 4, 5, 16, 17, 20, 25])); + patch.buildUnstagePatchForLines(originalBuffer, unstagePatchBuffer, new Set([1, 4, 5, 16, 17, 20, 25])); const layerRanges = [ Hunk.layerName, Unchanged.layerName, Addition.layerName, Deletion.layerName, NoNewline.layerName, ].reduce((obj, layerName) => { - obj[layerName] = unstageLayeredBuffer.findMarkers(layerName, {}).map(marker => marker.getRange().serialize()); + obj[layerName] = unstagePatchBuffer.findMarkers(layerName, {}).map(marker => marker.getRange().serialize()); return obj; }, {}); @@ -512,10 +512,10 @@ describe('Patch', function() { ]; const marker = markRange(layers.patch, 0, 2); const patch = new Patch({status: 'added', hunks, marker}); - const unstagePatch = patch.buildUnstagePatchForLines(buffer, unstageLayeredBuffer, new Set([1, 2])); + const unstagePatch = patch.buildUnstagePatchForLines(buffer, unstagePatchBuffer, new Set([1, 2])); assert.strictEqual(unstagePatch.getStatus(), 'modified'); - assert.strictEqual(unstageLayeredBuffer.buffer.getText(), '0000\n0001\n0002\n'); - assertInPatch(unstagePatch, unstageLayeredBuffer.buffer).hunks( + assert.strictEqual(unstagePatchBuffer.buffer.getText(), '0000\n0001\n0002\n'); + assertInPatch(unstagePatch, unstagePatchBuffer.buffer).hunks( { startRow: 0, endRow: 2, @@ -546,7 +546,7 @@ describe('Patch', function() { const marker = markRange(layers.patch, 0, 2); const patch = new Patch({status: 'added', hunks, marker}); - const unstagePatch = patch.buildUnstagePatchForLines(buffer, unstageLayeredBuffer, new Set([0, 1, 2])); + const unstagePatch = patch.buildUnstagePatchForLines(buffer, unstagePatchBuffer, new Set([0, 1, 2])); assert.strictEqual(unstagePatch.getStatus(), 'deleted'); }); @@ -568,7 +568,7 @@ describe('Patch', function() { const marker = markRange(layers.patch, 0, 2); const patch = new Patch({status: 'deleted', hunks, marker}); - const unstagePatch = patch.buildUnstagePatchForLines(buffer, unstageLayeredBuffer, new Set([0, 1, 2])); + const unstagePatch = patch.buildUnstagePatchForLines(buffer, unstagePatchBuffer, new Set([0, 1, 2])); assert.strictEqual(unstagePatch.getStatus(), 'added'); }); From 8db614da856158790e0d0802d8bbed5237f571c0 Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 28 Feb 2019 16:52:22 -0800 Subject: [PATCH 2956/4847] add details of third iteration --- docs/feature-requests/003-pull-request-review.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 3802a51dbb..d04793a091 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -119,7 +119,7 @@ Clicking "Finish your review" from a comment or clicking "Review Changes" in the This item is opened in the workspace's right dock when the user: * Clicks the review progress bar in the GitHub tab. -* Clicks the "open" button on the review summary footer of a `PullRequestDetailItem`. +* Clicks the "open reviews" button on the review summary footer of a `PullRequestDetailItem`. * Clicks the "<>" button on a review comment in the "Files Changed" tab of a `PullRequestDetailItem`. It shows a scrollable view of all of the reviews and comments associated with a specific pull request, @@ -201,6 +201,12 @@ It was a great improvement, but filtering the diff with radio buttons and checkb - Keep using an editable editor for the diffs, but add some padding. - Introduce a "Reviews" footer to all sub-views to allow creating/submit a review, no matter where you are. +#### Third iteration + +Long comments can disrupt the code editing experience. Our third iteration keeps the review comments in a dock, a la Google Docs. This helps code authors more easily address comments, because they can see the comments and also get them out of the way. + +Since this approach different from previous approaches, we performed a series of [usability studies](https://github.com/github/pe-editor-tools/blob/master/community/usability-testing/atom_rcid_research_summary.md) to validate that users would find this approach useful. + ## Unresolved questions From 37b09dc9da4c99aae316c41c17058de328f58009 Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 28 Feb 2019 17:00:04 -0800 Subject: [PATCH 2957/4847] remove section about review summary tab since we're not implementing that. --- docs/feature-requests/003-pull-request-review.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index d04793a091..70d461456c 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -57,15 +57,8 @@ Clicking on the "Files Changed" tab displays the full, multi-file diff associate ![files](https://user-images.githubusercontent.com/378023/51305826-43ab9d80-1a7f-11e9-8b41-42bc4812d214.png) -Clicking on the "Expand review summaries" control in the filter bar reveals an inline panel that displays the summary of each review created on this pull request, including the review's author, the review's current state, its summary comment, and a progress bar showing how many of the review comments associated with this review have been marked as resolved. -![review summary list panel](https://user-images.githubusercontent.com/378023/51305827-43ab9d80-1a7f-11e9-90be-902e541b805f.png) - -Clicking on "Comments" within each review summary block hides or reveals the review summary comments associated with that review in diff on this tab. Clicking the "Collapse review summaries" control conceals the review summary panel again. - -![review summary list panel with comments](https://user-images.githubusercontent.com/378023/51306485-ca14af00-1a80-11e9-8e52-bb4d55928736.png) - -Beneath the review summary panel is the pull request's combined diff. Diffs are editable, but _only_ if the pull request branch is checked out and the local branch history has not diverged incompatibly from the remote branch history. +Diffs are editable, but _only_ if the pull request branch is checked out and the local branch history has not diverged incompatibly from the remote branch history. For large diffs, the files can be collapsed to get a better overview. From 145d276b4d52256714794abd719344a0690cd758 Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 28 Feb 2019 17:01:47 -0800 Subject: [PATCH 2958/4847] "resolved conversation" buttons are now "mark as resolved" buttons. --- docs/feature-requests/003-pull-request-review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 70d461456c..095e6ae724 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -104,7 +104,7 @@ Clicking "Finish your review" from a comment or clicking "Review Changes" in the ![resolve a review](https://user-images.githubusercontent.com/378023/46927875-c08b3d80-d072-11e8-978b-024111312d79.png) -* Review comments can be resolved by clicking on the "Resolve conversation" buttons. +* Review comments can be resolved by clicking on the "Mark as resolved" buttons. * If the "reply..." editor has non-whitespace content, it is submitted as a final comment first. ### PullRequestReviewsItem From bbb5f2cdcc6684d724bce85fdab83c940bd2ed0a Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 28 Feb 2019 17:46:33 -0800 Subject: [PATCH 2959/4847] the tab is current "files" not "files changed" --- docs/feature-requests/003-pull-request-review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 095e6ae724..240a1bfc9d 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -51,7 +51,7 @@ A panel at the bottom of the pane shows the progress for resolved review comment When the pull request is checked out, an "open" button is shown in the review footer. Clicking "open" opens a `PullRequestReviewsItem` for this pull request's review comments as an item in the right workspace dock. -### Files Changed (tab) +### Files (tab) Clicking on the "Files Changed" tab displays the full, multi-file diff associated with the pull request. This is akin to the "Files changed" tab on dotcom. From bf18eb71672ee3b9c13813929bd5ce00bf8d8c34 Mon Sep 17 00:00:00 2001 From: annthurium Date: Thu, 28 Feb 2019 17:48:53 -0800 Subject: [PATCH 2960/4847] add clarifying point about migrating PullRequestDetailView to dock --- docs/feature-requests/003-pull-request-review.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 240a1bfc9d..7c2625d593 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -200,6 +200,8 @@ Long comments can disrupt the code editing experience. Our third iteration keep Since this approach different from previous approaches, we performed a series of [usability studies](https://github.com/github/pe-editor-tools/blob/master/community/usability-testing/atom_rcid_research_summary.md) to validate that users would find this approach useful. +We may at some point want to migrate the entire PullRequestDetailView from the pane item to the dock, so as not to duplicate information. However, in the interest of getting code review in the editor shipped, we'll keep the pane item around in the short term. + ## Unresolved questions From 3c4580d1f19eae2c6b8fbfa514c4077e1fd68e79 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 28 Feb 2019 17:55:06 -0800 Subject: [PATCH 2961/4847] add new screenshot of PullRequestReviewsItem --- docs/feature-requests/003-pull-request-review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 7c2625d593..36ba29914f 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -117,7 +117,7 @@ This item is opened in the workspace's right dock when the user: It shows a scrollable view of all of the reviews and comments associated with a specific pull request, -![pull request reviews item](https://user-images.githubusercontent.com/378023/51306720-6939a680-1a81-11e9-8eaa-ffd480e3d47f.png) +![pull request reviews item](https://user-images.githubusercontent.com/3781742/53610984-c85f0080-3b81-11e9-9a82-9df43b6410f3.png) Reviews are sorted by "urgency," showing reviews that still need to be addressed at the top. Within each group, sorting is done by "newest first". From 4718550ccef8d64f5a128ebc60b9b98f48aa7a1f Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 28 Feb 2019 18:08:59 -0800 Subject: [PATCH 2962/4847] add screenshot of expanded RCID comment --- docs/feature-requests/003-pull-request-review.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 36ba29914f..9af4f95f1e 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -129,7 +129,14 @@ Reviews are sorted by "urgency," showing reviews that still need to be addressed Clicking on a review summary comment expands or collapses the associated review comments. -Clicking on a review comment opens a `TextEditor` on the corresponding position of the file under review. The clicked review comment is highlighted as the "current" one. +screen shot 2019-02-28 at 6 03 50 pm + +In addition to the comment, users see an abbreviated version of the diff, with 4 context lines. + +Clicking on the "Jump To File" button opens a `TextEditor` on the corresponding position of the file under review. The clicked review comment is highlighted as the "current" one. + +Clicking on the "View Changes" button opens the "Files" tab of the `PullRequestDetailsView`, so the user can see the full diff. + #### Within an open TextEditor From 6dd375269107368d17e05bf950827d6761937b96 Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 28 Feb 2019 18:13:45 -0800 Subject: [PATCH 2963/4847] update footer screenshot --- docs/feature-requests/003-pull-request-review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index 9af4f95f1e..a4823c9aad 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -45,7 +45,7 @@ Below the tabs is a "tools bar" with controls to toggle review comments or colla #### Footer -![reviews panel](https://user-images.githubusercontent.com/378023/51305353-f2e77500-1a7d-11e9-96f0-da879d49da3a.png) +![reviews panel](https://user-images.githubusercontent.com/3781742/53611708-5805ae80-3b84-11e9-915d-fb29476e3001.png) A panel at the bottom of the pane shows the progress for resolved review comments. It also has a "Review Changes" button to create a new review. This panel is persistent throughout all sub-views. It allows creating new reviews no matter where you are. From 51e2f848b86a75341b9f3f4da57be990f7506b5e Mon Sep 17 00:00:00 2001 From: Tilde Ann Thurium Date: Thu, 28 Feb 2019 18:16:36 -0800 Subject: [PATCH 2964/4847] clarify button copy --- docs/feature-requests/003-pull-request-review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/feature-requests/003-pull-request-review.md b/docs/feature-requests/003-pull-request-review.md index a4823c9aad..920072e4bd 100644 --- a/docs/feature-requests/003-pull-request-review.md +++ b/docs/feature-requests/003-pull-request-review.md @@ -49,7 +49,7 @@ Below the tabs is a "tools bar" with controls to toggle review comments or colla A panel at the bottom of the pane shows the progress for resolved review comments. It also has a "Review Changes" button to create a new review. This panel is persistent throughout all sub-views. It allows creating new reviews no matter where you are. -When the pull request is checked out, an "open" button is shown in the review footer. Clicking "open" opens a `PullRequestReviewsItem` for this pull request's review comments as an item in the right workspace dock. +When the pull request is checked out, an "Open Reviews" button is shown in the review footer. Clicking "Open Reviews" opens a `PullRequestReviewsItem` for this pull request's review comments as an item in the right workspace dock. ### Files (tab) From d1cf331cf5bc23aec91b8521749dfeef624d4475 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 09:32:49 -0500 Subject: [PATCH 2965/4847] Stub out "Reviews" component tree --- lib/containers/reviews-container.js | 7 +++++++ lib/controllers/reviews-controller.js | 7 +++++++ lib/items/reviews-item.js | 7 +++++++ lib/views/reviews-view.js | 7 +++++++ 4 files changed, 28 insertions(+) create mode 100644 lib/containers/reviews-container.js create mode 100644 lib/controllers/reviews-controller.js create mode 100644 lib/items/reviews-item.js create mode 100644 lib/views/reviews-view.js diff --git a/lib/containers/reviews-container.js b/lib/containers/reviews-container.js new file mode 100644 index 0000000000..8a531f7521 --- /dev/null +++ b/lib/containers/reviews-container.js @@ -0,0 +1,7 @@ +import React from 'react'; + +export default class ReviewsContainer extends React.Component { + render() { + return null; + } +} diff --git a/lib/controllers/reviews-controller.js b/lib/controllers/reviews-controller.js new file mode 100644 index 0000000000..cfac131b33 --- /dev/null +++ b/lib/controllers/reviews-controller.js @@ -0,0 +1,7 @@ +import React from 'react'; + +export default class ReviewsController extends React.Component { + render() { + return null; + } +} diff --git a/lib/items/reviews-item.js b/lib/items/reviews-item.js new file mode 100644 index 0000000000..83d44c4fcc --- /dev/null +++ b/lib/items/reviews-item.js @@ -0,0 +1,7 @@ +import React from 'react'; + +export default class ReviewsItem extends React.Component { + render() { + return null; + } +} diff --git a/lib/views/reviews-view.js b/lib/views/reviews-view.js new file mode 100644 index 0000000000..4e92166fae --- /dev/null +++ b/lib/views/reviews-view.js @@ -0,0 +1,7 @@ +import React from 'react'; + +export default class ReviewsView extends React.Component { + render() { + return null; + } +} From 2840bd44c86a191e030783509730cf9a8bcdd8aa Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 10:16:19 -0500 Subject: [PATCH 2966/4847] Item boilerplate for ReviewsItem --- lib/items/reviews-item.js | 76 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/lib/items/reviews-item.js b/lib/items/reviews-item.js index 83d44c4fcc..17c85428cb 100644 --- a/lib/items/reviews-item.js +++ b/lib/items/reviews-item.js @@ -1,7 +1,81 @@ import React from 'react'; +import PropTypes from 'prop-types'; +import {Emitter} from 'event-kit'; + +import {GithubLoginModelPropType, WorkdirContextPoolPropType} from '../prop-types'; +import ReviewsContainer from '../containers/reviews-container'; export default class ReviewsItem extends React.Component { + static propTypes = { + // Parsed from URI + host: PropTypes.string.isRequired, + owner: PropTypes.string.isRequired, + repo: PropTypes.string.isRequired, + number: PropTypes.number.isRequired, + workdir: PropTypes.string.isRequired, + + // Package models + workdirContextPool: WorkdirContextPoolPropType.isRequired, + loginModel: GithubLoginModelPropType.isRequired, + } + + static uriPattern = 'atom-github://reviews/{host}/{owner}/{repo}/{number}?workdir={workdir}' + + static buildURI(host, owner, repo, number, workdir) { + return 'atom-github://reviews/' + + encodeURIComponent(host) + '/' + + encodeURIComponent(owner) + '/' + + encodeURIComponent(repo) + '/' + + encodeURIComponent(number) + '?workdir=' + encodeURIComponent(workdir); + } + + constructor(props) { + super(props); + + this.emitter = new Emitter(); + this.isDestroyed = false; + } + render() { - return null; + return ( + + ); + } + + getTitle() { + return `Reviews #${this.props.number}`; + } + + getDefaultLocation() { + return 'right'; + } + + getPreferredWidth() { + return 400; + } + + destroy() { + /* istanbul ignore else */ + if (!this.isDestroyed) { + this.emitter.emit('did-destroy'); + this.isDestroyed = true; + } + } + + onDidDestroy(callback) { + return this.emitter.on('did-destroy', callback); + } + + serialize() { + return { + deserializer: 'ReviewsStub', + uri: this.constructor.buildURI( + this.props.host, + this.props.owner, + this.props.repo, + this.props.number, + this.props.workdir, + ), + }; } } From 66658d7e63d73886e9c84f62ea758597c1b54ab1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 10:57:06 -0500 Subject: [PATCH 2967/4847] ReviewsContainer boilerplate: API token, repository data, and GraphQL --- lib/containers/reviews-container.js | 142 +++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) diff --git a/lib/containers/reviews-container.js b/lib/containers/reviews-container.js index 8a531f7521..7de75d094e 100644 --- a/lib/containers/reviews-container.js +++ b/lib/containers/reviews-container.js @@ -1,7 +1,147 @@ import React from 'react'; +import PropTypes from 'prop-types'; +import yubikiri from 'yubikiri'; +import {QueryRenderer, graphql} from 'react-relay'; + +import {PAGE_SIZE} from '../helpers'; +import {GithubLoginModelPropType, EndpointPropType} from '../prop-types'; +import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy'; +import ObserveModel from '../views/observe-model'; +import LoadingView from '../views/loading-view'; +import GithubLoginView from '../views/github-login-view'; +import QueryErrorView from '../views/query-error-view'; +import RelayNetworkLayerManager from '../relay-network-layer-manager'; +import RelayEnvironment from '../views/relay-environment'; +import ReviewsController from '../controllers/reviews-controller'; export default class ReviewsContainer extends React.Component { + static propTypes = { + // Connection + endpoint: EndpointPropType.isRequired, + + // Pull request selection criteria + owner: PropTypes.string.isRequired, + repo: PropTypes.string.isRequired, + number: PropTypes.number.isRequired, + + // Package models + repository: PropTypes.object.isRequired, + loginModel: GithubLoginModelPropType.isRequired, + } + render() { - return null; + return ( + + {tokenData => this.renderWithToken(tokenData)} + + ); + } + + renderWithToken(tokenData) { + if (!tokenData) { + return ; + } + + if (tokenData.token === UNAUTHENTICATED) { + return ; + } + + if (tokenData.token === INSUFFICIENT) { + return ( + +

    + Your token no longer has sufficient authorizations. Please re-authenticate and generate a new one. +

    +
    + ); + } + + return ( + + {repoData => this.renderWithRepositoryData(repoData, tokenData.token)} + + ); } + + renderWithRepositoryData(repoData, token) { + if (!repoData) { + return ; + } + + const environment = RelayNetworkLayerManager.getEnvironmentForHost(this.props.endpoint, token); + const query = graphql` + query reviewsContainerQuery + ( + $repoOwner: String! + $repoName: String! + $prNumber: Int! + $reviewCount: Int! + $reviewCursor: String + $commentCount: Int! + $commentCursor: String + ) { + repository(owner: $repoOwner, name: $repoName) { + id + } + } + `; + const variables = { + repoOwner: this.props.owner, + repoName: this.props.repo, + prNumber: this.props.number, + reviewCount: PAGE_SIZE, + reviewCursor: null, + commentCount: PAGE_SIZE, + commentCursor: null, + }; + + return ( + + this.renderWithResult(queryResult, repoData)} + /> + + ); + } + + renderWithResult({error, props, retry}, repoData) { + if (error) { + return ( + + ); + } + + if (!props) { + return ; + } + + return ( + + ); + } + + fetchToken = loginModel => loginModel.getToken(this.props.endpoint.getLoginAccount()); + + fetchRepositoryData = repository => { + return yubikiri({ + branches: repository.getBranches(), + isLoading: repository.isLoading(), + isPresent: repository.isPresent(), + }); + } + + handleLogin = token => this.props.loginModel.setToken(this.props.endpoint.getLoginAccount(), token); + + handleLogout = this.props.loginModel.removeToken(this.props.endpoint.getLoginAccount()); } From d82a26893c1dc258fad8cf68230c62e2c7b6d7c6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 10:57:25 -0500 Subject: [PATCH 2968/4847] Derive and pass repository and endpoint in ReviewsItem --- lib/items/reviews-item.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/items/reviews-item.js b/lib/items/reviews-item.js index 17c85428cb..f8fbb0df01 100644 --- a/lib/items/reviews-item.js +++ b/lib/items/reviews-item.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import {Emitter} from 'event-kit'; import {GithubLoginModelPropType, WorkdirContextPoolPropType} from '../prop-types'; +import {getEndpoint} from '../models/endpoint'; import ReviewsContainer from '../containers/reviews-container'; export default class ReviewsItem extends React.Component { @@ -37,8 +38,15 @@ export default class ReviewsItem extends React.Component { } render() { + const endpoint = getEndpoint(this.props.host); + const repository = this.props.workdirContextPool.add(this.props.workdir).getRepository(); + return ( - + ); } From df61f33237104c69042b82276cdd22f37174ac9f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 10:57:36 -0500 Subject: [PATCH 2969/4847] Render ReviewsView from ReviewsController --- lib/controllers/reviews-controller.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/controllers/reviews-controller.js b/lib/controllers/reviews-controller.js index cfac131b33..e586fda16f 100644 --- a/lib/controllers/reviews-controller.js +++ b/lib/controllers/reviews-controller.js @@ -1,7 +1,13 @@ import React from 'react'; +import ReviewsView from '../views/reviews-view'; + export default class ReviewsController extends React.Component { render() { - return null; + return ( + + ); } } From 44f214aa0bc4bc4a72569711a58695ada739aac8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 10:57:44 -0500 Subject: [PATCH 2970/4847] Placeholder ReviewsView --- lib/views/reviews-view.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/views/reviews-view.js b/lib/views/reviews-view.js index 4e92166fae..ce8ec6b45d 100644 --- a/lib/views/reviews-view.js +++ b/lib/views/reviews-view.js @@ -1,7 +1,13 @@ import React from 'react'; +import {inspect} from 'util'; export default class ReviewsView extends React.Component { render() { - return null; + return ( +
    +

    HELL YEAH PR REVIEW COMMENTS

    +
    {inspect(this.props, {depth: 4})}
    +
    + ); } } From c6926e35bf67395cfd8fbfb3a4b70b061c2a2134 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 11:01:21 -0500 Subject: [PATCH 2971/4847] Register ReviewsItem opener in RootController --- lib/controllers/root-controller.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/controllers/root-controller.js b/lib/controllers/root-controller.js index b911f11b3e..e83f80ad6b 100644 --- a/lib/controllers/root-controller.js +++ b/lib/controllers/root-controller.js @@ -22,6 +22,7 @@ import CommitDetailItem from '../items/commit-detail-item'; import CommitPreviewItem from '../items/commit-preview-item'; import GitTabItem from '../items/git-tab-item'; import GitHubTabItem from '../items/github-tab-item'; +import ReviewsItem from '../items/reviews-item'; import StatusBarTileController from './status-bar-tile-controller'; import RepositoryConflictController from './repository-conflict-controller'; import GitCacheView from '../views/git-cache-view'; @@ -425,6 +426,22 @@ export default class RootController extends React.Component { /> )} + + {({itemHolder, params}) => ( + + )} + {({itemHolder}) => } From c68452a04027d821b3ee6818d94d1dcaddbbeb7d Mon Sep 17 00:00:00 2001 From: annthurium Date: Fri, 1 Mar 2019 08:38:20 -0800 Subject: [PATCH 2972/4847] add `ReviewsFooterView` component --- lib/views/pr-detail-view.js | 8 ++----- lib/views/reviews-footer-view.js | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 lib/views/reviews-footer-view.js diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index 92d660b024..794842b55a 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -15,6 +15,7 @@ import EmojiReactionsView from '../views/emoji-reactions-view'; import IssueishBadge from '../views/issueish-badge'; import PrCommitsView from '../views/pr-commits-view'; import PrStatusesView from '../views/pr-statuses-view'; +import ReviewsFooterView from '../views/reviews-footer-view'; import {PAGE_SIZE} from '../helpers'; class CheckoutState { @@ -275,12 +276,7 @@ export class BarePullRequestDetailView extends React.Component { {this.renderPullRequestBody(pullRequest)} - - +
    ); diff --git a/lib/views/reviews-footer-view.js b/lib/views/reviews-footer-view.js new file mode 100644 index 0000000000..1e444f2943 --- /dev/null +++ b/lib/views/reviews-footer-view.js @@ -0,0 +1,39 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + + +export default class ReviewsFooterView extends React.Component { + static propTypes = { + commentsResolved: PropTypes.number.isRequired, + totalComments: PropTypes.number.isRequired, + }; + + render() { + return ( +
    + + Reviews + + + + Resolved{' '} + + {this.props.commentsResolved} + + {' '}of{' '} + + {this.props.totalComments} + {' '}comments + + + {' '}comments{' '} + + + + +
    + ); + } +} From 0efc6a5c4ad565cac49d800a1bd681135d9ed36f Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 14:49:52 -0500 Subject: [PATCH 2973/4847] Serialization and deserialization for ReviewsItems --- lib/github-package.js | 10 ++++++++++ lib/items/reviews-item.js | 2 +- package.json | 3 ++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/github-package.js b/lib/github-package.js index 092c8eb6fa..ae96b0fa0c 100644 --- a/lib/github-package.js +++ b/lib/github-package.js @@ -394,6 +394,16 @@ export default class GithubPackage { return item; } + createReviewsStub({uri}) { + const item = StubItem.create('github-reviews', { + title: 'Reviews', + }, uri); + if (this.controller) { + this.rerender(); + } + return item; + } + destroyGitTabItem() { if (this.gitTabStubItem) { this.gitTabStubItem.destroy(); diff --git a/lib/items/reviews-item.js b/lib/items/reviews-item.js index f8fbb0df01..95369545b7 100644 --- a/lib/items/reviews-item.js +++ b/lib/items/reviews-item.js @@ -77,7 +77,7 @@ export default class ReviewsItem extends React.Component { serialize() { return { deserializer: 'ReviewsStub', - uri: this.constructor.buildURI( + uri: ReviewsItem.buildURI( this.props.host, this.props.owner, this.props.repo, diff --git a/package.json b/package.json index 056387db25..f6293da2b1 100644 --- a/package.json +++ b/package.json @@ -204,7 +204,8 @@ "GithubDockItem": "createDockItemStub", "FilePatchControllerStub": "createFilePatchControllerStub", "CommitPreviewStub": "createCommitPreviewStub", - "CommitDetailStub": "createCommitDetailStub" + "CommitDetailStub": "createCommitDetailStub", + "ReviewsStub": "createReviewsStub" }, "greenkeeper": { "ignore": [ From 3a4aee94edf793392cc74025a837ab5100fea8f5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 14:50:20 -0500 Subject: [PATCH 2974/4847] Plumbing to open the ReviewsItem from the ReviewsFooterView --- lib/controllers/issueish-detail-controller.js | 22 +++++++++++++++++++ lib/views/pr-detail-view.js | 7 +++++- lib/views/reviews-footer-view.js | 5 ++++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/lib/controllers/issueish-detail-controller.js b/lib/controllers/issueish-detail-controller.js index c704a8ebed..5beb3642a5 100644 --- a/lib/controllers/issueish-detail-controller.js +++ b/lib/controllers/issueish-detail-controller.js @@ -10,6 +10,7 @@ import EnableableOperation from '../models/enableable-operation'; import PullRequestDetailView, {checkoutStates} from '../views/pr-detail-view'; import IssueDetailView from '../views/issue-detail-view'; import CommitDetailItem from '../items/commit-detail-item'; +import ReviewsItem from '../items/reviews-item'; import {incrementCounter, addEvent} from '../reporter-proxy'; export class BareIssueishDetailController extends React.Component { @@ -132,6 +133,7 @@ export class BareIssueishDetailController extends React.Component { repository={repository} pullRequest={repository.pullRequest} checkoutOp={this.checkoutOp} + openReviews={this.openReviews} switchToIssueish={this.props.switchToIssueish} endpoint={this.props.endpoint} @@ -290,6 +292,26 @@ export class BareIssueishDetailController extends React.Component { await this.props.workspace.open(uri, {pending: true}); addEvent('open-commit-in-pane', {package: 'github', from: this.constructor.name}); } + + openReviews = async () => { + if (!this.props.workdirPath) { + return; + } + + if (this.state.typename !== 'PullRequest') { + return; + } + + const uri = ReviewsItem.buildURI( + this.props.endpoint.getHost(), + this.props.repository.owner.login, + this.props.repository.name, + this.props.issueishNumber, + this.props.workdirPath, + ); + await this.props.workspace.open(uri); + addEvent('open-reviews-tab', {package: 'github', from: this.constructor.name}); + } } export default createFragmentContainer(BareIssueishDetailController, { diff --git a/lib/views/pr-detail-view.js b/lib/views/pr-detail-view.js index 794842b55a..1f8cc76955 100644 --- a/lib/views/pr-detail-view.js +++ b/lib/views/pr-detail-view.js @@ -41,6 +41,7 @@ export class BarePullRequestDetailView extends React.Component { relay: PropTypes.shape({ refetch: PropTypes.func.isRequired, }), + openReviews: PropTypes.func.isRequired, switchToIssueish: PropTypes.func.isRequired, checkoutOp: EnableableOperationPropType.isRequired, repository: PropTypes.shape({ @@ -276,7 +277,11 @@ export class BarePullRequestDetailView extends React.Component { {this.renderPullRequestBody(pullRequest)} - +
    ); diff --git a/lib/views/reviews-footer-view.js b/lib/views/reviews-footer-view.js index 1e444f2943..8ad8a671ed 100644 --- a/lib/views/reviews-footer-view.js +++ b/lib/views/reviews-footer-view.js @@ -6,6 +6,9 @@ export default class ReviewsFooterView extends React.Component { static propTypes = { commentsResolved: PropTypes.number.isRequired, totalComments: PropTypes.number.isRequired, + + // Controller actions + openReviews: PropTypes.func.isRequired, }; render() { @@ -31,7 +34,7 @@ export default class ReviewsFooterView extends React.Component { + onClick={this.props.openReviews}>Open reviews
    ); From 78a6c64566036ce8f02b2bf3b306f640591a6988 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 14:53:27 -0500 Subject: [PATCH 2975/4847] Generate Relay files for the stub query in ReviewsContainer --- .../reviewsContainerQuery.graphql.js | 114 ++++++++++++++++++ lib/containers/reviews-container.js | 10 +- 2 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 lib/containers/__generated__/reviewsContainerQuery.graphql.js diff --git a/lib/containers/__generated__/reviewsContainerQuery.graphql.js b/lib/containers/__generated__/reviewsContainerQuery.graphql.js new file mode 100644 index 0000000000..df5eb0e96a --- /dev/null +++ b/lib/containers/__generated__/reviewsContainerQuery.graphql.js @@ -0,0 +1,114 @@ +/** + * @flow + * @relayHash 68140a8082e21c7d56516fb6ca6c8db7 + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest } from 'relay-runtime'; +export type reviewsContainerQueryVariables = {| + repoOwner: string, + repoName: string, +|}; +export type reviewsContainerQueryResponse = {| + +repository: ?{| + +id: string + |} +|}; +export type reviewsContainerQuery = {| + variables: reviewsContainerQueryVariables, + response: reviewsContainerQueryResponse, +|}; +*/ + + +/* +query reviewsContainerQuery( + $repoOwner: String! + $repoName: String! +) { + repository(owner: $repoOwner, name: $repoName) { + id + } +} +*/ + +const node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "LocalArgument", + "name": "repoOwner", + "type": "String!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "repoName", + "type": "String!", + "defaultValue": null + } +], +v1 = [ + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": [ + { + "kind": "Variable", + "name": "name", + "variableName": "repoName", + "type": "String!" + }, + { + "kind": "Variable", + "name": "owner", + "variableName": "repoOwner", + "type": "String!" + } + ], + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null + } + ] + } +]; +return { + "kind": "Request", + "fragment": { + "kind": "Fragment", + "name": "reviewsContainerQuery", + "type": "Query", + "metadata": null, + "argumentDefinitions": (v0/*: any*/), + "selections": (v1/*: any*/) + }, + "operation": { + "kind": "Operation", + "name": "reviewsContainerQuery", + "argumentDefinitions": (v0/*: any*/), + "selections": (v1/*: any*/) + }, + "params": { + "operationKind": "query", + "name": "reviewsContainerQuery", + "id": null, + "text": "query reviewsContainerQuery(\n $repoOwner: String!\n $repoName: String!\n) {\n repository(owner: $repoOwner, name: $repoName) {\n id\n }\n}\n", + "metadata": {} + } +}; +})(); +// prettier-ignore +(node/*: any*/).hash = '2a432f9e2a062215c96118ec0b5070cd'; +module.exports = node; diff --git a/lib/containers/reviews-container.js b/lib/containers/reviews-container.js index 7de75d094e..e0e1b4310c 100644 --- a/lib/containers/reviews-container.js +++ b/lib/containers/reviews-container.js @@ -74,11 +74,11 @@ export default class ReviewsContainer extends React.Component { ( $repoOwner: String! $repoName: String! - $prNumber: Int! - $reviewCount: Int! - $reviewCursor: String - $commentCount: Int! - $commentCursor: String + # $prNumber: Int! + # $reviewCount: Int! + # $reviewCursor: String + # $commentCount: Int! + # $commentCursor: String ) { repository(owner: $repoOwner, name: $repoName) { id From 41b88dcdcafad28c623c7f873de896c10836376e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 15:01:44 -0500 Subject: [PATCH 2976/4847] fetchToken() returns the token alone, not wrapped in an object --- lib/containers/reviews-container.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/containers/reviews-container.js b/lib/containers/reviews-container.js index e0e1b4310c..81cd707a27 100644 --- a/lib/containers/reviews-container.js +++ b/lib/containers/reviews-container.js @@ -37,16 +37,16 @@ export default class ReviewsContainer extends React.Component { ); } - renderWithToken(tokenData) { - if (!tokenData) { + renderWithToken(token) { + if (!token) { return ; } - if (tokenData.token === UNAUTHENTICATED) { + if (token === UNAUTHENTICATED) { return ; } - if (tokenData.token === INSUFFICIENT) { + if (token === INSUFFICIENT) { return (

    @@ -58,7 +58,7 @@ export default class ReviewsContainer extends React.Component { return ( - {repoData => this.renderWithRepositoryData(repoData, tokenData.token)} + {repoData => this.renderWithRepositoryData(repoData, token)} ); } @@ -143,5 +143,5 @@ export default class ReviewsContainer extends React.Component { handleLogin = token => this.props.loginModel.setToken(this.props.endpoint.getLoginAccount(), token); - handleLogout = this.props.loginModel.removeToken(this.props.endpoint.getLoginAccount()); + handleLogout = () => this.props.loginModel.removeToken(this.props.endpoint.getLoginAccount()); } From 062e20e84235946dd201d79bb89e10aa8ca9e694 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 15:38:36 -0500 Subject: [PATCH 2977/4847] Stub tests for ReviewsItem --- test/items/reviews-item.test.js | 110 ++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 test/items/reviews-item.test.js diff --git a/test/items/reviews-item.test.js b/test/items/reviews-item.test.js new file mode 100644 index 0000000000..f5fb363f31 --- /dev/null +++ b/test/items/reviews-item.test.js @@ -0,0 +1,110 @@ +import React from 'react'; +import {mount} from 'enzyme'; + +import ReviewsItem from '../../lib/items/reviews-item'; +import {cloneRepository} from '../helpers'; +import PaneItem from '../../lib/atom/pane-item'; +import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; +import GithubLoginModel from '../../lib/models/github-login-model'; +import WorkdirContextPool from '../../lib/models/workdir-context-pool'; + +describe('ReviewsItem', function() { + let atomEnv, repository, pool; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + const workdir = await cloneRepository(); + + pool = new WorkdirContextPool({ + workspace: atomEnv.workspace, + }); + + repository = pool.add(workdir).getRepository(); + }); + + afterEach(function() { + atomEnv.destroy(); + pool.clear(); + }); + + function buildPaneApp(override = {}) { + const props = { + workdirContextPool: pool, + loginModel: new GithubLoginModel(InMemoryStrategy), + ...override, + }; + + return ( + + {({itemHolder, params}) => ( + + )} + + ); + } + + async function open(wrapper, options = {}) { + const opts = { + host: 'github.com', + owner: 'atom', + repo: 'github', + number: 1848, + workdir: repository.getWorkingDirectoryPath(), + ...options, + }; + + const uri = ReviewsItem.buildURI(opts.host, opts.owner, opts.repo, opts.number, opts.workdir); + const item = await atomEnv.workspace.open(uri); + wrapper.update(); + return item; + } + + it('constructs and opens the correct URI', async function() { + const wrapper = mount(buildPaneApp()); + assert.isFalse(wrapper.exists('ReviewsItem')); + await open(wrapper); + assert.isTrue(wrapper.exists('ReviewsItem')); + }); + + it('locates the repository from the context pool', async function() { + const wrapper = mount(buildPaneApp()); + await open(wrapper); + + assert.strictEqual(wrapper.find('ReviewsContainer').prop('repository'), repository); + }); + + it('returns a title containing the pull request number', async function() { + const wrapper = mount(buildPaneApp()); + const item = await open(wrapper, {number: 1234}); + + assert.strictEqual(item.getTitle(), 'Reviews #1234'); + }); + + it('may be destroyed once', async function() { + const wrapper = mount(buildPaneApp()); + + const item = await open(wrapper); + const callback = sinon.spy(); + const sub = item.onDidDestroy(callback); + + assert.strictEqual(callback.callCount, 0); + item.destroy(); + assert.strictEqual(callback.callCount, 1); + + sub.dispose(); + }); + + it('serializes itself as a ReviewsItemStub', async function() { + const wrapper = mount(buildPaneApp()); + const item = await open(wrapper, {host: 'github.horse', owner: 'atom', repo: 'atom', number: 12, workdir: '/here'}); + assert.deepEqual(item.serialize(), { + deserializer: 'ReviewsStub', + uri: 'atom-github://reviews/github.horse/atom/atom/12?workdir=%2Fhere', + }); + }); +}); From a281f7061e379622707f7436becb955bc7f722bc Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 15:45:24 -0500 Subject: [PATCH 2978/4847] Stub test for ReviewsContainer --- test/containers/reviews-container.test.js | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 test/containers/reviews-container.test.js diff --git a/test/containers/reviews-container.test.js b/test/containers/reviews-container.test.js new file mode 100644 index 0000000000..77075e6c85 --- /dev/null +++ b/test/containers/reviews-container.test.js @@ -0,0 +1,46 @@ +import React from 'react'; +import {mount} from 'enzyme'; + +import ReviewsContainer from '../../lib/containers/reviews-container'; +import Repository from '../../lib/models/repository'; +import {InMemoryStrategy} from '../../lib/shared/keytar-strategy'; +import GithubLoginModel from '../../lib/models/github-login-model'; +import {getEndpoint} from '../../lib/models/endpoint'; +import {cloneRepository} from '../helpers'; + +describe('ReviewsContainer', function() { + let atomEnv, repository, loginModel; + + beforeEach(async function() { + atomEnv = global.buildAtomEnvironment(); + const workdir = await cloneRepository(); + repository = new Repository(workdir); + await repository.getLoadPromise(); + loginModel = new GithubLoginModel(InMemoryStrategy); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + function buildApp(override = {}) { + const props = { + endpoint: getEndpoint('github.com'), + owner: 'atom', + repo: 'github', + number: 1234, + repository, + loginModel, + ...override, + }; + + return ; + } + + it('renders a loading spinner while the token is loading', function() { + sinon.stub(loginModel, 'getToken').returns(new Promise(() => {})); + + const wrapper = mount(buildApp()); + assert.isTrue(wrapper.exists('LoadingView')); + }); +}); From 99162ced2143aa68fb98a2dde405db81ad97d3cd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 15:47:16 -0500 Subject: [PATCH 2979/4847] Stub test for ReviewsController --- test/controllers/reviews-controller.test.js | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 test/controllers/reviews-controller.test.js diff --git a/test/controllers/reviews-controller.test.js b/test/controllers/reviews-controller.test.js new file mode 100644 index 0000000000..273ef953c2 --- /dev/null +++ b/test/controllers/reviews-controller.test.js @@ -0,0 +1,31 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import ReviewsController from '../../lib/controllers/reviews-controller'; + +describe('ReviewsController', function() { + let atomEnv; + + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + function buildApp(override = {}) { + const props = { + ...override, + }; + + return ; + } + + it('renders a ReviewsView', function() { + const extra = Symbol('extra'); + const wrapper = shallow(buildApp({extra})); + assert.isTrue(wrapper.exists('ReviewsView')); + assert.strictEqual(wrapper.find('ReviewsView').prop('extra'), extra); + }); +}); From cc5a2479e1e639a3b0ac5117704488d014dd57ce Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 15:48:47 -0500 Subject: [PATCH 2980/4847] Stub test for ReviewsView --- test/views/reviews-view.test.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 test/views/reviews-view.test.js diff --git a/test/views/reviews-view.test.js b/test/views/reviews-view.test.js new file mode 100644 index 0000000000..736627fc22 --- /dev/null +++ b/test/views/reviews-view.test.js @@ -0,0 +1,29 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import ReviewsView from '../../lib/views/reviews-view'; + +describe('ReviewsView', function() { + let atomEnv; + + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + function buildApp(override = {}) { + const props = { + ...override, + }; + + return ; + } + + it('renders something', function() { + const wrapper = shallow(buildApp()); + assert.isTrue(wrapper.exists('div')); + }); +}); From f0ccde066ed183f772b4fef209bab22c922aaa62 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 1 Mar 2019 15:54:01 -0500 Subject: [PATCH 2981/4847] Stub test for ReviewsFooterView --- test/views/reviews-footer-view.test.js | 44 ++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 test/views/reviews-footer-view.test.js diff --git a/test/views/reviews-footer-view.test.js b/test/views/reviews-footer-view.test.js new file mode 100644 index 0000000000..d4eed8b8d9 --- /dev/null +++ b/test/views/reviews-footer-view.test.js @@ -0,0 +1,44 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import ReviewsFooterView from '../../lib/views/reviews-footer-view'; + +describe('ReviewsFooterView', function() { + let atomEnv; + + beforeEach(function() { + atomEnv = global.buildAtomEnvironment(); + }); + + afterEach(function() { + atomEnv.destroy(); + }); + + function buildApp(override = {}) { + const props = { + commentsResolved: 3, + totalComments: 4, + ...override, + }; + + return ; + } + + it('renders the resolved and total comment counts', function() { + const wrapper = shallow(buildApp({commentsResolved: 4, totalComments: 7})); + + assert.strictEqual(wrapper.find('.github-PrDetailViewReviews-countNr').text(), '4'); + assert.strictEqual(wrapper.find('.github-Reviews-countNr').text(), '7'); + assert.strictEqual(wrapper.find('.github-PrDetailViewReviews-progessBar').prop('value'), 4); + assert.strictEqual(wrapper.find('.github-PrDetailViewReviews-progessBar').prop('max'), 7); + }); + + it('triggers openReviews on button click', function() { + const openReviews = sinon.spy(); + const wrapper = shallow(buildApp({openReviews})); + + wrapper.find('.github-PrDetailViewReviews-openReviewsButton').simulate('click'); + + assert.isTrue(openReviews.called); + }); +}); From c50a80a5c9acac73c9d3775e57fb79e42578078c Mon Sep 17 00:00:00 2001 From: annthurium Date: Fri, 1 Mar 2019 13:47:58 -0800 Subject: [PATCH 2982/4847] style the :foot:er is my emoji too much? SORRY NOT SORRY --- lib/views/reviews-footer-view.js | 23 ++++++++----------- styles/reviews-footer-view.less | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 styles/reviews-footer-view.less diff --git a/lib/views/reviews-footer-view.js b/lib/views/reviews-footer-view.js index 8ad8a671ed..d693d8dcea 100644 --- a/lib/views/reviews-footer-view.js +++ b/lib/views/reviews-footer-view.js @@ -6,36 +6,33 @@ export default class ReviewsFooterView extends React.Component { static propTypes = { commentsResolved: PropTypes.number.isRequired, totalComments: PropTypes.number.isRequired, - - // Controller actions - openReviews: PropTypes.func.isRequired, }; render() { return ( -

    - +
    + Reviews - - + + Resolved{' '} - + {this.props.commentsResolved} {' '}of{' '} - + {this.props.totalComments} {' '}comments - {' '}comments{' '} - - + +
    ); } diff --git a/styles/reviews-footer-view.less b/styles/reviews-footer-view.less new file mode 100644 index 0000000000..6b24b82ad0 --- /dev/null +++ b/styles/reviews-footer-view.less @@ -0,0 +1,39 @@ +@import 'variables'; + +.github-ReviewsFooterView { + + margin-right: auto; + + // Footer ------------------------ + + &-footer { + display: flex; + align-items: center; + padding: @component-padding; + border-top: 1px solid @base-border-color; + background-color: @app-background-color; + } + + &-footerTitle { + font-size: 1.4em; + margin: 0 @component-padding*2 0 0; + } + + &-openReviewsButton, + &-reviewChangesButton { + margin-left: @component-padding; + } + + &-count { + margin-right: @component-padding; + color: @text-color-subtle; + } + + &-countNumber { + color: @text-color-highlight; + } + + &-progessBar { + margin-right: @component-padding; + } +} From e85700cbc170802f94d0a99503c0c1d473a5c164 Mon Sep 17 00:00:00 2001 From: annthurium Date: Fri, 1 Mar 2019 13:50:34 -0800 Subject: [PATCH 2983/4847] fix @smaswilson's changes that I accidentally nerfed Co-Authored-By: Ash Wilson --- lib/views/reviews-footer-view.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/views/reviews-footer-view.js b/lib/views/reviews-footer-view.js index d693d8dcea..f8abded9c1 100644 --- a/lib/views/reviews-footer-view.js +++ b/lib/views/reviews-footer-view.js @@ -6,6 +6,9 @@ export default class ReviewsFooterView extends React.Component { static propTypes = { commentsResolved: PropTypes.number.isRequired, totalComments: PropTypes.number.isRequired, + + // Controller actions + openReviews: PropTypes.func.isRequired, }; render() { @@ -31,7 +34,7 @@ export default class ReviewsFooterView extends React.Component {
    + onClick={this.props.openReviews}>Open reviews
    ); From 2e4bb46819f229ab1251208541c701c6f1dd3fc7 Mon Sep 17 00:00:00 2001 From: annthurium Date: Fri, 1 Mar 2019 14:11:11 -0800 Subject: [PATCH 2984/4847] fix ReviewsFooterView tests --- lib/views/reviews-footer-view.js | 6 +++--- styles/reviews-footer-view.less | 4 ++-- test/views/reviews-footer-view.test.js | 11 ++++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/views/reviews-footer-view.js b/lib/views/reviews-footer-view.js index f8abded9c1..82f41a8155 100644 --- a/lib/views/reviews-footer-view.js +++ b/lib/views/reviews-footer-view.js @@ -18,13 +18,13 @@ export default class ReviewsFooterView extends React.Component { Reviews - + Resolved{' '} - + {this.props.commentsResolved} {' '}of{' '} - + {this.props.totalComments} {' '}comments diff --git a/styles/reviews-footer-view.less b/styles/reviews-footer-view.less index 6b24b82ad0..4a3179b19b 100644 --- a/styles/reviews-footer-view.less +++ b/styles/reviews-footer-view.less @@ -24,12 +24,12 @@ margin-left: @component-padding; } - &-count { + &-commentCount { margin-right: @component-padding; color: @text-color-subtle; } - &-countNumber { + &-commentsResolved { color: @text-color-highlight; } diff --git a/test/views/reviews-footer-view.test.js b/test/views/reviews-footer-view.test.js index d4eed8b8d9..03339076f3 100644 --- a/test/views/reviews-footer-view.test.js +++ b/test/views/reviews-footer-view.test.js @@ -18,6 +18,7 @@ describe('ReviewsFooterView', function() { const props = { commentsResolved: 3, totalComments: 4, + openReviews: () => {}, ...override, }; @@ -27,17 +28,17 @@ describe('ReviewsFooterView', function() { it('renders the resolved and total comment counts', function() { const wrapper = shallow(buildApp({commentsResolved: 4, totalComments: 7})); - assert.strictEqual(wrapper.find('.github-PrDetailViewReviews-countNr').text(), '4'); - assert.strictEqual(wrapper.find('.github-Reviews-countNr').text(), '7'); - assert.strictEqual(wrapper.find('.github-PrDetailViewReviews-progessBar').prop('value'), 4); - assert.strictEqual(wrapper.find('.github-PrDetailViewReviews-progessBar').prop('max'), 7); + assert.strictEqual(wrapper.find('.github-ReviewsFooterView-commentsResolved').text(), '4'); + assert.strictEqual(wrapper.find('.github-ReviewsFooterView-totalComments').text(), '7'); + assert.strictEqual(wrapper.find('.github-ReviewsFooterView-progessBar').prop('value'), 4); + assert.strictEqual(wrapper.find('.github-ReviewsFooterView-progessBar').prop('max'), 7); }); it('triggers openReviews on button click', function() { const openReviews = sinon.spy(); const wrapper = shallow(buildApp({openReviews})); - wrapper.find('.github-PrDetailViewReviews-openReviewsButton').simulate('click'); + wrapper.find('.github-ReviewsFooterView-openReviewsButton').simulate('click'); assert.isTrue(openReviews.called); }); From 4b6787059fd4854e1ec3b8f50c1f626b95823cd9 Mon Sep 17 00:00:00 2001 From: annthurium Date: Fri, 1 Mar 2019 14:24:40 -0800 Subject: [PATCH 2985/4847] add test for footer in `PullRequestDetailView` --- test/fixtures/props/issueish-pane-props.js | 1 + test/views/pr-detail-view.test.js | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/test/fixtures/props/issueish-pane-props.js b/test/fixtures/props/issueish-pane-props.js index cabc7e4140..4fd32e976d 100644 --- a/test/fixtures/props/issueish-pane-props.js +++ b/test/fixtures/props/issueish-pane-props.js @@ -171,6 +171,7 @@ export function pullRequestDetailViewProps(opts, overrides = {}) { switchToIssueish: () => {}, destroy: () => {}, openCommit: () => {}, + openReviews: () => {}, // atom env props workspace: {}, diff --git a/test/views/pr-detail-view.test.js b/test/views/pr-detail-view.test.js index 62364fe02d..99f7ec1e8f 100644 --- a/test/views/pr-detail-view.test.js +++ b/test/views/pr-detail-view.test.js @@ -64,6 +64,14 @@ describe('PullRequestDetailView', function() { assert.strictEqual(wrapper.find('.github-IssueishDetailView-headRefName').text(), headRefName); }); + it('renders footer and passes openReviews prop through', function() { + const wrapper = shallow(buildApp()); + const footer = wrapper.find('ReviewsFooterView'); + assert.lengthOf(footer, 1); + + assert.strictEqual(footer.prop('openReviews'), wrapper.instance().props.openReviews); + }); + it('renders tabs', function() { const pullRequestCommitCount = 11; const pullRequestChangedFileCount = 22; From c57862952da435a95bdec0b1e854fb62b9674c0b Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Fri, 1 Mar 2019 23:32:32 +0000 Subject: [PATCH 2986/4847] chore(package): update sinon to version 7.2.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 056387db25..2b775c3bc5 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "nyc": "13.3.0", "relay-compiler": "3.0.0", "semver": "5.6.0", - "sinon": "7.2.5", + "sinon": "7.2.6", "test-until": "1.1.1" }, "consumedServices": { From a141469609c7ceaf1cf630775e8bf77ff880c351 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Fri, 1 Mar 2019 23:32:36 +0000 Subject: [PATCH 2987/4847] chore(package): update lockfile package-lock.json --- package-lock.json | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3a33c7b5a1..1ee071b868 100644 --- a/package-lock.json +++ b/package-lock.json @@ -864,21 +864,22 @@ "dev": true }, "@sinonjs/commons": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.3.0.tgz", - "integrity": "sha512-j4ZwhaHmwsCb4DlDOIWnI5YyKDNMoNThsmwEpfHx6a1EpsGZ9qYLxP++LMlmBRjtGptGHFsGItJ768snllFWpA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.3.1.tgz", + "integrity": "sha512-rgmZk5CrBGAMATk0HlHOFvo8V44/r+On6cKS80tqid0Eljd+fFBWBOXZp9H2/EB3faxdNdzXTx6QZIKLkbJ7mA==", "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/formatio": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.1.0.tgz", - "integrity": "sha512-ZAR2bPHOl4Xg6eklUGpsdiIJ4+J1SNag1DHHrG/73Uz/nVwXqjgUtRPLoS+aVyieN9cSbc0E4LsU984tWcDyNg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.0.tgz", + "integrity": "sha512-hskkZG4qB0HgsxrPUlnk2EiIyBwntM+ETIxCha/gidl172MCfdosNezB5706ciS5P2VhueM7MoACWwMc4A4gMQ==", "dev": true, "requires": { - "@sinonjs/samsam": "^2 || ^3" + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" } }, "@sinonjs/samsam": { @@ -7453,13 +7454,13 @@ } }, "sinon": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.2.5.tgz", - "integrity": "sha512-1c2KK6g5NQr9XNYCEcUbeFtBpKZD1FXEw0VX7gNhWUBtkchguT2lNdS7XmS7y64OpQWfSNeeV/f8py3NNcQ63Q==", + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.2.6.tgz", + "integrity": "sha512-n5r5wZ/VyrP7oAJpGGGjSxvw2Yy8T+qdGjDBltK01KBqB33O60V/xcG0Hgqm6SbJEIyCGuICpaXg9uFzY5DOYw==", "dev": true, "requires": { "@sinonjs/commons": "^1.3.0", - "@sinonjs/formatio": "^3.1.0", + "@sinonjs/formatio": "^3.2.0", "@sinonjs/samsam": "^3.2.0", "diff": "^3.5.0", "lolex": "^3.1.0", From 46e80515ac5d4537fb6193bc7b80d775f5434a54 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sat, 2 Mar 2019 06:46:22 +0000 Subject: [PATCH 2988/4847] chore(package): update eslint to version 5.15.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b775c3bc5..abdf1fe47e 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "electron-mksnapshot": "~2.0", "enzyme": "3.8.0", "enzyme-adapter-react-16": "1.7.1", - "eslint": "5.14.1", + "eslint": "5.15.0", "eslint-config-fbjs-opensource": "1.0.0", "eslint-plugin-jsx-a11y": "6.2.1", "globby": "9.0.0", From 7adad21fd548eb317383827021545a6898ce5bf5 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sat, 2 Mar 2019 06:46:26 +0000 Subject: [PATCH 2989/4847] chore(package): update lockfile package-lock.json --- package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1ee071b868..31fb13a08c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2511,9 +2511,9 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.14.1.tgz", - "integrity": "sha512-CyUMbmsjxedx8B0mr79mNOqetvkbij/zrXnFeK2zc3pGRn3/tibjiNAv/3UxFEyfMDjh+ZqTrJrEGBFiGfD5Og==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.15.0.tgz", + "integrity": "sha512-xwG7SS5JLeqkiR3iOmVgtF8Y6xPdtr6AAsN6ph7Q6R/fv+3UlKYoika8SmNzmb35qdRF+RfTY35kMEdtbi+9wg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -2522,7 +2522,7 @@ "cross-spawn": "^6.0.5", "debug": "^4.0.1", "doctrine": "^3.0.0", - "eslint-scope": "^4.0.0", + "eslint-scope": "^4.0.2", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", "espree": "^5.0.1", @@ -2682,9 +2682,9 @@ } }, "eslint-scope": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.2.tgz", + "integrity": "sha512-5q1+B/ogmHl8+paxtOKx38Z8LtWkVGuNt3+GQNErqwLl6ViNp/gdJGMCjZNxZ8j/VYjDNZ2Fo+eQc1TAVPIzbg==", "dev": true, "requires": { "esrecurse": "^4.1.0", From baaeb402d72c99ec63fcd3484e6791531d31f444 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sun, 3 Mar 2019 13:22:09 +0000 Subject: [PATCH 2990/4847] chore(package): update globby to version 9.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index abdf1fe47e..3550e4faf9 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "eslint": "5.15.0", "eslint-config-fbjs-opensource": "1.0.0", "eslint-plugin-jsx-a11y": "6.2.1", - "globby": "9.0.0", + "globby": "9.1.0", "hock": "1.3.3", "lodash.isequalwith": "4.4.0", "mkdirp": "0.5.1", From 6ac3d653a1c84977d769caf4c6ef0e49f93d8c69 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sun, 3 Mar 2019 13:22:12 +0000 Subject: [PATCH 2991/4847] chore(package): update lockfile package-lock.json --- package-lock.json | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 31fb13a08c..84dc7ce21d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -899,6 +899,29 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, "@types/node": { "version": "11.9.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.5.tgz", @@ -3374,11 +3397,12 @@ "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==" }, "globby": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-9.0.0.tgz", - "integrity": "sha512-q0qiO/p1w/yJ0hk8V9x1UXlgsXUxlGd0AHUOXZVXBO6aznDtpx7M8D1kBrCAItoPm+4l8r6ATXV1JpjY2SBQOw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.1.0.tgz", + "integrity": "sha512-VtYjhHr7ncls724Of5W6Kaahz0ag7dB4G62/2HsN+xEKG6SrPzM1AJMerGxQTwJGnN9reeyxdvXbuZYpfssCvg==", "dev": true, "requires": { + "@types/glob": "^7.1.1", "array-union": "^1.0.2", "dir-glob": "^2.2.1", "fast-glob": "^2.2.6", From fc95d2ae5daa42bb8dabc3ff4577f7c1a1ab7f9d Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Mon, 4 Mar 2019 12:59:45 +0000 Subject: [PATCH 2992/4847] chore(package): update sinon to version 7.2.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3550e4faf9..b320382bbc 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "nyc": "13.3.0", "relay-compiler": "3.0.0", "semver": "5.6.0", - "sinon": "7.2.6", + "sinon": "7.2.7", "test-until": "1.1.1" }, "consumedServices": { From 289ea022e66fbdd2bd06ffb2fe986ebd4465607b Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Mon, 4 Mar 2019 12:59:52 +0000 Subject: [PATCH 2993/4847] chore(package): update lockfile package-lock.json --- package-lock.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 84dc7ce21d..fb82b96122 100644 --- a/package-lock.json +++ b/package-lock.json @@ -873,9 +873,9 @@ } }, "@sinonjs/formatio": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.0.tgz", - "integrity": "sha512-hskkZG4qB0HgsxrPUlnk2EiIyBwntM+ETIxCha/gidl172MCfdosNezB5706ciS5P2VhueM7MoACWwMc4A4gMQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz", + "integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==", "dev": true, "requires": { "@sinonjs/commons": "^1", @@ -7478,13 +7478,13 @@ } }, "sinon": { - "version": "7.2.6", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.2.6.tgz", - "integrity": "sha512-n5r5wZ/VyrP7oAJpGGGjSxvw2Yy8T+qdGjDBltK01KBqB33O60V/xcG0Hgqm6SbJEIyCGuICpaXg9uFzY5DOYw==", + "version": "7.2.7", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.2.7.tgz", + "integrity": "sha512-rlrre9F80pIQr3M36gOdoCEWzFAMDgHYD8+tocqOw+Zw9OZ8F84a80Ds69eZfcjnzDqqG88ulFld0oin/6rG/g==", "dev": true, "requires": { - "@sinonjs/commons": "^1.3.0", - "@sinonjs/formatio": "^3.2.0", + "@sinonjs/commons": "^1.3.1", + "@sinonjs/formatio": "^3.2.1", "@sinonjs/samsam": "^3.2.0", "diff": "^3.5.0", "lolex": "^3.1.0", From 1935f455904ed552a0d5365e3c7eca1120aa2168 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Mar 2019 10:23:50 -0500 Subject: [PATCH 2994/4847] :art: delete a newline --- lib/containers/pr-review-comments-container.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/containers/pr-review-comments-container.js b/lib/containers/pr-review-comments-container.js index 16051026bd..03749fee74 100644 --- a/lib/containers/pr-review-comments-container.js +++ b/lib/containers/pr-review-comments-container.js @@ -5,7 +5,6 @@ import React from 'react'; import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../helpers'; export class BarePullRequestReviewCommentsContainer extends React.Component { - static propTypes = { collectComments: PropTypes.func.isRequired, review: PropTypes.shape({ From 9bec06acb195214e25115d5e13c1661a567293f5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Mar 2019 10:26:53 -0500 Subject: [PATCH 2995/4847] PullRequestReviewsController calls a render prop with each comment thread This sets us up to render a PullRequestCommentThreadView from MultiFilePatchView and a different view component from the ReviewsItem. --- lib/controllers/pr-reviews-controller.js | 16 ++-- .../controllers/pr-reviews-controller.test.js | 93 ++++++++++++++++--- 2 files changed, 88 insertions(+), 21 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index fdaf09c434..94adeed5a5 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types'; import {RelayConnectionPropType} from '../prop-types'; import PullRequestReviewCommentsContainer from '../containers/pr-review-comments-container'; -import PullRequestReviewCommentsView from '../views/pr-review-comments-view'; import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../helpers'; export default class PullRequestReviewsController extends React.Component { @@ -18,8 +17,7 @@ export default class PullRequestReviewsController extends React.Component { PropTypes.object, ), }), - getBufferRowForDiffPosition: PropTypes.func.isRequired, - isPatchVisible: PropTypes.func.isRequired, + children: PropTypes.func.isRequired, } constructor(props) { @@ -77,12 +75,18 @@ export default class PullRequestReviewsController extends React.Component { * Upon fetching new comments, the `collectComments` method is called with all comments fetched for that review. * Ultimately we want to group comments based on the root comment they are replies to. * `renderCommentFetchingContainers` only fetches data and doesn't render any user visible DOM elements. - * `PullRequestReviewCommentsView` renders the aggregated comment thread data. - * */ + * The child render prop is called with each comment thread. + */ return ( {this.renderCommentFetchingContainers()} - + {commentThreads.map(commentThread => { + return ( + + {this.props.children(commentThread)} + + ); + })} ); } diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index 60e2dbf2be..e90c1d6ca9 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -1,17 +1,23 @@ import React from 'react'; import {shallow} from 'enzyme'; import {reviewBuilder} from '../builder/pr'; +import {inspect} from 'util'; import PullRequestReviewsController from '../../lib/controllers/pr-reviews-controller'; +import PullRequestReviewCommentsContainer from '../../lib/containers/pr-review-comments-container'; import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../../lib/helpers'; +function SomeView(props) { + return
    {inspect(props, {depth: 3})}
    ; +} + describe('PullRequestReviewsController', function() { - function buildApp(opts, overrideProps = {}) { + function buildApp(opts, overrideProps = {}, childFn = SomeView) { const o = { - relayHasMore: () => { return false; }, + relayHasMore: () => false, relayLoadMore: () => {}, - relayIsLoading: () => { return false; }, + relayIsLoading: () => false, reviewSpecs: [], reviewStartCursor: 0, ...opts, @@ -40,14 +46,15 @@ describe('PullRequestReviewsController', function() { loadMore: o.relayLoadMore, isLoading: o.relayIsLoading, }, - - switchToIssueish: () => {}, - getBufferRowForDiffPosition: () => {}, - isPatchVisible: () => true, pullRequest: {reviews}, ...overrideProps, }; - return ; + + return ( + + {childFn} + + ); } it('returns null if props.pullRequest is falsy', function() { const wrapper = shallow(buildApp({}, {pullRequest: null})); @@ -72,17 +79,73 @@ describe('PullRequestReviewsController', function() { assert.strictEqual(containers.at(1).prop('review').id, review2.id); }); - it('renders a PullRequestReviewCommentsView and passes props through', function() { - const review1 = reviewBuilder().build(); - const review2 = reviewBuilder().build(); + it('calls the child render prop for each comment thread', function() { + const review1 = reviewBuilder() + .id(10) + .submittedAt('2019-01-01T10:00:00Z') + .addComment(c => c.id(1)) + .build(); + const review2 = reviewBuilder() + .id(20) + .submittedAt('2019-01-01T11:00:00Z') + .addComment(c => c.id(2)) + .addComment(c => c.id(3).replyTo(1)) + .addComment(c => c.id(4)) + .build(); + + function ChildComponent() { + return
    ; + } const reviewSpecs = [review1, review2]; const passThroughProp = 'I only exist for the children'; - const wrapper = shallow(buildApp({reviewSpecs}, {passThroughProp})); - const view = wrapper.find('PullRequestCommentsView'); - assert.strictEqual(view.length, 1); - assert.strictEqual(wrapper.instance().props.passThroughProp, view.prop('passThroughProp')); + const wrapper = shallow(buildApp({reviewSpecs}, {}, thread => { + return ; + })); + + assert.isFalse(wrapper.exists('ChildComponent')); + + wrapper.find(PullRequestReviewCommentsContainer).at(0).prop('collectComments')({ + reviewId: review1.id, + submittedAt: review1.submittedAt, + comments: review1.comments, + fetchingMoreComments: false, + }); + + assert.lengthOf(wrapper.find('ChildComponent'), 1); + assert.strictEqual(wrapper.find('ChildComponent').at(0).prop('passThroughProp'), passThroughProp); + assert.deepEqual(wrapper.find('ChildComponent').at(0).prop('thread'), { + rootCommentId: '1', + comments: [review1.comments.edges[0].node], + }); + + wrapper.find(PullRequestReviewCommentsContainer).at(1).prop('collectComments')({ + reviewId: review2.id, + submittedAt: review2.submittedAt, + comments: review2.comments, + fetchingMoreComments: false, + }); + + assert.lengthOf(wrapper.find('ChildComponent'), 3); + + assert.strictEqual(wrapper.find('ChildComponent').at(0).prop('passThroughProp'), passThroughProp); + assert.deepEqual(wrapper.find('ChildComponent').at(0).prop('thread'), { + rootCommentId: '4', + comments: [review2.comments.edges[2].node], + }); + + assert.strictEqual(wrapper.find('ChildComponent').at(1).prop('passThroughProp'), passThroughProp); + assert.deepEqual(wrapper.find('ChildComponent').at(1).prop('thread'), { + rootCommentId: '2', + comments: [review2.comments.edges[0].node], + }); + + assert.strictEqual(wrapper.find('ChildComponent').at(2).prop('passThroughProp'), passThroughProp); + assert.deepEqual(wrapper.find('ChildComponent').at(2).prop('thread'), { + rootCommentId: '1', + comments: [review1.comments.edges[0].node, review2.comments.edges[1].node], + }); }); describe('collectComments', function() { From 30bc7ced9d0ced734b14d21d417afde4b61d0dd1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Mar 2019 10:28:34 -0500 Subject: [PATCH 2996/4847] PullRequestReviewCommentsView > PullRequestReviewCommentThreadView Rework PullRequestReviewCommentsView to render a single comment thread at a time. Rename it to PullRequestReviewCommentThreadView which is a mouthful, but a more accurate description of what it does. --- ...ew.js => pr-review-comment-thread-view.js} | 63 +++++++++---------- ... => pr-review-comment-thread-view.test.js} | 51 +++++++-------- 2 files changed, 54 insertions(+), 60 deletions(-) rename lib/views/{pr-review-comments-view.js => pr-review-comment-thread-view.js} (63%) rename test/views/{pr-comments-view.test.js => pr-review-comment-thread-view.test.js} (75%) diff --git a/lib/views/pr-review-comments-view.js b/lib/views/pr-review-comment-thread-view.js similarity index 63% rename from lib/views/pr-review-comments-view.js rename to lib/views/pr-review-comment-thread-view.js index 636b88d4b1..232136dca4 100644 --- a/lib/views/pr-review-comments-view.js +++ b/lib/views/pr-review-comment-thread-view.js @@ -10,55 +10,51 @@ import Octicon from '../atom/octicon'; import GithubDotcomMarkdown from './github-dotcom-markdown'; import Timeago from './timeago'; -export default class PullRequestCommentsView extends React.Component { +export default class PullRequestReviewCommentThreadView extends React.Component { static propTypes = { - commentThreads: PropTypes.arrayOf(PropTypes.shape({ + commentThread: PropTypes.shape({ rootCommentId: PropTypes.string.isRequired, comments: PropTypes.arrayOf(PropTypes.object).isRequired, - })), + }), getBufferRowForDiffPosition: PropTypes.func.isRequired, switchToIssueish: PropTypes.func.isRequired, isPatchVisible: PropTypes.func.isRequired, } render() { - return [...this.props.commentThreads].map(({rootCommentId, comments}) => { - const rootComment = comments[0]; - if (!rootComment.position) { - return null; - } + const {rootCommentId, comments} = this.props.commentThread; + const rootComment = comments[0]; + if (!rootComment.position) { + return null; + } - // if file patch is collapsed or too large, do not render the comments - if (!this.props.isPatchVisible(rootComment.path)) { - return null; - } + // if file patch is collapsed or too large, do not render the comments + if (!this.props.isPatchVisible(rootComment.path)) { + return null; + } - const nativePath = toNativePathSep(rootComment.path); - const row = this.props.getBufferRowForDiffPosition(nativePath, rootComment.position); - const point = new Point(row, 0); - const range = new Range(point, point); - return ( - - - {comments.map(comment => { - return ( - - ); - })} - - - ); - }); + const nativePath = toNativePathSep(rootComment.path); + const row = this.props.getBufferRowForDiffPosition(nativePath, rootComment.position); + const point = new Point(row, 0); + const range = new Range(point, point); + return ( + + + {comments.map(comment => ( + + ))} + + + ); } } export class PullRequestCommentView extends React.Component { static propTypes = { - switchToIssueish: PropTypes.func.isRequired, comment: PropTypes.shape({ author: PropTypes.shape({ avatarUrl: PropTypes.string, @@ -69,6 +65,7 @@ export class PullRequestCommentView extends React.Component { createdAt: PropTypes.string.isRequired, isMinimized: PropTypes.bool.isRequired, }).isRequired, + switchToIssueish: PropTypes.func.isRequired, } render() { diff --git a/test/views/pr-comments-view.test.js b/test/views/pr-review-comment-thread-view.test.js similarity index 75% rename from test/views/pr-comments-view.test.js rename to test/views/pr-review-comment-thread-view.test.js index ff563441fc..331c294143 100644 --- a/test/views/pr-comments-view.test.js +++ b/test/views/pr-review-comment-thread-view.test.js @@ -3,26 +3,21 @@ import {shallow} from 'enzyme'; import {multiFilePatchBuilder} from '../builder/patch'; import {pullRequestBuilder} from '../builder/pr'; -import PullRequestCommentsView, {PullRequestCommentView} from '../../lib/views/pr-review-comments-view'; - -describe('PullRequestCommentsView', function() { - function buildApp(multiFilePatch, pullRequest, overrideProps) { - const relay = { - hasMore: () => {}, - loadMore: () => {}, - isLoading: () => {}, - }; +import PullRequestReviewCommentThreadView, {PullRequestCommentView} from '../../lib/views/pr-review-comment-thread-view'; + +describe('PullRequestReviewCommentThreadView', function() { + function buildApp(multiFilePatch, commentThread, overrideProps = {}) { return shallow( - true} + getBufferRowForDiffPosition={multiFilePatch.getBufferRowForDiffPosition} + commentThread={commentThread} switchToIssueish={() => {}} {...overrideProps} />, ); } + it('adjusts the position for comments after hunk headers', function() { const {multiFilePatch} = multiFilePatchBuilder() .addFilePatch(fp => { @@ -48,11 +43,14 @@ describe('PullRequestCommentsView', function() { }) .build(); - const wrapper = buildApp(multiFilePatch, pr, {}); + const wrapper0 = buildApp(multiFilePatch, pr.commentThreads[0]); + assert.deepEqual(wrapper0.find('Marker').prop('bufferRange').serialize(), [[1, 0], [1, 0]]); - assert.deepEqual(wrapper.find('Marker').at(0).prop('bufferRange').serialize(), [[1, 0], [1, 0]]); - assert.deepEqual(wrapper.find('Marker').at(1).prop('bufferRange').serialize(), [[12, 0], [12, 0]]); - assert.deepEqual(wrapper.find('Marker').at(2).prop('bufferRange').serialize(), [[20, 0], [20, 0]]); + const wrapper1 = buildApp(multiFilePatch, pr.commentThreads[1]); + assert.deepEqual(wrapper1.find('Marker').prop('bufferRange').serialize(), [[12, 0], [12, 0]]); + + const wrapper2 = buildApp(multiFilePatch, pr.commentThreads[2]); + assert.deepEqual(wrapper2.find('Marker').prop('bufferRange').serialize(), [[20, 0], [20, 0]]); }); it('does not render comment if patch is too large or collapsed', function() { @@ -64,9 +62,8 @@ describe('PullRequestCommentsView', function() { }) .build(); - const wrapper = buildApp(multiFilePatch, pr, {isPatchVisible: () => { return false; }}); - const comments = wrapper.find('PullRequestCommentView'); - assert.lengthOf(comments, 0); + const wrapper = buildApp(multiFilePatch, pr.commentThreads[0], {isPatchVisible: () => false}); + assert.isFalse(wrapper.exists('PullRequestCommentView')); }); it('does not render comment if position is null', function() { @@ -88,11 +85,11 @@ describe('PullRequestCommentsView', function() { }) .build(); - const wrapper = buildApp(multiFilePatch, pr, {}); + const wrapper = buildApp(multiFilePatch, pr.commentThreads[0]); const comments = wrapper.find('PullRequestCommentView'); assert.lengthOf(comments, 1); - assert.strictEqual(comments.at(0).prop('comment').body, 'one'); + assert.strictEqual(comments.prop('comment').body, 'one'); }); }); @@ -132,7 +129,7 @@ describe('PullRequestCommentView', function() { assert.strictEqual(avatar.getElement('src').props.src, avatarUrl); assert.strictEqual(avatar.getElement('alt').props.alt, login); - assert.isTrue(wrapper.text().includes(`${login} commented`)); + assert.include(wrapper.text(), `${login} commented`); const a = wrapper.find('.github-PrComment-timeAgo'); assert.strictEqual(a.getElement('href').props.href, commentUrl); @@ -147,12 +144,12 @@ describe('PullRequestCommentView', function() { it('contains the text `someone commented` for null authors', function() { const wrapper = shallow(buildApp({author: null})); - assert.isTrue(wrapper.text().includes('someone commented')); + assert.include(wrapper.text(), 'someone commented'); }); it('hides minimized comment', function() { const wrapper = shallow(buildApp({isMinimized: true})); - assert.isTrue(wrapper.find('.github-PrComment-hidden').exists()); - assert.isFalse(wrapper.find('.github-PrComment-header').exists()); + assert.isTrue(wrapper.exists('.github-PrComment-hidden')); + assert.isFalse(wrapper.exists('.github-PrComment-header')); }); }); From 9090283a478d6d61c613a0585c238d10d872b86d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Mar 2019 10:31:16 -0500 Subject: [PATCH 2997/4847] Pass a render prop to PullRequestReviewsContainer Preserve existing review comments behavior in MultiFilePatchView. --- lib/views/multi-file-patch-view.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 76fa7e199f..edc80adb59 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -16,7 +16,8 @@ import Commands, {Command} from '../atom/commands'; import FilePatchHeaderView from './file-patch-header-view'; import FilePatchMetaView from './file-patch-meta-view'; import HunkHeaderView from './hunk-header-view'; -import PullRequestsReviewsContainer from '../containers/pr-reviews-container'; +import PullRequestReviewsContainer from '../containers/pr-reviews-container'; +import PullRequestReviewCommentThreadView from './pr-review-comment-thread-view'; import RefHolder from '../models/ref-holder'; import ChangedFileItem from '../items/changed-file-item'; import CommitDetailItem from '../items/commit-detail-item'; @@ -385,13 +386,16 @@ export default class MultiFilePatchView extends React.Component { // "forceRerender" ensures that the PullRequestCommentsView re-renders each time that the MultiFilePatchView does. // It doesn't re-query for reviews, but it does re-check patch visibility. return ( - + + {commentThread => ( + + )} + ); } else { return null; From eb70cc00cee5274b61b1e3954c88b18c690c99d8 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 4 Mar 2019 15:52:05 +0100 Subject: [PATCH 2998/4847] port over view styles from prototype --- lib/views/reviews-view.js | 394 +++++++++++++++++++++++++++++++++++++- styles/review.less | 388 +++++++++++++++++++++++++++++++++++++ 2 files changed, 779 insertions(+), 3 deletions(-) create mode 100644 styles/review.less diff --git a/lib/views/reviews-view.js b/lib/views/reviews-view.js index ce8ec6b45d..309581d925 100644 --- a/lib/views/reviews-view.js +++ b/lib/views/reviews-view.js @@ -4,9 +4,397 @@ import {inspect} from 'util'; export default class ReviewsView extends React.Component { render() { return ( -
    -

    HELL YEAH PR REVIEW COMMENTS

    -
    {inspect(this.props, {depth: 4})}
    +
    + + {/* Review Summaries ------------------------------------------ */} + +
    + +

    Reviews

    +
    +
    + +
    +
    + + + vanessayuenn + approved these changes + 18 minutes ago +
    +
    + looks good! 🚢 +
    +
    + +
    +
    + + + simurai + requested changes + 2 hours ago +
    +
    + This is a great addition. Before merging we might should rethink the position of the icon. +
    +
    + +
    +
    + + + annthurium + commented + 4 hours ago +
    +
    + looking good so far -- just found a few nits to address. +
    +
    + +
    +
    + + + + {/* Review Comments ------------------------------------------ */} + +
    + +

    Review comments

    + + Resolved 1 of 7 + + +
    +
    + +
    + + + lib/controllers/ + commit-detail-controller.js + 19 + + 4h + + +
    +                
    { ' messageCollapsible: this.props.commit.isBodyLong(),' }
    +
    { ' messageOpen: !this.props.commit.isBodyLong(),' }
    +
    { ' };' }
    +
    { ' }' }
    +
    +
    +
    +
    + + annthurium + 4 hours ago +
    +
    mind adding the missing semicolon here?
    +
    + +
    + + + +
    +
    +
    + +
    +
    + +
    + + + lib/controllers/ + pr-reviews-controller.js + 22 + + 4h + + +
    +                
    { ' ),' }
    +
    { ' }),' }
    +
    { ' getBufferRowForDiffPosition: PropTypes.func.isRequired,' }
    +
    { ' isPatchTooLargeOrCollapsed: PropTypes.func.isRequired,' }
    +
    +
    +
    +
    + + annthurium + 4 hours ago +
    +
    this is a really long name -- can you come up with something more concise?
    +
    +
    +
    + + vanessayuenn + 18 minutes ago +
    +
    how about just isPatchCollapsed?
    +
    + +
    + + + +
    +
    +
    + +
    +
    + +
    + + + lib/models/patch/ + builder.js + 12 + + 1h + + +
    +                
    { 'export const DEFAULT_OPTIONS = {' }
    +
    { ' // Number of lines after which we consider the diff "large"' }
    +
    { ' // TODO: Set this based on performance measurements' }
    +
    { ' largeDiffThreshold: 100,' }
    +
    +
    +
    +
    + + annthurium + 1 hour ago +
    +
    @simurai: how many lines do you think constitutes a large diff? Not just from a performance perspective, but from a user experience perspective. Like how many lines is disruptive to a user when they're trying to read, because often large diffs are the result of auto generated code.
    +
    +
    +
    + + simurai + 1 hour ago +
    +
    Hmmm.. will large diffs be collapsed by default or there is a "load" button? Maybe if the diff is so large that it fills the whole scroll height. Then I can uncollapse only if I'm really interested in that file. 100 seems fine. 👍
    +
    +
    +
    + + annthurium + 1 hour ago +
    + +
    +
    +
    + + vanessayuenn + 25 minutes ago +
    +
    mm we were using 1000 lines as the threshold before, but that's for performance reasons. 100 does seem a bit small though considering it's counting both deleted and added lines. 🤔
    +
    + 300 seems a bit more reasonable, but still an arbitrary number.
    +
    + +
    + + + +
    +
    +
    + +
    +
    + +
    + + + lib/models/patch/ + multi-file-patch.js + 359 + + 4h + + +
    +                
    { ' }' }
    +
    { ' }' }
    +
    { '' }
    +
    { ' isPatchTooLargeOrCollapsed = filePatchPath => {' }
    +
    +
    +
    +
    + + annthurium + 4 hours ago +
    +
    same as above - this name is too long and the line length linters are gonna be unhappy.
    +
    + +
    + + + +
    +
    +
    + +
    +
    + +
    + + + lib/views/ + file-patch-header-view.js + 52 + + 2h + + +
    +                
    { '
    ' }
    +
    { ' ' }
    +
    { ' {this.renderTitle()}' }
    +
    { ' {this.renderCollapseButton()}' }
    +
    +
    +
    +
    + + simurai + 2 hours ago +
    +
    Should we move the chevron icon to the left? So that the position doesn't jump when there are more buttons. Alternative would be to move it all the way to the right.
    +
    + +
    + + + +
    +
    +
    + +
    +
    + +
    + + + test/views/ + pr-comments-view.test.js + 17 + + 4h + + +
    +                
    { ' };' }
    +
    { ' return shallow(' }
    +
    { ' +
    { ' isPatchTooLargeOrCollapsed={sinon.stub().returns(false)}' }
    +
    +
    +
    +
    + + annthurium + 4 hours ago +
    +
    again, this variable name is too long
    +
    + +
    + + + +
    +
    +
    + +
    +
    + +
    + + + lib/models/patch/ + builder.js + 280 + + 4h + + +
    +                
    { ' /*' }
    +
    { ' * Construct a String containing diagnostic information about the internal state of this FilePatch.' }
    +
    { ' */' }
    +
    { ' inspect(opts = {}) {' }
    +
    +
    +
    +
    + + annthurium + 4 hours ago +
    +
    nice! This is going to be so useful when we are trying to debug the marker layer on a text buffer.
    +
    + +
    + + + +
    +
    +
    + annthurium marked this as resolved + +
    +
    + +
    +
    +
    ); } diff --git a/styles/review.less b/styles/review.less new file mode 100644 index 0000000000..3730283ef5 --- /dev/null +++ b/styles/review.less @@ -0,0 +1,388 @@ +@import "variables"; + +@avatar-size: 16px; +@font-size-default: @font-size; +@font-size-body: @font-size + 1px; +@nav-size: 2.5em; +@background-color: mix(@base-background-color, @tool-panel-background-color, 66%); + + +// PR ------------------------------------ + +.github-Pr { + flex: 1; + overflow-x: auto; +} + + +// Reviews ---------------------------------------------- + +.github-Reviews { + flex: 1; + overflow-y: auto; + + &-section { + border-bottom: 1px solid @base-border-color; + } + + &-header { + display: flex; + align-items: center; + padding: @component-padding; + cursor: default; + } + + &-title { + flex: 1; + font-size: 1.15em; + margin: 0; + } + + &-count { + color: @text-color-subtle; + } + + &-countNr { + color: @text-color-highlight; + } + + &-progessBar { + width: 5em; + margin-left: @component-padding; + } + + &-container { + font-size: @font-size-default; + padding: @component-padding; + padding-top: 0; + + &.is-resolved { + padding-top: @component-padding; + border-top: 1px solid @base-border-color; + } + } +} + + +// Review Summaries ------------------------------------------ + +.github-ReviewSummary { + padding: @component-padding; + border: 1px solid @base-border-color; + border-radius: @component-border-radius; + background-color: @background-color; + + & + & { + margin-top: @component-padding; + } + + &-header { + display: flex; + } + + &-icon { + vertical-align: -3px; + &.icon-check { + color: @text-color-success; + } + &.icon-alert { + color: @text-color-warning; + } + &.icon-comment { + color: @text-color-subtle; + } + } + + &-avatar { + margin-right: .5em; + width: @avatar-size; + height: @avatar-size; + border-radius: @component-border-radius; + image-rendering: -webkit-optimize-contrast; + } + + &-username { + margin-right: .3em; + font-weight: 500; + } + + &-type { + color: @text-color-subtle; + } + + &-timeAgo { + margin-left: auto; + color: @text-color-subtle; + } + + &-comment { + position: relative; + margin-top: @component-padding/2; + margin-left: 7px; + padding-left: 12px; + font-size: @font-size-body; + border-left: 2px solid @base-border-color; + } +} + + +// Review Comments ---------------------------------------------- + +.github-Review { + position: relative; + border: 1px solid @base-border-color; + border-radius: @component-border-radius; + background-color: @background-color; + + & + & { + margin-top: @component-padding; + } + + // Header ------------------ + + &-reference { + display: flex; + align-items: center; + padding-left: @component-padding; + height: @nav-size; + cursor: default; + + &::-webkit-details-marker { + margin-right: @component-padding/1.5; + } + + .is-resolved & { + &::-webkit-details-marker { + display: none; + } + } + } + + &-resolvedIcon { + display: none; + + .is-resolved & { + display: inline-block; + } + + &:before { + font-size: 12px; + width: 15px; // magic to match the triangle + margin-right: 0; + } + } + + &-path { + color: @text-color-subtle; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + pointer-events: none; + } + + &-file { + color: @text-color; + margin-right: @component-padding/2; + font-weight: 500; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + pointer-events: none; + } + + &-lineNr { + color: @text-color-subtle; + margin-right: @component-padding/2; + } + + &-referenceAvatar { + margin-left: auto; + margin-right: @component-padding/2; + width: @avatar-size; + height: @avatar-size; + border-radius: @component-border-radius; + image-rendering: -webkit-optimize-contrast; + + .github-Review[open] & { + display: none; + } + } + + &-referenceTimeAgo { + color: @text-color-subtle; + margin-right: @component-padding/2; + .github-Review[open] & { + display: none; + } + } + + &-nav { + display: none; + margin-left: auto; + .github-Review[open] & { + display: initial; + } + } + &-navButton { + width: @nav-size; + height: @nav-size; + padding: 0; + border: none; + border-left: 1px solid @base-border-color; + background-color: transparent; + cursor: default; + + &:hover { + background-color: @background-color-highlight; + } + &:active { + background-color: @background-color-selected; + } + + &:before { + width: auto; + margin-right: 0; + } + } + + + // Diff ------------------ + + &-diff { + padding: 0; + color: @text-color; + font-family: var(--editor-font-family); + border-top: 1px solid @base-border-color; + border-bottom: 1px solid @base-border-color; + border-radius: 0; + background: @base-background-color; + } + + &-diffLine { + padding: 0 @component-padding/2; + line-height: 1.75; + + &:last-child { + font-weight: 500; + } + + &::before { + content: " "; + margin-right: .5em; + } + + &.is-added { + color: mix(@text-color-success, @text-color-highlight, 25%); + background-color: mix(@background-color-success, @base-background-color, 20%); + &::before { + content: "+"; + } + } + &.is-deleted { + color: mix(@text-color-error, @text-color-highlight, 25%); + background-color: mix(@background-color-error, @base-background-color, 20%); + &::before { + content: "-"; + } + } + } + + &-diffLineIcon { + margin-right: .5em; + } + + + // Comments ------------------ + + &-comments { + padding: @component-padding; + padding-left: @component-padding + @avatar-size + 5px; // space for avatar + } + + &-comment { + margin-bottom: @component-padding*1.5; + } + + &-header { + display: flex; + align-items: center; + margin-bottom: @component-padding/4; + } + + &-avatar { + position: absolute; + left: @component-padding; + margin-right: .5em; + width: @avatar-size; + height: @avatar-size; + border-radius: @component-border-radius; + image-rendering: -webkit-optimize-contrast; + } + + &-username { + margin-right: .5em; + font-weight: 500; + } + + &-timeAgo { + color: @text-color-subtle; + } + + &-text { + font-size: @font-size-body; + + a { + font-weight: 500; + } + } + + &-reply { + margin-top: @component-padding; + } + + &-replyInput { + width: 100%; + height: 2.125em; // one line + min-height: 2.125em; + resize: vertical; + + &:focus { + height: 3.75em; // two lines + } + + &:focus + .github-ReviewComment-replyButton { + display: block; + } + } + + &-replyButton { + display: none; + margin-top: @component-padding; + } + + + // Footer ------------------ + + &-footer { + display: flex; + align-items: center; + justify-content: space-between; + padding: @component-padding; + border-top: 1px solid @base-border-color; + } + + &-resolveText { + margin-right: @component-padding; + color: @text-color-subtle; + } + + &-resolveButton { + margin-left: auto; + &.btn.icon { + &:before { + font-size: 14px; + } + } + } + +} From 4ab61052e0a7bff6b7cfa4fe71c20c0369a93582 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Mon, 4 Mar 2019 16:36:59 +0100 Subject: [PATCH 2999/4847] make it more programmatic --- lib/views/reviews-view.js | 695 ++++++++++++++++++-------------------- 1 file changed, 337 insertions(+), 358 deletions(-) diff --git a/lib/views/reviews-view.js b/lib/views/reviews-view.js index 309581d925..22a6bc425e 100644 --- a/lib/views/reviews-view.js +++ b/lib/views/reviews-view.js @@ -2,21 +2,19 @@ import React from 'react'; import {inspect} from 'util'; export default class ReviewsView extends React.Component { - render() { - return ( -
    - - {/* Review Summaries ------------------------------------------ */} - -
    - -

    Reviews

    -
    -
    + renderReviewSummaries() { + return ( +
    + +

    Reviews

    +
    +
    + {[1,2].map(({something}) => (
    - + {/*icon-check: approved, icon-comment: commented, icon-alert: requested changes */} + vanessayuenn approved these changes @@ -26,375 +24,356 @@ export default class ReviewsView extends React.Component { looks good! 🚢
    + ))} + + + ); + } -
    -
    - - - simurai - requested changes - 2 hours ago -
    -
    - This is a great addition. Before merging we might should rethink the position of the icon. -
    -
    + renderReviewComments() { + return ( +
    + +

    Review comments

    + + Resolved 1 of 7 + + +
    +
    -
    -
    - - - annthurium - commented - 4 hours ago -
    -
    - looking good so far -- just found a few nits to address. +
    + + + lib/controllers/ + commit-detail-controller.js + 19 + + 4h + + +
    +              
    { ' messageCollapsible: this.props.commit.isBodyLong(),' }
    +
    { ' messageOpen: !this.props.commit.isBodyLong(),' }
    +
    { ' };' }
    +
    { ' }' }
    +
    +
    +
    +
    + + annthurium + 4 hours ago +
    +
    mind adding the missing semicolon here?
    -
    - -
    -
    - +
    + + + +
    + +
    + +
    + - {/* Review Comments ------------------------------------------ */} - -
    - -

    Review comments

    - - Resolved 1 of 7 - - -
    -
    - -
    - - - lib/controllers/ - commit-detail-controller.js - 19 - - 4h - - -
    -                
    { ' messageCollapsible: this.props.commit.isBodyLong(),' }
    -
    { ' messageOpen: !this.props.commit.isBodyLong(),' }
    -
    { ' };' }
    -
    { ' }' }
    -
    -
    -
    -
    - - annthurium - 4 hours ago -
    -
    mind adding the missing semicolon here?
    -
    - -
    +
    + + + lib/controllers/ + pr-reviews-controller.js + 22 + + 4h + + +
    +              
    { ' ),' }
    +
    { ' }),' }
    +
    { ' getBufferRowForDiffPosition: PropTypes.func.isRequired,' }
    +
    { ' isPatchTooLargeOrCollapsed: PropTypes.func.isRequired,' }
    +
    +
    +
    +
    - - -
    -
    -
    - -
    -
    + annthurium + 4 hours ago + +
    this is a really long name -- can you come up with something more concise?
    +
    +
    +
    + + vanessayuenn + 18 minutes ago +
    +
    how about just isPatchCollapsed?
    +
    -
    - - - lib/controllers/ - pr-reviews-controller.js - 22 - - 4h - - -
    -                
    { ' ),' }
    -
    { ' }),' }
    -
    { ' getBufferRowForDiffPosition: PropTypes.func.isRequired,' }
    -
    { ' isPatchTooLargeOrCollapsed: PropTypes.func.isRequired,' }
    -
    -
    -
    -
    - - annthurium - 4 hours ago -
    -
    this is a really long name -- can you come up with something more concise?
    -
    -
    -
    - - vanessayuenn - 18 minutes ago -
    -
    how about just isPatchCollapsed?
    -
    +
    + + + +
    +
    +
    + +
    +
    -
    +
    + + + lib/models/patch/ + builder.js + 12 + + 1h + + +
    +              
    { 'export const DEFAULT_OPTIONS = {' }
    +
    { ' // Number of lines after which we consider the diff "large"' }
    +
    { ' // TODO: Set this based on performance measurements' }
    +
    { ' largeDiffThreshold: 100,' }
    +
    +
    +
    +
    - - -
    -
    -
    - -
    -
    - -
    - - - lib/models/patch/ - builder.js - 12 - - 1h - - -
    -                
    { 'export const DEFAULT_OPTIONS = {' }
    -
    { ' // Number of lines after which we consider the diff "large"' }
    -
    { ' // TODO: Set this based on performance measurements' }
    -
    { ' largeDiffThreshold: 100,' }
    -
    -
    -
    -
    - - annthurium - 1 hour ago -
    -
    @simurai: how many lines do you think constitutes a large diff? Not just from a performance perspective, but from a user experience perspective. Like how many lines is disruptive to a user when they're trying to read, because often large diffs are the result of auto generated code.
    -
    -
    -
    - - simurai - 1 hour ago -
    -
    Hmmm.. will large diffs be collapsed by default or there is a "load" button? Maybe if the diff is so large that it fills the whole scroll height. Then I can uncollapse only if I'm really interested in that file. 100 seems fine. 👍
    -
    -
    -
    - - annthurium - 1 hour ago -
    - -
    -
    -
    - - vanessayuenn - 25 minutes ago -
    -
    mm we were using 1000 lines as the threshold before, but that's for performance reasons. 100 does seem a bit small though considering it's counting both deleted and added lines. 🤔
    -
    - 300 seems a bit more reasonable, but still an arbitrary number.
    -
    - -
    + annthurium + 1 hour ago + +
    @simurai: how many lines do you think constitutes a large diff? Not just from a performance perspective, but from a user experience perspective. Like how many lines is disruptive to a user when they're trying to read, because often large diffs are the result of auto generated code.
    +
    +
    +
    + + simurai + 1 hour ago +
    +
    Hmmm.. will large diffs be collapsed by default or there is a "load" button? Maybe if the diff is so large that it fills the whole scroll height. Then I can uncollapse only if I'm really interested in that file. 100 seems fine. 👍
    +
    +
    +
    - - -
    -
    -
    - -
    -
    + annthurium + 1 hour ago + + +
    +
    +
    + + vanessayuenn + 25 minutes ago +
    +
    mm we were using 1000 lines as the threshold before, but that's for performance reasons. 100 does seem a bit small though considering it's counting both deleted and added lines. 🤔
    +
    + 300 seems a bit more reasonable, but still an arbitrary number.
    +
    -
    - - - lib/models/patch/ - multi-file-patch.js - 359 - - 4h - - -
    -                
    { ' }' }
    -
    { ' }' }
    -
    { '' }
    -
    { ' isPatchTooLargeOrCollapsed = filePatchPath => {' }
    -
    -
    -
    -
    - - annthurium - 4 hours ago -
    -
    same as above - this name is too long and the line length linters are gonna be unhappy.
    -
    +
    + + + +
    +
    +
    + +
    +
    -
    +
    + + + lib/models/patch/ + multi-file-patch.js + 359 + + 4h + + +
    +              
    { ' }' }
    +
    { ' }' }
    +
    { '' }
    +
    { ' isPatchTooLargeOrCollapsed = filePatchPath => {' }
    +
    +
    +
    +
    - - -
    -
    -
    - -
    -
    + annthurium + 4 hours ago + +
    same as above - this name is too long and the line length linters are gonna be unhappy.
    +
    -
    - - - lib/views/ - file-patch-header-view.js - 52 - - 2h - - -
    -                
    { '
    ' }
    -
    { ' ' }
    -
    { ' {this.renderTitle()}' }
    -
    { ' {this.renderCollapseButton()}' }
    -
    -
    -
    -
    - - simurai - 2 hours ago -
    -
    Should we move the chevron icon to the left? So that the position doesn't jump when there are more buttons. Alternative would be to move it all the way to the right.
    -
    +
    + + + +
    +
    +
    + +
    +
    -
    - - - -
    -
    -
    - -
    -
    +
    + + + lib/views/ + file-patch-header-view.js + 52 + + 2h + + +
    +              
    { '
    ' }
    +
    { ' ' }
    +
    { ' {this.renderTitle()}' }
    +
    { ' {this.renderCollapseButton()}' }
    +
    +
    +
    +
    + + simurai + 2 hours ago +
    +
    Should we move the chevron icon to the left? So that the position doesn't jump when there are more buttons. Alternative would be to move it all the way to the right.
    +
    -
    - - - test/views/ - pr-comments-view.test.js - 17 - - 4h - - -
    -                
    { ' };' }
    -
    { ' return shallow(' }
    -
    { ' -
    { ' isPatchTooLargeOrCollapsed={sinon.stub().returns(false)}' }
    -
    -
    -
    -
    - - annthurium - 4 hours ago -
    -
    again, this variable name is too long
    -
    +
    + + + +
    +
    +
    + +
    +
    -
    +
    + + + test/views/ + pr-comments-view.test.js + 17 + + 4h + + +
    +              
    { ' };' }
    +
    { ' return shallow(' }
    +
    { ' +
    { ' isPatchTooLargeOrCollapsed={sinon.stub().returns(false)}' }
    +
    +
    +
    +
    - - -
    -
    -
    - -
    -
    + annthurium + 4 hours ago + +
    again, this variable name is too long
    +
    -
    - - - lib/models/patch/ - builder.js - 280 - - 4h - - -
    -                
    { ' /*' }
    -
    { ' * Construct a String containing diagnostic information about the internal state of this FilePatch.' }
    -
    { ' */' }
    -
    { ' inspect(opts = {}) {' }
    -
    -
    -
    -
    - - annthurium - 4 hours ago -
    -
    nice! This is going to be so useful when we are trying to debug the marker layer on a text buffer.
    -
    +
    + + + +
    +
    +
    + +
    +
    -
    +
    + + + lib/models/patch/ + builder.js + 280 + + 4h + + +
    +              
    { ' /*' }
    +
    { ' * Construct a String containing diagnostic information about the internal state of this FilePatch.' }
    +
    { ' */' }
    +
    { ' inspect(opts = {}) {' }
    +
    +
    +
    +
    - - -
    -
    -
    - annthurium marked this as resolved - -
    -
    + annthurium + 4 hours ago + +
    nice! This is going to be so useful when we are trying to debug the marker layer on a text buffer.
    +
    + +
    + + + +
    +
    +
    + annthurium marked this as resolved + +
    +
    -
    -
    + + + ) + } + render() { + return ( +
    + {this.renderReviewSummaries()} + {this.renderReviewComments()}
    ); } From 0491894267add6fa74d633074f71378bf8c379a8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Mar 2019 10:45:37 -0500 Subject: [PATCH 3000/4847] Render the prReviewsContainer fragment in ReviewsContainer --- .../reviewsContainerQuery.graphql.js | 579 ++++++++++++++++-- lib/containers/reviews-container.js | 18 +- 2 files changed, 557 insertions(+), 40 deletions(-) diff --git a/lib/containers/__generated__/reviewsContainerQuery.graphql.js b/lib/containers/__generated__/reviewsContainerQuery.graphql.js index df5eb0e96a..1b17c91da2 100644 --- a/lib/containers/__generated__/reviewsContainerQuery.graphql.js +++ b/lib/containers/__generated__/reviewsContainerQuery.graphql.js @@ -1,6 +1,6 @@ /** * @flow - * @relayHash 68140a8082e21c7d56516fb6ca6c8db7 + * @relayHash 2ff5fd99b183d2c9a7e114fa51f38d04 */ /* eslint-disable */ @@ -9,13 +9,22 @@ /*:: import type { ConcreteRequest } from 'relay-runtime'; +type prReviewsContainer_pullRequest$ref = any; export type reviewsContainerQueryVariables = {| repoOwner: string, repoName: string, + prNumber: number, + reviewCount: number, + reviewCursor?: ?string, + commentCount: number, + commentCursor?: ?string, |}; export type reviewsContainerQueryResponse = {| +repository: ?{| - +id: string + +pullRequest: ?{| + +$fragmentRefs: prReviewsContainer_pullRequest$ref + |}, + +id: string, |} |}; export type reviewsContainerQuery = {| @@ -29,11 +38,94 @@ export type reviewsContainerQuery = {| query reviewsContainerQuery( $repoOwner: String! $repoName: String! + $prNumber: Int! + $reviewCount: Int! + $reviewCursor: String + $commentCount: Int! + $commentCursor: String ) { repository(owner: $repoOwner, name: $repoName) { + pullRequest(number: $prNumber) { + ...prReviewsContainer_pullRequest_y4qc0 + id + } id } } + +fragment prReviewsContainer_pullRequest_y4qc0 on PullRequest { + url + reviews(first: $reviewCount, after: $reviewCursor) { + pageInfo { + hasNextPage + endCursor + } + edges { + cursor + node { + id + body + commitId: commit { + oid + id + } + state + submittedAt + login: author { + __typename + login + ... on Node { + id + } + } + author { + __typename + avatarUrl + ... on Node { + id + } + } + ...prReviewCommentsContainer_review_1VbUmL + __typename + } + } + } +} + +fragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview { + id + submittedAt + comments(first: $commentCount, after: $commentCursor) { + pageInfo { + hasNextPage + endCursor + } + edges { + cursor + node { + id + author { + __typename + avatarUrl + login + ... on Node { + id + } + } + bodyHTML + isMinimized + path + position + replyTo { + id + } + createdAt + url + __typename + } + } + } +} */ const node/*: ConcreteRequest*/ = (function(){ @@ -49,39 +141,153 @@ var v0 = [ "name": "repoName", "type": "String!", "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "prNumber", + "type": "Int!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCount", + "type": "Int!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "reviewCursor", + "type": "String", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCount", + "type": "Int!", + "defaultValue": null + }, + { + "kind": "LocalArgument", + "name": "commentCursor", + "type": "String", + "defaultValue": null } ], v1 = [ { - "kind": "LinkedField", - "alias": null, - "name": "repository", - "storageKey": null, - "args": [ - { - "kind": "Variable", - "name": "name", - "variableName": "repoName", - "type": "String!" - }, - { - "kind": "Variable", - "name": "owner", - "variableName": "repoOwner", - "type": "String!" - } - ], - "concreteType": "Repository", - "plural": false, - "selections": [ - { - "kind": "ScalarField", - "alias": null, - "name": "id", - "args": null, - "storageKey": null - } - ] + "kind": "Variable", + "name": "name", + "variableName": "repoName", + "type": "String!" + }, + { + "kind": "Variable", + "name": "owner", + "variableName": "repoOwner", + "type": "String!" + } +], +v2 = [ + { + "kind": "Variable", + "name": "number", + "variableName": "prNumber", + "type": "Int!" + } +], +v3 = { + "kind": "ScalarField", + "alias": null, + "name": "id", + "args": null, + "storageKey": null +}, +v4 = { + "kind": "ScalarField", + "alias": null, + "name": "url", + "args": null, + "storageKey": null +}, +v5 = [ + { + "kind": "Variable", + "name": "after", + "variableName": "reviewCursor", + "type": "String" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "reviewCount", + "type": "Int" + } +], +v6 = { + "kind": "LinkedField", + "alias": null, + "name": "pageInfo", + "storageKey": null, + "args": null, + "concreteType": "PageInfo", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "hasNextPage", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "endCursor", + "args": null, + "storageKey": null + } + ] +}, +v7 = { + "kind": "ScalarField", + "alias": null, + "name": "cursor", + "args": null, + "storageKey": null +}, +v8 = { + "kind": "ScalarField", + "alias": null, + "name": "__typename", + "args": null, + "storageKey": null +}, +v9 = { + "kind": "ScalarField", + "alias": null, + "name": "login", + "args": null, + "storageKey": null +}, +v10 = { + "kind": "ScalarField", + "alias": null, + "name": "avatarUrl", + "args": null, + "storageKey": null +}, +v11 = [ + { + "kind": "Variable", + "name": "after", + "variableName": "commentCursor", + "type": "String" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "commentCount", + "type": "Int" } ]; return { @@ -92,23 +298,326 @@ return { "type": "Query", "metadata": null, "argumentDefinitions": (v0/*: any*/), - "selections": (v1/*: any*/) + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": (v1/*: any*/), + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "pullRequest", + "storageKey": null, + "args": (v2/*: any*/), + "concreteType": "PullRequest", + "plural": false, + "selections": [ + { + "kind": "FragmentSpread", + "name": "prReviewsContainer_pullRequest", + "args": [ + { + "kind": "Variable", + "name": "commentCount", + "variableName": "commentCount", + "type": null + }, + { + "kind": "Variable", + "name": "commentCursor", + "variableName": "commentCursor", + "type": null + }, + { + "kind": "Variable", + "name": "reviewCount", + "variableName": "reviewCount", + "type": null + }, + { + "kind": "Variable", + "name": "reviewCursor", + "variableName": "reviewCursor", + "type": null + } + ] + } + ] + }, + (v3/*: any*/) + ] + } + ] }, "operation": { "kind": "Operation", "name": "reviewsContainerQuery", "argumentDefinitions": (v0/*: any*/), - "selections": (v1/*: any*/) + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "repository", + "storageKey": null, + "args": (v1/*: any*/), + "concreteType": "Repository", + "plural": false, + "selections": [ + { + "kind": "LinkedField", + "alias": null, + "name": "pullRequest", + "storageKey": null, + "args": (v2/*: any*/), + "concreteType": "PullRequest", + "plural": false, + "selections": [ + (v4/*: any*/), + { + "kind": "LinkedField", + "alias": null, + "name": "reviews", + "storageKey": null, + "args": (v5/*: any*/), + "concreteType": "PullRequestReviewConnection", + "plural": false, + "selections": [ + (v6/*: any*/), + { + "kind": "LinkedField", + "alias": null, + "name": "edges", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewEdge", + "plural": true, + "selections": [ + (v7/*: any*/), + { + "kind": "LinkedField", + "alias": null, + "name": "node", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReview", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "kind": "ScalarField", + "alias": null, + "name": "body", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "commitId", + "name": "commit", + "storageKey": null, + "args": null, + "concreteType": "Commit", + "plural": false, + "selections": [ + { + "kind": "ScalarField", + "alias": null, + "name": "oid", + "args": null, + "storageKey": null + }, + (v3/*: any*/) + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "state", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "submittedAt", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": "login", + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + (v8/*: any*/), + (v9/*: any*/), + (v3/*: any*/) + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + (v8/*: any*/), + (v10/*: any*/), + (v3/*: any*/) + ] + }, + { + "kind": "LinkedField", + "alias": null, + "name": "comments", + "storageKey": null, + "args": (v11/*: any*/), + "concreteType": "PullRequestReviewCommentConnection", + "plural": false, + "selections": [ + (v6/*: any*/), + { + "kind": "LinkedField", + "alias": null, + "name": "edges", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewCommentEdge", + "plural": true, + "selections": [ + (v7/*: any*/), + { + "kind": "LinkedField", + "alias": null, + "name": "node", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "kind": "LinkedField", + "alias": null, + "name": "author", + "storageKey": null, + "args": null, + "concreteType": null, + "plural": false, + "selections": [ + (v8/*: any*/), + (v10/*: any*/), + (v9/*: any*/), + (v3/*: any*/) + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "bodyHTML", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "isMinimized", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "path", + "args": null, + "storageKey": null + }, + { + "kind": "ScalarField", + "alias": null, + "name": "position", + "args": null, + "storageKey": null + }, + { + "kind": "LinkedField", + "alias": null, + "name": "replyTo", + "storageKey": null, + "args": null, + "concreteType": "PullRequestReviewComment", + "plural": false, + "selections": [ + (v3/*: any*/) + ] + }, + { + "kind": "ScalarField", + "alias": null, + "name": "createdAt", + "args": null, + "storageKey": null + }, + (v4/*: any*/), + (v8/*: any*/) + ] + } + ] + } + ] + }, + { + "kind": "LinkedHandle", + "alias": null, + "name": "comments", + "args": (v11/*: any*/), + "handle": "connection", + "key": "PrReviewCommentsContainer_comments", + "filters": null + }, + (v8/*: any*/) + ] + } + ] + } + ] + }, + { + "kind": "LinkedHandle", + "alias": null, + "name": "reviews", + "args": (v5/*: any*/), + "handle": "connection", + "key": "PrReviewsContainer_reviews", + "filters": null + }, + (v3/*: any*/) + ] + }, + (v3/*: any*/) + ] + } + ] }, "params": { "operationKind": "query", "name": "reviewsContainerQuery", "id": null, - "text": "query reviewsContainerQuery(\n $repoOwner: String!\n $repoName: String!\n) {\n repository(owner: $repoOwner, name: $repoName) {\n id\n }\n}\n", + "text": "query reviewsContainerQuery(\n $repoOwner: String!\n $repoName: String!\n $prNumber: Int!\n $reviewCount: Int!\n $reviewCursor: String\n $commentCount: Int!\n $commentCursor: String\n) {\n repository(owner: $repoOwner, name: $repoName) {\n pullRequest(number: $prNumber) {\n ...prReviewsContainer_pullRequest_y4qc0\n id\n }\n id\n }\n}\n\nfragment prReviewsContainer_pullRequest_y4qc0 on PullRequest {\n url\n reviews(first: $reviewCount, after: $reviewCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n body\n commitId: commit {\n oid\n id\n }\n state\n submittedAt\n login: author {\n __typename\n login\n ... on Node {\n id\n }\n }\n author {\n __typename\n avatarUrl\n ... on Node {\n id\n }\n }\n ...prReviewCommentsContainer_review_1VbUmL\n __typename\n }\n }\n }\n}\n\nfragment prReviewCommentsContainer_review_1VbUmL on PullRequestReview {\n id\n submittedAt\n comments(first: $commentCount, after: $commentCursor) {\n pageInfo {\n hasNextPage\n endCursor\n }\n edges {\n cursor\n node {\n id\n author {\n __typename\n avatarUrl\n login\n ... on Node {\n id\n }\n }\n bodyHTML\n isMinimized\n path\n position\n replyTo {\n id\n }\n createdAt\n url\n __typename\n }\n }\n }\n}\n", "metadata": {} } }; })(); // prettier-ignore -(node/*: any*/).hash = '2a432f9e2a062215c96118ec0b5070cd'; +(node/*: any*/).hash = '51bf09a7273a2f166d4ff1c89b433cf6'; module.exports = node; diff --git a/lib/containers/reviews-container.js b/lib/containers/reviews-container.js index 81cd707a27..79a78d857e 100644 --- a/lib/containers/reviews-container.js +++ b/lib/containers/reviews-container.js @@ -74,13 +74,21 @@ export default class ReviewsContainer extends React.Component { ( $repoOwner: String! $repoName: String! - # $prNumber: Int! - # $reviewCount: Int! - # $reviewCursor: String - # $commentCount: Int! - # $commentCursor: String + $prNumber: Int! + $reviewCount: Int! + $reviewCursor: String + $commentCount: Int! + $commentCursor: String ) { repository(owner: $repoOwner, name: $repoName) { + pullRequest(number: $prNumber) { + ...prReviewsContainer_pullRequest @arguments( + reviewCount: $reviewCount + reviewCursor: $reviewCursor + commentCount: $commentCount + commentCursor: $commentCursor + ) + } id } } From c9d6b998c06a2fbbb8718aaa900585d2bf2a3a3e Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Mar 2019 10:53:44 -0500 Subject: [PATCH 3001/4847] :shirt: lint reviews-view --- lib/views/reviews-view.js | 93 +++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/lib/views/reviews-view.js b/lib/views/reviews-view.js index 22a6bc425e..a804f27c8d 100644 --- a/lib/views/reviews-view.js +++ b/lib/views/reviews-view.js @@ -1,5 +1,4 @@ import React from 'react'; -import {inspect} from 'util'; export default class ReviewsView extends React.Component { @@ -10,12 +9,12 @@ export default class ReviewsView extends React.Component {

    Reviews

    - {[1,2].map(({something}) => ( + {[1, 2].map(({something}) => (
    - {/*icon-check: approved, icon-comment: commented, icon-alert: requested changes */} + {/* icon-check: approved, icon-comment: commented, icon-alert: requested changes */} - + vanessayuenn approved these changes 18 minutes ago @@ -37,7 +36,7 @@ export default class ReviewsView extends React.Component {

    Review comments

    Resolved 1 of 7 - +
    @@ -48,12 +47,12 @@ export default class ReviewsView extends React.Component { lib/controllers/ commit-detail-controller.js 19 - + 4h
    @@ -65,7 +64,7 @@ export default class ReviewsView extends React.Component {
                 
    - + annthurium 4 hours ago
    @@ -73,8 +72,8 @@ export default class ReviewsView extends React.Component {
    - - + +
    @@ -89,12 +88,12 @@ export default class ReviewsView extends React.Component { lib/controllers/ pr-reviews-controller.js 22 - + 4h
    @@ -106,7 +105,7 @@ export default class ReviewsView extends React.Component {
                 
    - + annthurium 4 hours ago
    @@ -114,7 +113,7 @@ export default class ReviewsView extends React.Component {
    - + vanessayuenn 18 minutes ago
    @@ -122,8 +121,8 @@ export default class ReviewsView extends React.Component {
    - - + +
    @@ -138,12 +137,12 @@ export default class ReviewsView extends React.Component { lib/models/patch/ builder.js 12 - + 1h
    @@ -155,7 +154,7 @@ export default class ReviewsView extends React.Component {
                 
    - + annthurium 1 hour ago
    @@ -163,7 +162,7 @@ export default class ReviewsView extends React.Component {
    - + simurai 1 hour ago
    @@ -171,7 +170,7 @@ export default class ReviewsView extends React.Component {
    - + annthurium 1 hour ago
    @@ -179,18 +178,18 @@ export default class ReviewsView extends React.Component {
    - + vanessayuenn 25 minutes ago
    -
    mm we were using 1000 lines as the threshold before, but that's for performance reasons. 100 does seem a bit small though considering it's counting both deleted and added lines. 🤔
    -
    +
    mm we were using 1000 lines as the threshold before, but that's for performance reasons. 100 does seem a bit small though considering it's counting both deleted and added lines. 🤔
    +
    300 seems a bit more reasonable, but still an arbitrary number.
    - - + +
    @@ -205,12 +204,12 @@ export default class ReviewsView extends React.Component { lib/models/patch/ multi-file-patch.js 359 - + 4h
    @@ -222,7 +221,7 @@ export default class ReviewsView extends React.Component {
                 
    - + annthurium 4 hours ago
    @@ -230,8 +229,8 @@ export default class ReviewsView extends React.Component {
    - - + +
    @@ -246,12 +245,12 @@ export default class ReviewsView extends React.Component { lib/views/ file-patch-header-view.js 52 - + 2h
    @@ -263,7 +262,7 @@ export default class ReviewsView extends React.Component {
                 
    - + simurai 2 hours ago
    @@ -271,8 +270,8 @@ export default class ReviewsView extends React.Component {
    - - + +
    @@ -287,12 +286,12 @@ export default class ReviewsView extends React.Component { test/views/ pr-comments-view.test.js 17 - + 4h
    @@ -304,7 +303,7 @@ export default class ReviewsView extends React.Component {
                 
    - + annthurium 4 hours ago
    @@ -312,8 +311,8 @@ export default class ReviewsView extends React.Component {
    - - + +
    @@ -328,12 +327,12 @@ export default class ReviewsView extends React.Component { lib/models/patch/ builder.js 280 - + 4h
    @@ -345,7 +344,7 @@ export default class ReviewsView extends React.Component {
                 
    - + annthurium 4 hours ago
    @@ -353,8 +352,8 @@ export default class ReviewsView extends React.Component {
    - - + +
    @@ -366,7 +365,7 @@ export default class ReviewsView extends React.Component {
    - ) + ); } render() { From da9c23948b05fd3227ef1440655cb8a68ad0eff0 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Mar 2019 10:54:12 -0500 Subject: [PATCH 3002/4847] Fetch reviews and comments with a PullRequestReviewsContainer --- lib/views/reviews-view.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/views/reviews-view.js b/lib/views/reviews-view.js index a804f27c8d..57365fd15c 100644 --- a/lib/views/reviews-view.js +++ b/lib/views/reviews-view.js @@ -1,4 +1,5 @@ import React from 'react'; +import PullRequestReviewsContainer from '../containers/pr-reviews-container'; export default class ReviewsView extends React.Component { @@ -372,7 +373,9 @@ export default class ReviewsView extends React.Component { return (
    {this.renderReviewSummaries()} - {this.renderReviewComments()} + + {_commentThread => this.renderReviewComments()} +
    ); } From 3d6eaff4bed8aaf0ab8b3fcb83cc51fc7b90f74b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Mar 2019 11:24:49 -0500 Subject: [PATCH 3003/4847] Call a single render prop with review and comment thread collections --- lib/controllers/pr-reviews-controller.js | 10 +-- lib/views/multi-file-patch-view.js | 7 +- .../controllers/pr-reviews-controller.test.js | 68 ++++++++----------- 3 files changed, 35 insertions(+), 50 deletions(-) diff --git a/lib/controllers/pr-reviews-controller.js b/lib/controllers/pr-reviews-controller.js index 94adeed5a5..79811e3f01 100644 --- a/lib/controllers/pr-reviews-controller.js +++ b/lib/controllers/pr-reviews-controller.js @@ -61,6 +61,8 @@ export default class PullRequestReviewsController extends React.Component { return null; } + const reviews = this.props.pullRequest.reviews.edges.map(edge => edge.node); + const commentThreads = Object.keys(this.state).reverse().map(rootCommentId => { return { rootCommentId, @@ -80,13 +82,7 @@ export default class PullRequestReviewsController extends React.Component { return ( {this.renderCommentFetchingContainers()} - {commentThreads.map(commentThread => { - return ( - - {this.props.children(commentThread)} - - ); - })} + {this.props.children({reviews, commentThreads})} ); } diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index edc80adb59..761861af54 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -386,15 +386,16 @@ export default class MultiFilePatchView extends React.Component { // "forceRerender" ensures that the PullRequestCommentsView re-renders each time that the MultiFilePatchView does. // It doesn't re-query for reviews, but it does re-check patch visibility. return ( - - {commentThread => ( + + {({commentThreads}) => commentThreads.map(commentThread => ( - )} + ))} ); } else { diff --git a/test/controllers/pr-reviews-controller.test.js b/test/controllers/pr-reviews-controller.test.js index e90c1d6ca9..7bbf9e779c 100644 --- a/test/controllers/pr-reviews-controller.test.js +++ b/test/controllers/pr-reviews-controller.test.js @@ -1,19 +1,14 @@ import React from 'react'; import {shallow} from 'enzyme'; import {reviewBuilder} from '../builder/pr'; -import {inspect} from 'util'; import PullRequestReviewsController from '../../lib/controllers/pr-reviews-controller'; import PullRequestReviewCommentsContainer from '../../lib/containers/pr-review-comments-container'; import {PAGE_SIZE, PAGINATION_WAIT_TIME_MS} from '../../lib/helpers'; -function SomeView(props) { - return
    {inspect(props, {depth: 3})}
    ; -} - describe('PullRequestReviewsController', function() { - function buildApp(opts, overrideProps = {}, childFn = SomeView) { + function buildApp(opts, overrideProps = {}) { const o = { relayHasMore: () => false, relayLoadMore: () => {}, @@ -47,15 +42,13 @@ describe('PullRequestReviewsController', function() { isLoading: o.relayIsLoading, }, pullRequest: {reviews}, + children: () => {}, ...overrideProps, }; - return ( - - {childFn} - - ); + return ; } + it('returns null if props.pullRequest is falsy', function() { const wrapper = shallow(buildApp({}, {pullRequest: null})); assert.isNull(wrapper.getElement()); @@ -79,7 +72,7 @@ describe('PullRequestReviewsController', function() { assert.strictEqual(containers.at(1).prop('review').id, review2.id); }); - it('calls the child render prop for each comment thread', function() { + it('calls the render prop with all reviews and all comment threads', function() { const review1 = reviewBuilder() .id(10) .submittedAt('2019-01-01T10:00:00Z') @@ -100,11 +93,19 @@ describe('PullRequestReviewsController', function() { const reviewSpecs = [review1, review2]; const passThroughProp = 'I only exist for the children'; - const wrapper = shallow(buildApp({reviewSpecs}, {}, thread => { - return ; + const wrapper = shallow(buildApp({reviewSpecs}, { + children: ({reviews, commentThreads}) => ( + + ), })); - assert.isFalse(wrapper.exists('ChildComponent')); + assert.strictEqual(wrapper.find('ChildComponent').prop('passThroughProp'), passThroughProp); + assert.deepEqual(wrapper.find('ChildComponent').prop('reviews').map(review => review.id), [10, 20]); + assert.lengthOf(wrapper.find('ChildComponent').prop('threads'), 0); wrapper.find(PullRequestReviewCommentsContainer).at(0).prop('collectComments')({ reviewId: review1.id, @@ -113,12 +114,11 @@ describe('PullRequestReviewsController', function() { fetchingMoreComments: false, }); - assert.lengthOf(wrapper.find('ChildComponent'), 1); - assert.strictEqual(wrapper.find('ChildComponent').at(0).prop('passThroughProp'), passThroughProp); - assert.deepEqual(wrapper.find('ChildComponent').at(0).prop('thread'), { - rootCommentId: '1', - comments: [review1.comments.edges[0].node], - }); + assert.strictEqual(wrapper.find('ChildComponent').prop('passThroughProp'), passThroughProp); + assert.deepEqual(wrapper.find('ChildComponent').prop('reviews').map(review => review.id), [10, 20]); + assert.deepEqual(wrapper.find('ChildComponent').prop('threads'), [ + {rootCommentId: '1', comments: [review1.comments.edges[0].node]}, + ]); wrapper.find(PullRequestReviewCommentsContainer).at(1).prop('collectComments')({ reviewId: review2.id, @@ -127,25 +127,13 @@ describe('PullRequestReviewsController', function() { fetchingMoreComments: false, }); - assert.lengthOf(wrapper.find('ChildComponent'), 3); - - assert.strictEqual(wrapper.find('ChildComponent').at(0).prop('passThroughProp'), passThroughProp); - assert.deepEqual(wrapper.find('ChildComponent').at(0).prop('thread'), { - rootCommentId: '4', - comments: [review2.comments.edges[2].node], - }); - - assert.strictEqual(wrapper.find('ChildComponent').at(1).prop('passThroughProp'), passThroughProp); - assert.deepEqual(wrapper.find('ChildComponent').at(1).prop('thread'), { - rootCommentId: '2', - comments: [review2.comments.edges[0].node], - }); - - assert.strictEqual(wrapper.find('ChildComponent').at(2).prop('passThroughProp'), passThroughProp); - assert.deepEqual(wrapper.find('ChildComponent').at(2).prop('thread'), { - rootCommentId: '1', - comments: [review1.comments.edges[0].node, review2.comments.edges[1].node], - }); + assert.strictEqual(wrapper.find('ChildComponent').prop('passThroughProp'), passThroughProp); + assert.deepEqual(wrapper.find('ChildComponent').prop('reviews').map(review => review.id), [10, 20]); + assert.deepEqual(wrapper.find('ChildComponent').prop('threads'), [ + {rootCommentId: '4', comments: [review2.comments.edges[2].node]}, + {rootCommentId: '2', comments: [review2.comments.edges[0].node]}, + {rootCommentId: '1', comments: [review1.comments.edges[0].node, review2.comments.edges[1].node]}, + ]); }); describe('collectComments', function() { From 4c3211d15045e1a66a94701a4458624c04a54bef Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 4 Mar 2019 11:29:03 -0500 Subject: [PATCH 3004/4847] Oops, you _do_ need that pullRequest={} prop --- lib/views/multi-file-patch-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/multi-file-patch-view.js b/lib/views/multi-file-patch-view.js index 761861af54..f18183dfb5 100644 --- a/lib/views/multi-file-patch-view.js +++ b/lib/views/multi-file-patch-view.js @@ -386,7 +386,7 @@ export default class MultiFilePatchView extends React.Component { // "forceRerender" ensures that the PullRequestCommentsView re-renders each time that the MultiFilePatchView does. // It doesn't re-query for reviews, but it does re-check patch visibility. return ( - + {({commentThreads}) => commentThreads.map(commentThread => ( Date: Mon, 4 Mar 2019 17:32:17 +0100 Subject: [PATCH 3005/4847] split up to components, pull in markdown view and timeago --- lib/views/reviews-view.js | 390 +++++++------------------------------- 1 file changed, 67 insertions(+), 323 deletions(-) diff --git a/lib/views/reviews-view.js b/lib/views/reviews-view.js index 57365fd15c..19e04cf20b 100644 --- a/lib/views/reviews-view.js +++ b/lib/views/reviews-view.js @@ -1,5 +1,7 @@ import React from 'react'; import PullRequestReviewsContainer from '../containers/pr-reviews-container'; +import GithubDotcomMarkdown from './github-dotcom-markdown'; +import Timeago from './timeago'; export default class ReviewsView extends React.Component { @@ -41,329 +43,7 @@ export default class ReviewsView extends React.Component {
    - -
    - - - lib/controllers/ - commit-detail-controller.js - 19 - - 4h - - -
    -              
    { ' messageCollapsible: this.props.commit.isBodyLong(),' }
    -
    { ' messageOpen: !this.props.commit.isBodyLong(),' }
    -
    { ' };' }
    -
    { ' }' }
    -
    -
    -
    -
    - - annthurium - 4 hours ago -
    -
    mind adding the missing semicolon here?
    -
    - -
    - - - -
    -
    -
    - -
    -
    - -
    - - - lib/controllers/ - pr-reviews-controller.js - 22 - - 4h - - -
    -              
    { ' ),' }
    -
    { ' }),' }
    -
    { ' getBufferRowForDiffPosition: PropTypes.func.isRequired,' }
    -
    { ' isPatchTooLargeOrCollapsed: PropTypes.func.isRequired,' }
    -
    -
    -
    -
    - - annthurium - 4 hours ago -
    -
    this is a really long name -- can you come up with something more concise?
    -
    -
    -
    - - vanessayuenn - 18 minutes ago -
    -
    how about just isPatchCollapsed?
    -
    - -
    - - - -
    -
    -
    - -
    -
    - -
    - - - lib/models/patch/ - builder.js - 12 - - 1h - - -
    -              
    { 'export const DEFAULT_OPTIONS = {' }
    -
    { ' // Number of lines after which we consider the diff "large"' }
    -
    { ' // TODO: Set this based on performance measurements' }
    -
    { ' largeDiffThreshold: 100,' }
    -
    -
    -
    -
    - - annthurium - 1 hour ago -
    -
    @simurai: how many lines do you think constitutes a large diff? Not just from a performance perspective, but from a user experience perspective. Like how many lines is disruptive to a user when they're trying to read, because often large diffs are the result of auto generated code.
    -
    -
    -
    - - simurai - 1 hour ago -
    -
    Hmmm.. will large diffs be collapsed by default or there is a "load" button? Maybe if the diff is so large that it fills the whole scroll height. Then I can uncollapse only if I'm really interested in that file. 100 seems fine. 👍
    -
    -
    -
    - - annthurium - 1 hour ago -
    - -
    -
    -
    - - vanessayuenn - 25 minutes ago -
    -
    mm we were using 1000 lines as the threshold before, but that's for performance reasons. 100 does seem a bit small though considering it's counting both deleted and added lines. 🤔
    -
    - 300 seems a bit more reasonable, but still an arbitrary number.
    -
    - -
    - - - -
    -
    -
    - -
    -
    - -
    - - - lib/models/patch/ - multi-file-patch.js - 359 - - 4h - - -
    -              
    { ' }' }
    -
    { ' }' }
    -
    { '' }
    -
    { ' isPatchTooLargeOrCollapsed = filePatchPath => {' }
    -
    -
    -
    -
    - - annthurium - 4 hours ago -
    -
    same as above - this name is too long and the line length linters are gonna be unhappy.
    -
    - -
    - - - -
    -
    -
    - -
    -
    - -
    - - - lib/views/ - file-patch-header-view.js - 52 - - 2h - - -
    -              
    { '
    ' }
    -
    { ' ' }
    -
    { ' {this.renderTitle()}' }
    -
    { ' {this.renderCollapseButton()}' }
    -
    -
    -
    -
    - - simurai - 2 hours ago -
    -
    Should we move the chevron icon to the left? So that the position doesn't jump when there are more buttons. Alternative would be to move it all the way to the right.
    -
    - -
    - - - -
    -
    -
    - -
    -
    - -
    - - - test/views/ - pr-comments-view.test.js - 17 - - 4h - - -
    -              
    { ' };' }
    -
    { ' return shallow(' }
    -
    { ' -
    { ' isPatchTooLargeOrCollapsed={sinon.stub().returns(false)}' }
    -
    -
    -
    -
    - - annthurium - 4 hours ago -
    -
    again, this variable name is too long
    -
    - -
    - - - -
    -
    -
    - -
    -
    - -
    - - - lib/models/patch/ - builder.js - 280 - - 4h - - -
    -              
    { ' /*' }
    -
    { ' * Construct a String containing diagnostic information about the internal state of this FilePatch.' }
    -
    { ' */' }
    -
    { ' inspect(opts = {}) {' }
    -
    -
    -
    -
    - - annthurium - 4 hours ago -
    -
    nice! This is going to be so useful when we are trying to debug the marker layer on a text buffer.
    -
    - -
    - - - -
    -
    -
    - annthurium marked this as resolved - -
    -
    - +
    ); @@ -373,6 +53,7 @@ export default class ReviewsView extends React.Component { return (
    {this.renderReviewSummaries()} + {this.renderReviewComments()} {_commentThread => this.renderReviewComments()} @@ -380,3 +61,66 @@ export default class ReviewsView extends React.Component { ); } } + +class ReviewCommentThreadView extends React.Component { + render() { + const {comments} = this.props.commentThread; + const rootComment = comments[0]; + + return ( +
    + + + lib/controllers/ + commit-detail-controller.js + 19 + {rootComment.author.login} + {rootComment.createdAt} + + +
    +          
    { ' messageCollapsible: this.props.commit.isBodyLong(),' }
    +
    { ' messageOpen: !this.props.commit.isBodyLong(),' }
    +
    { ' };' }
    +
    { ' }' }
    +
    + +
    + {comments.map(comment => ( +
    +
    + {comment.author.login} + {comment.author.login} + + + +
    +
    + +
    +
    + ))} + +
    +