mirror of
https://github.com/pomber/git-history.git
synced 2024-08-17 02:10:25 +03:00
Move load to web worker
This commit is contained in:
parent
6d084adf1a
commit
4ab45430f1
10
craco.config.js
Normal file
10
craco.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module.exports = {
|
||||||
|
webpack: {
|
||||||
|
configure: {
|
||||||
|
output: {
|
||||||
|
// I need "this" for workerize-loader
|
||||||
|
globalObject: "this"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -4,6 +4,7 @@
|
|||||||
"repository": "pomber/git-history",
|
"repository": "pomber/git-history",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@craco/craco": "^3.4.1",
|
||||||
"diff": "^4.0.1",
|
"diff": "^4.0.1",
|
||||||
"js-base64": "^2.5.1",
|
"js-base64": "^2.5.1",
|
||||||
"netlify-auth-providers": "^1.0.0-alpha5",
|
"netlify-auth-providers": "^1.0.0-alpha5",
|
||||||
@ -12,10 +13,11 @@
|
|||||||
"react-dom": "^16.8.1",
|
"react-dom": "^16.8.1",
|
||||||
"react-scripts": "2.1.3",
|
"react-scripts": "2.1.3",
|
||||||
"react-swipeable": "^4.3.2",
|
"react-swipeable": "^4.3.2",
|
||||||
"react-use": "^5.2.2"
|
"react-use": "^5.2.2",
|
||||||
|
"workerize-loader": "^1.0.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "craco start",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
"format": "prettier --write \"**/*.{js,jsx,md,json,html,css,yml}\" --ignore-path .gitignore",
|
"format": "prettier --write \"**/*.{js,jsx,md,json,html,css,yml}\" --ignore-path .gitignore",
|
||||||
"test-prettier": "prettier --check \"**/*.{js,jsx,md,json,html,css,yml}\" --ignore-path .gitignore",
|
"test-prettier": "prettier --check \"**/*.{js,jsx,md,json,html,css,yml}\" --ignore-path .gitignore",
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
|
/* eslint-disable */
|
||||||
import { createAnimation, Stagger } from "./airframe/airframe";
|
import { createAnimation, Stagger } from "./airframe/airframe";
|
||||||
import easing from "./airframe/easing";
|
import easing from "./airframe/easing";
|
||||||
|
|
||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
const dx = 250;
|
const dx = 250;
|
||||||
|
|
||||||
/* @jsx createAnimation */
|
/* @jsx createAnimation */
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { getLanguage, loadLanguage } from "./language-detector";
|
|
||||||
|
|
||||||
export function Center({ children }) {
|
export function Center({ children }) {
|
||||||
return (
|
return (
|
||||||
@ -68,41 +67,6 @@ export function Error({ error, gitProvider }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useLoader(promiseFactory, deps) {
|
|
||||||
const [state, setState] = useState({
|
|
||||||
data: null,
|
|
||||||
loading: true,
|
|
||||||
error: null
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
promiseFactory()
|
|
||||||
.then(data => {
|
|
||||||
setState({
|
|
||||||
data,
|
|
||||||
loading: false,
|
|
||||||
error: false
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
setState({
|
|
||||||
loading: false,
|
|
||||||
error
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, deps);
|
|
||||||
|
|
||||||
return [state.data, state.loading, state.error];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useLanguageLoader(path) {
|
|
||||||
return useLoader(async () => {
|
|
||||||
const lang = getLanguage(path);
|
|
||||||
await loadLanguage(lang);
|
|
||||||
return lang;
|
|
||||||
}, [path]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useDocumentTitle(title) {
|
export function useDocumentTitle(title) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = title;
|
document.title = title;
|
||||||
|
37
src/app.js
37
src/app.js
@ -1,12 +1,7 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import History from "./history";
|
import History from "./history";
|
||||||
import Landing from "./landing";
|
import Landing from "./landing";
|
||||||
import {
|
import { useDocumentTitle, Loading, Error } from "./app-helpers";
|
||||||
useLanguageLoader,
|
|
||||||
useDocumentTitle,
|
|
||||||
Loading,
|
|
||||||
Error
|
|
||||||
} from "./app-helpers";
|
|
||||||
import getGitProvider from "./git-providers/providers";
|
import getGitProvider from "./git-providers/providers";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
@ -25,31 +20,32 @@ function InnerApp({ gitProvider }) {
|
|||||||
|
|
||||||
useDocumentTitle(`Git History - ${fileName}`);
|
useDocumentTitle(`Git History - ${fileName}`);
|
||||||
|
|
||||||
const [commits, commitsLoading, commitsError, loadMore] = useCommitsLoader(
|
const [versions, loading, error, loadMore] = useVersionsLoader(
|
||||||
gitProvider,
|
gitProvider,
|
||||||
path
|
path
|
||||||
);
|
);
|
||||||
const [lang, langLoading, langError] = useLanguageLoader(path);
|
|
||||||
|
|
||||||
const loading = langLoading || (!commits && commitsLoading);
|
|
||||||
const error = langError || commitsError;
|
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return <Error error={error} gitProvider={gitProvider} />;
|
return <Error error={error} gitProvider={gitProvider} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loading) {
|
if (!versions && loading) {
|
||||||
return <Loading path={path} />;
|
return <Loading path={path} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!commits.length) {
|
if (!versions.length) {
|
||||||
return <Error error={{ status: 404 }} gitProvider={gitProvider} />;
|
return <Error error={{ status: 404 }} gitProvider={gitProvider} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <History commits={commits} language={lang} loadMore={loadMore} />;
|
const commits = versions.map(v => v.commit);
|
||||||
|
const slideLines = versions.map(v => v.lines);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<History commits={commits} slideLines={slideLines} loadMore={loadMore} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useCommitsLoader(gitProvider, path) {
|
function useVersionsLoader(gitProvider) {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
data: null,
|
data: null,
|
||||||
loading: true,
|
loading: true,
|
||||||
@ -69,7 +65,7 @@ function useCommitsLoader(gitProvider, path) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
gitProvider
|
gitProvider
|
||||||
.getCommits(path, state.last)
|
.getVersions(state.last)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
setState(old => ({
|
setState(old => ({
|
||||||
data,
|
data,
|
||||||
@ -80,12 +76,13 @@ function useCommitsLoader(gitProvider, path) {
|
|||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
setState({
|
setState(old => ({
|
||||||
|
...old,
|
||||||
loading: false,
|
loading: false,
|
||||||
error
|
error: error.message
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
}, [state.last]);
|
||||||
}, [path, state.last]);
|
|
||||||
|
|
||||||
return [state.data, state.loading, state.error, loadMore];
|
return [state.data, state.loading, state.error, loadMore];
|
||||||
}
|
}
|
||||||
|
74
src/git-providers/bitbucket-commit-fetcher.js
Normal file
74
src/git-providers/bitbucket-commit-fetcher.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
const cache = {};
|
||||||
|
|
||||||
|
async function getCommits({ repo, sha, path, last, token }) {
|
||||||
|
if (!cache[path]) {
|
||||||
|
let fields =
|
||||||
|
"values.path,values.commit.date,values.commit.message,values.commit.hash,values.commit.author.*,values.commit.links.html, values.commit.author.user.nickname, values.commit.author.user.links.avatar.href, values.commit.links.html.href";
|
||||||
|
// fields = "*.*.*.*.*";
|
||||||
|
const commitsResponse = await fetch(
|
||||||
|
`https://api.bitbucket.org/2.0/repositories/${repo}/filehistory/${sha}/${path}?fields=${fields}`,
|
||||||
|
{ headers: token ? { Authorization: `bearer ${token}` } : {} }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!commitsResponse.ok) {
|
||||||
|
throw {
|
||||||
|
status: commitsResponse.status === 403 ? 404 : commitsResponse.status,
|
||||||
|
body: commitsJson
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const commitsJson = await commitsResponse.json();
|
||||||
|
|
||||||
|
cache[path] = commitsJson.values.map(({ commit }) => ({
|
||||||
|
sha: commit.hash,
|
||||||
|
date: new Date(commit.date),
|
||||||
|
author: {
|
||||||
|
login: commit.author.user
|
||||||
|
? commit.author.user.nickname
|
||||||
|
: commit.author.raw,
|
||||||
|
avatar: commit.author.user && commit.author.user.links.avatar.href
|
||||||
|
},
|
||||||
|
commitUrl: commit.links.html.href,
|
||||||
|
message: commit.message
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const commits = cache[path].slice(0, last);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
commits.map(async commit => {
|
||||||
|
if (!commit.content) {
|
||||||
|
const info = await getContent(repo, commit.sha, path, token);
|
||||||
|
commit.content = info.content;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return commits;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getContent(repo, sha, path, token) {
|
||||||
|
const contentResponse = await fetch(
|
||||||
|
`https://api.bitbucket.org/2.0/repositories/${repo}/src/${sha}/${path}`,
|
||||||
|
{ headers: token ? { Authorization: `bearer ${token}` } : {} }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (contentResponse.status === 404) {
|
||||||
|
return { content: "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contentResponse.ok) {
|
||||||
|
throw {
|
||||||
|
status: contentResponse.status,
|
||||||
|
body: contentJson
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = await contentResponse.text();
|
||||||
|
|
||||||
|
return { content };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getCommits
|
||||||
|
};
|
@ -1,35 +1,15 @@
|
|||||||
import netlify from "netlify-auth-providers";
|
import netlify from "netlify-auth-providers";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
const TOKEN_KEY = "bitbucket-token";
|
|
||||||
|
|
||||||
function getHeaders() {
|
import versioner from "./versioner";
|
||||||
const token = window.localStorage.getItem(TOKEN_KEY);
|
import { SOURCE } from "./sources";
|
||||||
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
||||||
}
|
const TOKEN_KEY = "bitbucket-token";
|
||||||
|
|
||||||
function isLoggedIn() {
|
function isLoggedIn() {
|
||||||
return !!window.localStorage.getItem(TOKEN_KEY);
|
return !!window.localStorage.getItem(TOKEN_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getContent(repo, sha, path) {
|
|
||||||
const contentResponse = await fetch(
|
|
||||||
`https://api.bitbucket.org/2.0/repositories/${repo}/src/${sha}/${path}`,
|
|
||||||
{ headers: getHeaders() }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (contentResponse.status === 404) {
|
|
||||||
return { content: "" };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!contentResponse.ok) {
|
|
||||||
throw contentResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
const content = await contentResponse.text();
|
|
||||||
|
|
||||||
return { content };
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUrlParams() {
|
function getUrlParams() {
|
||||||
const [, owner, reponame, , sha, ...paths] = window.location.pathname.split(
|
const [, owner, reponame, , sha, ...paths] = window.location.pathname.split(
|
||||||
"/"
|
"/"
|
||||||
@ -52,52 +32,6 @@ function showLanding() {
|
|||||||
return !repo;
|
return !repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cache = {};
|
|
||||||
|
|
||||||
async function getCommits(path, last) {
|
|
||||||
const [repo, sha] = getUrlParams();
|
|
||||||
|
|
||||||
if (!cache[path]) {
|
|
||||||
let fields =
|
|
||||||
"values.path,values.commit.date,values.commit.message,values.commit.hash,values.commit.author.*,values.commit.links.html, values.commit.author.user.nickname, values.commit.author.user.links.avatar.href, values.commit.links.html.href";
|
|
||||||
// fields = "*.*.*.*.*";
|
|
||||||
const commitsResponse = await fetch(
|
|
||||||
`https://api.bitbucket.org/2.0/repositories/${repo}/filehistory/${sha}/${path}?fields=${fields}`,
|
|
||||||
{ headers: getHeaders() }
|
|
||||||
);
|
|
||||||
if (!commitsResponse.ok) {
|
|
||||||
throw commitsResponse;
|
|
||||||
}
|
|
||||||
const commitsJson = await commitsResponse.json();
|
|
||||||
|
|
||||||
cache[path] = commitsJson.values.map(({ commit }) => ({
|
|
||||||
sha: commit.hash,
|
|
||||||
date: new Date(commit.date),
|
|
||||||
author: {
|
|
||||||
login: commit.author.user
|
|
||||||
? commit.author.user.nickname
|
|
||||||
: commit.author.raw,
|
|
||||||
avatar: commit.author.user && commit.author.user.links.avatar.href
|
|
||||||
},
|
|
||||||
commitUrl: commit.links.html.href,
|
|
||||||
message: commit.message
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const commits = cache[path].slice(0, last);
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
commits.map(async commit => {
|
|
||||||
if (!commit.content) {
|
|
||||||
const info = await getContent(repo, commit.sha, path);
|
|
||||||
commit.content = info.content;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return commits;
|
|
||||||
}
|
|
||||||
|
|
||||||
function logIn() {
|
function logIn() {
|
||||||
// return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
var authenticator = new netlify({
|
var authenticator = new netlify({
|
||||||
@ -125,10 +59,21 @@ function LogInButton() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getParams() {
|
||||||
|
const [repo, sha, path] = getUrlParams();
|
||||||
|
const token = window.localStorage.getItem(TOKEN_KEY);
|
||||||
|
return { repo, sha, path, token };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getVersions(last) {
|
||||||
|
const params = { ...getParams(), last };
|
||||||
|
return await versioner.getVersions(SOURCE.BITBUCKET, params);
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
showLanding,
|
showLanding,
|
||||||
getPath,
|
getPath,
|
||||||
getCommits,
|
getVersions,
|
||||||
logIn,
|
logIn,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
LogInButton
|
LogInButton
|
||||||
|
14
src/git-providers/cli-commit-fetcher.js
Normal file
14
src/git-providers/cli-commit-fetcher.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
async function getCommits({ path, last }) {
|
||||||
|
// TODO cache
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/commits?path=${encodeURIComponent(path)}&last=${last}`
|
||||||
|
);
|
||||||
|
const commits = await response.json();
|
||||||
|
commits.forEach(c => (c.date = new Date(c.date)));
|
||||||
|
|
||||||
|
return commits;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getCommits
|
||||||
|
};
|
@ -1,3 +1,6 @@
|
|||||||
|
import versioner from "./versioner";
|
||||||
|
import { SOURCE } from "./sources";
|
||||||
|
|
||||||
function getPath() {
|
function getPath() {
|
||||||
return new URLSearchParams(window.location.search).get("path");
|
return new URLSearchParams(window.location.search).get("path");
|
||||||
}
|
}
|
||||||
@ -6,19 +9,13 @@ function showLanding() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCommits(path, last) {
|
async function getVersions(last) {
|
||||||
// TODO cache
|
const params = { path: getPath(), last };
|
||||||
const response = await fetch(
|
return await versioner.getVersions(SOURCE.CLI, params);
|
||||||
`/api/commits?path=${encodeURIComponent(path)}&last=${last}`
|
|
||||||
);
|
|
||||||
const commits = await response.json();
|
|
||||||
commits.forEach(c => (c.date = new Date(c.date)));
|
|
||||||
|
|
||||||
return commits;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
showLanding,
|
showLanding,
|
||||||
getPath,
|
getVersions,
|
||||||
getCommits
|
getPath
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import * as diff from "diff";
|
import { diffLines } from "diff";
|
||||||
import tokenize from "./tokenizer";
|
import tokenize from "./tokenizer";
|
||||||
const newlineRe = /\r\n|\r|\n/;
|
const newlineRe = /\r\n|\r|\n/;
|
||||||
|
|
||||||
function myDiff(oldCode, newCode) {
|
function myDiff(oldCode, newCode) {
|
||||||
const changes = diff.diffLines(oldCode || "", newCode);
|
const changes = diffLines(oldCode || "", newCode);
|
||||||
|
|
||||||
let oldIndex = -1;
|
let oldIndex = -1;
|
||||||
return changes.map(({ value, count, removed, added }) => {
|
return changes.map(({ value, count, removed, added }) => {
|
74
src/git-providers/github-commit-fetcher.js
Normal file
74
src/git-providers/github-commit-fetcher.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { Base64 } from "js-base64";
|
||||||
|
|
||||||
|
const cache = {};
|
||||||
|
|
||||||
|
async function getCommits({ repo, sha, path, token, last }) {
|
||||||
|
if (!cache[path]) {
|
||||||
|
const commitsResponse = await fetch(
|
||||||
|
`https://api.github.com/repos/${repo}/commits?sha=${sha}&path=${path}`,
|
||||||
|
{ headers: token ? { Authorization: `bearer ${token}` } : {} }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!commitsResponse.ok) {
|
||||||
|
throw {
|
||||||
|
status: commitsResponse.status,
|
||||||
|
body: commitsJson
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const commitsJson = await commitsResponse.json();
|
||||||
|
|
||||||
|
cache[path] = commitsJson.map(commit => ({
|
||||||
|
sha: commit.sha,
|
||||||
|
date: new Date(commit.commit.author.date),
|
||||||
|
author: {
|
||||||
|
login: commit.author ? commit.author.login : commit.commit.author.name,
|
||||||
|
avatar: commit.author
|
||||||
|
? commit.author.avatar_url
|
||||||
|
: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
|
||||||
|
},
|
||||||
|
commitUrl: commit.html_url,
|
||||||
|
message: commit.commit.message
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const commits = cache[path].slice(0, last);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
commits.map(async commit => {
|
||||||
|
if (!commit.content) {
|
||||||
|
const info = await getContent(repo, commit.sha, path, token);
|
||||||
|
commit.content = info.content;
|
||||||
|
commit.fileUrl = info.url;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return commits;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getContent(repo, sha, path, token) {
|
||||||
|
const contentResponse = await fetch(
|
||||||
|
`https://api.github.com/repos/${repo}/contents${path}?ref=${sha}`,
|
||||||
|
{ headers: token ? { Authorization: `bearer ${token}` } : {} }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (contentResponse.status === 404) {
|
||||||
|
return { content: "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contentResponse.ok) {
|
||||||
|
throw {
|
||||||
|
status: contentResponse.status,
|
||||||
|
body: contentJson
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentJson = await contentResponse.json();
|
||||||
|
const content = Base64.decode(contentJson.content);
|
||||||
|
return { content, url: contentJson.html_url };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getCommits
|
||||||
|
};
|
@ -1,34 +1,14 @@
|
|||||||
import netlify from "netlify-auth-providers";
|
import netlify from "netlify-auth-providers";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Base64 } from "js-base64";
|
import versioner from "./versioner";
|
||||||
const TOKEN_KEY = "github-token";
|
import { SOURCE } from "./sources";
|
||||||
|
|
||||||
function getHeaders() {
|
const TOKEN_KEY = "github-token";
|
||||||
const token = window.localStorage.getItem(TOKEN_KEY);
|
|
||||||
return token ? { Authorization: `bearer ${token}` } : {};
|
|
||||||
}
|
|
||||||
|
|
||||||
function isLoggedIn() {
|
function isLoggedIn() {
|
||||||
return !!window.localStorage.getItem(TOKEN_KEY);
|
return !!window.localStorage.getItem(TOKEN_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getContent(repo, sha, path) {
|
|
||||||
const contentResponse = await fetch(
|
|
||||||
`https://api.github.com/repos/${repo}/contents${path}?ref=${sha}`,
|
|
||||||
{ headers: getHeaders() }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (contentResponse.status === 404) {
|
|
||||||
return { content: "" };
|
|
||||||
}
|
|
||||||
if (!contentResponse.ok) {
|
|
||||||
throw contentResponse;
|
|
||||||
}
|
|
||||||
const contentJson = await contentResponse.json();
|
|
||||||
const content = Base64.decode(contentJson.content);
|
|
||||||
return { content, url: contentJson.html_url };
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUrlParams() {
|
function getUrlParams() {
|
||||||
const [
|
const [
|
||||||
,
|
,
|
||||||
@ -56,50 +36,6 @@ function showLanding() {
|
|||||||
return !repo;
|
return !repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cache = {};
|
|
||||||
|
|
||||||
async function getCommits(path, last) {
|
|
||||||
const [repo, sha] = getUrlParams();
|
|
||||||
|
|
||||||
if (!cache[path]) {
|
|
||||||
const commitsResponse = await fetch(
|
|
||||||
`https://api.github.com/repos/${repo}/commits?sha=${sha}&path=${path}`,
|
|
||||||
{ headers: getHeaders() }
|
|
||||||
);
|
|
||||||
if (!commitsResponse.ok) {
|
|
||||||
throw commitsResponse;
|
|
||||||
}
|
|
||||||
const commitsJson = await commitsResponse.json();
|
|
||||||
|
|
||||||
cache[path] = commitsJson.map(commit => ({
|
|
||||||
sha: commit.sha,
|
|
||||||
date: new Date(commit.commit.author.date),
|
|
||||||
author: {
|
|
||||||
login: commit.author ? commit.author.login : commit.commit.author.name,
|
|
||||||
avatar: commit.author
|
|
||||||
? commit.author.avatar_url
|
|
||||||
: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
|
|
||||||
},
|
|
||||||
commitUrl: commit.html_url,
|
|
||||||
message: commit.commit.message
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const commits = cache[path].slice(0, last);
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
commits.map(async commit => {
|
|
||||||
if (!commit.content) {
|
|
||||||
const info = await getContent(repo, commit.sha, path);
|
|
||||||
commit.content = info.content;
|
|
||||||
commit.fileUrl = info.url;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return commits;
|
|
||||||
}
|
|
||||||
|
|
||||||
function logIn() {
|
function logIn() {
|
||||||
// return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
var authenticator = new netlify({
|
var authenticator = new netlify({
|
||||||
@ -143,10 +79,22 @@ function LogInButton() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getParams() {
|
||||||
|
const [repo, sha, path] = getUrlParams();
|
||||||
|
const token = window.localStorage.getItem(TOKEN_KEY);
|
||||||
|
return { repo, sha, path, token };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getVersions(last) {
|
||||||
|
const params = { ...getParams(), last };
|
||||||
|
return await versioner.getVersions(SOURCE.GITHUB, params);
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
showLanding,
|
showLanding,
|
||||||
getPath,
|
getPath,
|
||||||
getCommits,
|
getParams,
|
||||||
|
getVersions,
|
||||||
logIn,
|
logIn,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
LogInButton
|
LogInButton
|
||||||
|
74
src/git-providers/gitlab-commit-fetcher.js
Normal file
74
src/git-providers/gitlab-commit-fetcher.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { Base64 } from "js-base64";
|
||||||
|
|
||||||
|
const cache = {};
|
||||||
|
|
||||||
|
async function getCommits({ repo, sha, path, token, last }) {
|
||||||
|
if (!cache[path]) {
|
||||||
|
const commitsResponse = await fetch(
|
||||||
|
`https://gitlab.com/api/v4/projects/${encodeURIComponent(
|
||||||
|
repo
|
||||||
|
)}/repository/commits?path=${encodeURIComponent(path)}&ref_name=${sha}`,
|
||||||
|
{ headers: token ? { Authorization: `bearer ${token}` } : {} }
|
||||||
|
);
|
||||||
|
|
||||||
|
const commitsJson = await commitsResponse.json();
|
||||||
|
|
||||||
|
if (!commitsResponse.ok) {
|
||||||
|
throw {
|
||||||
|
status: commitsResponse.status,
|
||||||
|
body: commitsJson
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
cache[path] = commitsJson.map(commit => ({
|
||||||
|
sha: commit.id,
|
||||||
|
date: new Date(commit.authored_date),
|
||||||
|
author: {
|
||||||
|
login: commit.author_name
|
||||||
|
},
|
||||||
|
// commitUrl: commit.html_url,
|
||||||
|
message: commit.title
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const commits = cache[path].slice(0, last);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
commits.map(async commit => {
|
||||||
|
if (!commit.content) {
|
||||||
|
const info = await getContent(repo, commit.sha, path, token);
|
||||||
|
commit.content = info.content;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return commits;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getContent(repo, sha, path, token) {
|
||||||
|
const contentResponse = await fetch(
|
||||||
|
`https://gitlab.com/api/v4/projects/${encodeURIComponent(
|
||||||
|
repo
|
||||||
|
)}/repository/files/${encodeURIComponent(path)}?ref=${sha}`,
|
||||||
|
{ headers: token ? { Authorization: `bearer ${token}` } : {} }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (contentResponse.status === 404) {
|
||||||
|
return { content: "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contentResponse.ok) {
|
||||||
|
throw {
|
||||||
|
status: contentResponse.status,
|
||||||
|
body: contentJson
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentJson = await contentResponse.json();
|
||||||
|
const content = Base64.decode(contentJson.content);
|
||||||
|
return { content };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getCommits
|
||||||
|
};
|
@ -1,36 +1,15 @@
|
|||||||
import netlify from "netlify-auth-providers";
|
import netlify from "netlify-auth-providers";
|
||||||
import { Base64 } from "js-base64";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
const TOKEN_KEY = "gitlab-token";
|
|
||||||
|
|
||||||
function getHeaders() {
|
import versioner from "./versioner";
|
||||||
const token = window.localStorage.getItem(TOKEN_KEY);
|
import { SOURCE } from "./sources";
|
||||||
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
||||||
}
|
const TOKEN_KEY = "gitlab-token";
|
||||||
|
|
||||||
function isLoggedIn() {
|
function isLoggedIn() {
|
||||||
return !!window.localStorage.getItem(TOKEN_KEY);
|
return !!window.localStorage.getItem(TOKEN_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getContent(repo, sha, path) {
|
|
||||||
const contentResponse = await fetch(
|
|
||||||
`https://gitlab.com/api/v4/projects/${encodeURIComponent(
|
|
||||||
repo
|
|
||||||
)}/repository/files/${encodeURIComponent(path)}?ref=${sha}`,
|
|
||||||
{ headers: getHeaders() }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (contentResponse.status === 404) {
|
|
||||||
return { content: "" };
|
|
||||||
}
|
|
||||||
if (!contentResponse.ok) {
|
|
||||||
throw contentResponse;
|
|
||||||
}
|
|
||||||
const contentJson = await contentResponse.json();
|
|
||||||
const content = Base64.decode(contentJson.content);
|
|
||||||
return { content };
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUrlParams() {
|
function getUrlParams() {
|
||||||
const [
|
const [
|
||||||
,
|
,
|
||||||
@ -58,48 +37,6 @@ function showLanding() {
|
|||||||
return !repo;
|
return !repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cache = {};
|
|
||||||
|
|
||||||
async function getCommits(path, last) {
|
|
||||||
const [repo, sha] = getUrlParams();
|
|
||||||
|
|
||||||
if (!cache[path]) {
|
|
||||||
const commitsResponse = await fetch(
|
|
||||||
`https://gitlab.com/api/v4/projects/${encodeURIComponent(
|
|
||||||
repo
|
|
||||||
)}/repository/commits?path=${encodeURIComponent(path)}&ref_name=${sha}`,
|
|
||||||
{ headers: getHeaders() }
|
|
||||||
);
|
|
||||||
if (!commitsResponse.ok) {
|
|
||||||
throw commitsResponse;
|
|
||||||
}
|
|
||||||
const commitsJson = await commitsResponse.json();
|
|
||||||
|
|
||||||
cache[path] = commitsJson.map(commit => ({
|
|
||||||
sha: commit.id,
|
|
||||||
date: new Date(commit.authored_date),
|
|
||||||
author: {
|
|
||||||
login: commit.author_name
|
|
||||||
},
|
|
||||||
// commitUrl: commit.html_url,
|
|
||||||
message: commit.title
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const commits = cache[path].slice(0, last);
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
commits.map(async commit => {
|
|
||||||
if (!commit.content) {
|
|
||||||
const info = await getContent(repo, commit.sha, path);
|
|
||||||
commit.content = info.content;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return commits;
|
|
||||||
}
|
|
||||||
|
|
||||||
function logIn() {
|
function logIn() {
|
||||||
// return new Promise((resolve, reject) => {
|
// return new Promise((resolve, reject) => {
|
||||||
var authenticator = new netlify({
|
var authenticator = new netlify({
|
||||||
@ -130,10 +67,21 @@ function LogInButton() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getParams() {
|
||||||
|
const [repo, sha, path] = getUrlParams();
|
||||||
|
const token = window.localStorage.getItem(TOKEN_KEY);
|
||||||
|
return { repo, sha, path, token };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getVersions(last) {
|
||||||
|
const params = { ...getParams(), last };
|
||||||
|
return await versioner.getVersions(SOURCE.GITLAB, params);
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
showLanding,
|
showLanding,
|
||||||
getPath,
|
getPath,
|
||||||
getCommits,
|
getVersions,
|
||||||
logIn,
|
logIn,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
LogInButton
|
LogInButton
|
||||||
|
@ -3,21 +3,18 @@ import githubProvider from "./github-provider";
|
|||||||
import vscodeProvider from "./vscode-provider";
|
import vscodeProvider from "./vscode-provider";
|
||||||
import gitlabProvider from "./gitlab-provider";
|
import gitlabProvider from "./gitlab-provider";
|
||||||
import bitbucketProvider from "./bitbucket-provider";
|
import bitbucketProvider from "./bitbucket-provider";
|
||||||
|
import { SOURCE, getSource } from "./sources";
|
||||||
|
|
||||||
export default function getGitProvider() {
|
const providers = {
|
||||||
switch (process.env.REACT_APP_GIT_PROVIDER) {
|
[SOURCE.CLI]: cliProvider,
|
||||||
case "cli":
|
[SOURCE.VSCODE]: vscodeProvider,
|
||||||
return cliProvider;
|
[SOURCE.GITLAB]: gitlabProvider,
|
||||||
case "vscode":
|
[SOURCE.GITHUB]: githubProvider,
|
||||||
return vscodeProvider;
|
[SOURCE.BITBUCKET]: bitbucketProvider
|
||||||
default: {
|
};
|
||||||
const [cloud] = window.location.host.split(".");
|
|
||||||
if (cloud === "gitlab") {
|
export default function getGitProvider(source) {
|
||||||
return gitlabProvider;
|
source = source || getSource();
|
||||||
} else if (cloud === "bitbucket") {
|
const provider = providers[source];
|
||||||
return bitbucketProvider;
|
return provider;
|
||||||
}
|
|
||||||
return githubProvider;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
18
src/git-providers/sources.js
Normal file
18
src/git-providers/sources.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export const SOURCE = {
|
||||||
|
GITHUB: "github",
|
||||||
|
GITLAB: "gitlab",
|
||||||
|
BITBUCKET: "bitbucket",
|
||||||
|
CLI: "cli",
|
||||||
|
VSCODE: "vscode"
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getSource() {
|
||||||
|
if (process.env.REACT_APP_GIT_PROVIDER)
|
||||||
|
return process.env.REACT_APP_GIT_PROVIDER;
|
||||||
|
|
||||||
|
const [cloud] = window.location.host.split(".");
|
||||||
|
if ([SOURCE.GITLAB, SOURCE.GITHUB, SOURCE.BITBUCKET].includes(cloud)) {
|
||||||
|
return cloud;
|
||||||
|
}
|
||||||
|
return SOURCE.BITBUCKET;
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
import Prism from "prismjs";
|
// https://github.com/PrismJS/prism/issues/1303#issuecomment-375353987
|
||||||
|
global.Prism = { disableWorkerMessageHandler: true };
|
||||||
|
const Prism = require("prismjs");
|
||||||
|
|
||||||
const newlineRe = /\r\n|\r|\n/;
|
const newlineRe = /\r\n|\r|\n/;
|
||||||
|
|
5
src/git-providers/versioner.js
Normal file
5
src/git-providers/versioner.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/* eslint-disable import/no-webpack-loader-syntax */
|
||||||
|
import worker from "workerize-loader!./versioner.worker";
|
||||||
|
let versioner = worker();
|
||||||
|
|
||||||
|
export default versioner;
|
29
src/git-providers/versioner.worker.js
Normal file
29
src/git-providers/versioner.worker.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { getLanguage, loadLanguage } from "./language-detector";
|
||||||
|
import { getSlides } from "./differ";
|
||||||
|
|
||||||
|
import github from "./github-commit-fetcher";
|
||||||
|
import gitlab from "./gitlab-commit-fetcher";
|
||||||
|
import bitbucket from "./bitbucket-commit-fetcher";
|
||||||
|
import cli from "./cli-commit-fetcher";
|
||||||
|
import { SOURCE } from "./sources";
|
||||||
|
|
||||||
|
const fetchers = {
|
||||||
|
[SOURCE.GITHUB]: github.getCommits,
|
||||||
|
[SOURCE.GITLAB]: gitlab.getCommits,
|
||||||
|
[SOURCE.BITBUCKET]: bitbucket.getCommits,
|
||||||
|
[SOURCE.CLI]: cli.getCommits
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getVersions(source, params) {
|
||||||
|
const { path } = params;
|
||||||
|
const lang = getLanguage(path);
|
||||||
|
const langPromise = loadLanguage(lang);
|
||||||
|
|
||||||
|
const getCommits = fetchers[source];
|
||||||
|
const commits = await getCommits(params);
|
||||||
|
await langPromise;
|
||||||
|
|
||||||
|
const codes = commits.map(commit => commit.content);
|
||||||
|
const slides = getSlides(codes, lang);
|
||||||
|
return commits.map((commit, i) => ({ commit, lines: slides[i] }));
|
||||||
|
}
|
@ -1,3 +1,6 @@
|
|||||||
|
import { getLanguage, loadLanguage } from "./language-detector";
|
||||||
|
import { getSlides } from "./differ";
|
||||||
|
|
||||||
const vscode = window.vscode;
|
const vscode = window.vscode;
|
||||||
|
|
||||||
function getPath() {
|
function getPath() {
|
||||||
@ -30,8 +33,21 @@ function getCommits(path, last) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getVersions(last) {
|
||||||
|
const path = getPath();
|
||||||
|
const lang = getLanguage(path);
|
||||||
|
const langPromise = loadLanguage(lang);
|
||||||
|
|
||||||
|
const commits = await getCommits(path, last);
|
||||||
|
await langPromise;
|
||||||
|
|
||||||
|
const codes = commits.map(commit => commit.content);
|
||||||
|
const slides = getSlides(codes, lang);
|
||||||
|
return commits.map((commit, i) => ({ commit, lines: slides[i] }));
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
showLanding,
|
showLanding,
|
||||||
getPath,
|
getPath,
|
||||||
getCommits
|
getVersions
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { getSlides } from "./differ";
|
|
||||||
import useSpring from "react-use/lib/useSpring";
|
import useSpring from "react-use/lib/useSpring";
|
||||||
import Swipeable from "react-swipeable";
|
import Swipeable from "react-swipeable";
|
||||||
import Slide from "./slide";
|
import Slide from "./slide";
|
||||||
@ -43,7 +42,11 @@ function CommitInfo({ commit, move, onClick }) {
|
|||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: "0.85rem", opacity: "0.9" }}>
|
<div style={{ fontSize: "0.85rem", opacity: "0.9" }}>
|
||||||
{isActive && commit.commitUrl ? (
|
{isActive && commit.commitUrl ? (
|
||||||
<a href={commit.commitUrl} target="_blank">
|
<a
|
||||||
|
href={commit.commitUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
on {commit.date.toDateString()}
|
on {commit.date.toDateString()}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
@ -96,10 +99,7 @@ function CommitList({ commits, currentIndex, selectCommit }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function History({ commits, language, loadMore }) {
|
export default function History({ commits, slideLines, loadMore }) {
|
||||||
const codes = commits.map(commit => commit.content);
|
|
||||||
const slideLines = getSlides(codes, language);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slides slideLines={slideLines} commits={commits} loadMore={loadMore} />
|
<Slides slideLines={slideLines} commits={commits} loadMore={loadMore} />
|
||||||
);
|
);
|
||||||
|
@ -69,6 +69,7 @@ export default function Landing() {
|
|||||||
<a
|
<a
|
||||||
href="https://opencollective.com/git-history/donate"
|
href="https://opencollective.com/git-history/donate"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src="https://opencollective.com/git-history/donate/button.png?color=white"
|
src="https://opencollective.com/git-history/donate/button.png?color=white"
|
||||||
|
@ -28,7 +28,7 @@ export default function Scroller({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{ height: "100%", overflowY: "auto" }}
|
style={{ height: "100%", overflowY: "auto", overflowX: "hidden" }}
|
||||||
className="scroller"
|
className="scroller"
|
||||||
ref={ref}
|
ref={ref}
|
||||||
onScroll={e => setTop(e.target.scrollTop)}
|
onScroll={e => setTop(e.target.scrollTop)}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
- move diffing to web worker
|
- move diffing to web worker
|
||||||
- make diffing incremental
|
- make diffing incremental
|
||||||
- cache all the react elements from the lines + styles
|
- cache all the react elements from the lines + styles
|
||||||
- only set scrollTop if `top` is different from the last value from the event (and clean the last value from the event after that)
|
- only set scrollTop if `top` is different from the last value from the event (and clean the last value from the event after that) https://codesandbox.io/s/r089yvk82m
|
||||||
|
98
yarn.lock
98
yarn.lock
@ -865,6 +865,15 @@
|
|||||||
lodash "^4.17.10"
|
lodash "^4.17.10"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
|
"@craco/craco@^3.4.1":
|
||||||
|
version "3.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@craco/craco/-/craco-3.4.1.tgz#a65e29d7cb661e09e68269ba09ade39d174ec359"
|
||||||
|
integrity sha512-PVuDx5iLzoYeFrjNUVbblQCGzFyw/DoBBHFI4+JlSCvgEkp07jbBm5fe+z/MqzYJUQm1bFbxe6qbQWI5LFl6XA==
|
||||||
|
dependencies:
|
||||||
|
cross-spawn "6.0.5"
|
||||||
|
lodash.mergewith "4.6.1"
|
||||||
|
webpack-merge "4.1.4"
|
||||||
|
|
||||||
"@csstools/convert-colors@^1.4.0":
|
"@csstools/convert-colors@^1.4.0":
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
|
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
|
||||||
@ -1141,11 +1150,6 @@ acorn@^6.0.1, acorn@^6.0.2, acorn@^6.0.4:
|
|||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.5.tgz#81730c0815f3f3b34d8efa95cb7430965f4d887a"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.5.tgz#81730c0815f3f3b34d8efa95cb7430965f4d887a"
|
||||||
integrity sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==
|
integrity sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==
|
||||||
|
|
||||||
add-px-to-style@1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/add-px-to-style/-/add-px-to-style-1.0.0.tgz#d0c135441fa8014a8137904531096f67f28f263a"
|
|
||||||
integrity sha1-0ME1RB+oAUqBN5BFMQlvZ/KPJjo=
|
|
||||||
|
|
||||||
address@1.0.3, address@^1.0.1:
|
address@1.0.3, address@^1.0.1:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9"
|
resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9"
|
||||||
@ -3095,15 +3099,6 @@ dom-converter@~0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
utila "~0.4"
|
utila "~0.4"
|
||||||
|
|
||||||
dom-css@^2.0.0:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/dom-css/-/dom-css-2.1.0.tgz#fdbc2d5a015d0a3e1872e11472bbd0e7b9e6a202"
|
|
||||||
integrity sha1-/bwtWgFdCj4YcuEUcrvQ57nmogI=
|
|
||||||
dependencies:
|
|
||||||
add-px-to-style "1.0.0"
|
|
||||||
prefix-style "2.0.1"
|
|
||||||
to-camel-case "1.0.0"
|
|
||||||
|
|
||||||
dom-serializer@0:
|
dom-serializer@0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
|
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
|
||||||
@ -6000,6 +5995,11 @@ lodash.memoize@^4.1.2:
|
|||||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||||
|
|
||||||
|
lodash.mergewith@4.6.1:
|
||||||
|
version "4.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
|
||||||
|
integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==
|
||||||
|
|
||||||
lodash.sortby@^4.7.0:
|
lodash.sortby@^4.7.0:
|
||||||
version "4.7.0"
|
version "4.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||||
@ -6040,7 +6040,7 @@ loglevel@^1.4.1:
|
|||||||
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa"
|
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa"
|
||||||
integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=
|
integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=
|
||||||
|
|
||||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
|
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||||
@ -7797,11 +7797,6 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2, postcss@^7.0.5, postcss@^7.0.7:
|
|||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
supports-color "^5.5.0"
|
supports-color "^5.5.0"
|
||||||
|
|
||||||
prefix-style@2.0.1:
|
|
||||||
version "2.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/prefix-style/-/prefix-style-2.0.1.tgz#66bba9a870cfda308a5dc20e85e9120932c95a06"
|
|
||||||
integrity sha1-ZrupqHDP2jCKXcIOhekSCTLJWgY=
|
|
||||||
|
|
||||||
prelude-ls@~1.1.2:
|
prelude-ls@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||||
@ -7890,15 +7885,6 @@ prompts@^0.1.9:
|
|||||||
kleur "^2.0.1"
|
kleur "^2.0.1"
|
||||||
sisteransi "^0.1.1"
|
sisteransi "^0.1.1"
|
||||||
|
|
||||||
prop-types@^15.5.10:
|
|
||||||
version "15.7.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
|
||||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.4.0"
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
react-is "^16.8.1"
|
|
||||||
|
|
||||||
prop-types@^15.5.8, prop-types@^15.6.2:
|
prop-types@^15.5.8, prop-types@^15.6.2:
|
||||||
version "15.6.2"
|
version "15.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
|
||||||
@ -8014,13 +8000,6 @@ raf@3.4.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
performance-now "^2.1.0"
|
performance-now "^2.1.0"
|
||||||
|
|
||||||
raf@^3.1.0:
|
|
||||||
version "3.4.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
|
|
||||||
integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
|
|
||||||
dependencies:
|
|
||||||
performance-now "^2.1.0"
|
|
||||||
|
|
||||||
randomatic@^3.0.0:
|
randomatic@^3.0.0:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
|
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
|
||||||
@ -8081,15 +8060,6 @@ react-app-polyfill@^0.2.0:
|
|||||||
raf "3.4.0"
|
raf "3.4.0"
|
||||||
whatwg-fetch "3.0.0"
|
whatwg-fetch "3.0.0"
|
||||||
|
|
||||||
react-custom-scrollbars@^4.2.1:
|
|
||||||
version "4.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-custom-scrollbars/-/react-custom-scrollbars-4.2.1.tgz#830fd9502927e97e8a78c2086813899b2a8b66db"
|
|
||||||
integrity sha1-gw/ZUCkn6X6KeMIIaBOJmyqLZts=
|
|
||||||
dependencies:
|
|
||||||
dom-css "^2.0.0"
|
|
||||||
prop-types "^15.5.10"
|
|
||||||
raf "^3.1.0"
|
|
||||||
|
|
||||||
react-dev-utils@^7.0.1:
|
react-dev-utils@^7.0.1:
|
||||||
version "7.0.1"
|
version "7.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-7.0.1.tgz#c53e759a22668ee2c0d146c24ce4bdec2b41e3c8"
|
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-7.0.1.tgz#c53e759a22668ee2c0d146c24ce4bdec2b41e3c8"
|
||||||
@ -8135,11 +8105,6 @@ react-error-overlay@^5.1.2:
|
|||||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-5.1.2.tgz#888957b884d4b25b083a82ad550f7aad96585394"
|
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-5.1.2.tgz#888957b884d4b25b083a82ad550f7aad96585394"
|
||||||
integrity sha512-7kEBKwU9R8fKnZJBRa5RSIfay4KJwnYvKB6gODGicUmDSAhQJ7Tdnll5S0RLtYrzRfMVXlqYw61rzrSpP4ThLQ==
|
integrity sha512-7kEBKwU9R8fKnZJBRa5RSIfay4KJwnYvKB6gODGicUmDSAhQJ7Tdnll5S0RLtYrzRfMVXlqYw61rzrSpP4ThLQ==
|
||||||
|
|
||||||
react-is@^16.8.1:
|
|
||||||
version "16.8.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.3.tgz#4ad8b029c2a718fc0cfc746c8d4e1b7221e5387d"
|
|
||||||
integrity sha512-Y4rC1ZJmsxxkkPuMLwvKvlL1Zfpbcu+Bf4ZigkHup3v9EfdYhAlWAaVyA19olXq2o2mGn0w+dFKvk3pVVlYcIA==
|
|
||||||
|
|
||||||
react-scripts@2.1.3:
|
react-scripts@2.1.3:
|
||||||
version "2.1.3"
|
version "2.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-2.1.3.tgz#6e49be279f4039fb9f330d2b3529b933b8e90945"
|
resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-2.1.3.tgz#6e49be279f4039fb9f330d2b3529b933b8e90945"
|
||||||
@ -9539,13 +9504,6 @@ to-arraybuffer@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
|
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
|
||||||
integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
|
integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
|
||||||
|
|
||||||
to-camel-case@1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/to-camel-case/-/to-camel-case-1.0.0.tgz#1a56054b2f9d696298ce66a60897322b6f423e46"
|
|
||||||
integrity sha1-GlYFSy+daWKYzmamCJcyK29CPkY=
|
|
||||||
dependencies:
|
|
||||||
to-space-case "^1.0.0"
|
|
||||||
|
|
||||||
to-fast-properties@^1.0.3:
|
to-fast-properties@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
|
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
|
||||||
@ -9556,11 +9514,6 @@ to-fast-properties@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||||
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
|
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
|
||||||
|
|
||||||
to-no-case@^1.0.0:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a"
|
|
||||||
integrity sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo=
|
|
||||||
|
|
||||||
to-object-path@^0.3.0:
|
to-object-path@^0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
|
resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
|
||||||
@ -9586,13 +9539,6 @@ to-regex@^3.0.1, to-regex@^3.0.2:
|
|||||||
regex-not "^1.0.2"
|
regex-not "^1.0.2"
|
||||||
safe-regex "^1.1.0"
|
safe-regex "^1.1.0"
|
||||||
|
|
||||||
to-space-case@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17"
|
|
||||||
integrity sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc=
|
|
||||||
dependencies:
|
|
||||||
to-no-case "^1.0.0"
|
|
||||||
|
|
||||||
topo@2.x.x:
|
topo@2.x.x:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/topo/-/topo-2.0.2.tgz#cd5615752539057c0dc0491a621c3bc6fbe1d182"
|
resolved "https://registry.yarnpkg.com/topo/-/topo-2.0.2.tgz#cd5615752539057c0dc0491a621c3bc6fbe1d182"
|
||||||
@ -10045,6 +9991,13 @@ webpack-manifest-plugin@2.0.4:
|
|||||||
lodash ">=3.5 <5"
|
lodash ">=3.5 <5"
|
||||||
tapable "^1.0.0"
|
tapable "^1.0.0"
|
||||||
|
|
||||||
|
webpack-merge@4.1.4:
|
||||||
|
version "4.1.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.4.tgz#0fde38eabf2d5fd85251c24a5a8c48f8a3f4eb7b"
|
||||||
|
integrity sha512-TmSe1HZKeOPey3oy1Ov2iS3guIZjWvMT2BBJDzzT5jScHTjVC3mpjJofgueEzaEd6ibhxRDD6MIblDr8tzh8iQ==
|
||||||
|
dependencies:
|
||||||
|
lodash "^4.17.5"
|
||||||
|
|
||||||
webpack-sources@^1.1.0, webpack-sources@^1.2.0:
|
webpack-sources@^1.1.0, webpack-sources@^1.2.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85"
|
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85"
|
||||||
@ -10294,6 +10247,13 @@ worker-farm@^1.5.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
errno "~0.1.7"
|
errno "~0.1.7"
|
||||||
|
|
||||||
|
workerize-loader@^1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/workerize-loader/-/workerize-loader-1.0.4.tgz#5e7d1b7775e842399be50a761e0c4dd902ff42f1"
|
||||||
|
integrity sha512-HMTr/zpuZhm8dbhcK52cMYmn57uf7IJeMZJil+5lL/vC5+AO9wzxZ0FISkGVj78No7HcpaINwAWHGCYx3dnsTw==
|
||||||
|
dependencies:
|
||||||
|
loader-utils "^1.1.0"
|
||||||
|
|
||||||
wrap-ansi@^2.0.0:
|
wrap-ansi@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
|
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
|
||||||
|
Loading…
Reference in New Issue
Block a user