less hacking way of pulling poe data

This commit is contained in:
2018-08-27 23:54:27 -05:00
parent 5423b81c95
commit 97acc0d4fa
34 changed files with 651 additions and 221 deletions

View File

@@ -1,6 +1,16 @@
import { Provider } from 'mobx-react';
import React from 'react';
import ReactDOM from 'react-dom';
import { Home } from './components';
import './scss/index.scss';
import { RootStore } from './stores/root.store';
import { Wrapper } from './wrapper';
ReactDOM.render(<Home />, document.getElementById('app'));
const rootStore = new RootStore();
const app = (
<Provider {...rootStore}>
<Wrapper />
</Provider>
);
ReactDOM.render(app, document.getElementById('app'));

View File

@@ -1,109 +0,0 @@
import { WebviewTag } from 'electron';
import * as _ from 'lodash';
import React from 'react';
import { ItemTextService } from '../services';
import { PoeService } from '../services/poe.service';
import { LoginWebview } from './login-webview';
import { PriceListItem } from './price-list-item/price-list-item';
interface IState {
showLogin: boolean;
data: any;
}
export class Home extends React.Component<any, IState> {
private webview: WebviewTag;
constructor(props: any) {
super(props);
this.state = {
showLogin: false,
data: [],
};
}
componentDidMount() {
this.addWebviewListeners();
}
public addWebviewListeners() {
this.webview = this.refs['webview'] as any;
this.webview.addEventListener('dom-ready', () => {
// this.webview.openDevTools();
});
this.webview.addEventListener('ipc-message', e => {
if (e.channel === 'html-content') {
const htmlContents = e.args[0];
this.handleResponse(htmlContents);
}
});
}
public handleResponse(res: any) {
const json = JSON.parse(res);
if (json === null || json['error']) {
this.setState({ showLogin: true });
} else if (json.items) {
const items = _.map(json.items, item => {
item.fullText = ItemTextService.parseItem(item);
return item;
});
this.setState({ showLogin: false, data: items });
this.getItemPrice(items, 0);
}
}
onLogin = () => {
this.setState({ showLogin: false });
this.webview.reload();
};
async getItemPrice(data: any[], index: number) {
if (!data[index] || data !== this.state.data) {
return;
}
console.log(data[index]);
console.log(data[index].fullText + '\n\n\n');
const res = await PoeService.priceCheck(data[index].fullText);
if ((res.min && res.currency) || (res.currency_rec && res.min_price)) {
const dataCopy: any = [...data];
dataCopy[index].priceInfo = res;
await new Promise(resolve => this.setState({ data: dataCopy }, resolve));
}
setTimeout(() => {
this.getItemPrice(this.state.data, index + 1);
}, 1000);
}
renderPriceList = (data: any[]) => {
return data.map((item, index) => <PriceListItem data={item} key={index} />);
};
public render() {
const { data, showLogin } = this.state;
const url =
'https://www.pathofexile.com/character-window/get-stash-items' +
'?league=Incursion&tabs=1&tabIndex=0&accountName=DoctorCoctor';
return (
<div style={{ padding: '20px' }}>
{showLogin && <LoginWebview onSuccess={this.onLogin} />}
{data && this.renderPriceList(data)}
{/* {data && <StashTab data={data} />} */}
<webview
ref="webview"
partition="persist:poe"
preload="ipc-renderer.js"
src={url}
style={{ opacity: 0, width: '0', height: '0' }}
/>
</div>
);
}
}

View File

View File

@@ -0,0 +1,34 @@
import { inject, observer } from 'mobx-react';
import React from 'react';
import { AppStore } from '../../stores/app.store';
import { Navbar } from '../navbar/navbar';
import { PriceListItem } from '../price-list-item/price-list-item';
import './home.scss';
interface IProps {
appStore?: AppStore;
}
interface IState {}
@inject('appStore')
@observer
export class Home extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {};
}
render() {
return (
<div>
<Navbar />
<div style={{ padding: '10px' }}>
{this.props.appStore!.stashItems.map((v, k) => {
return <PriceListItem key={k} data={v} />;
})}
</div>
</div>
);
}
}

View File

@@ -1,5 +1,6 @@
export * from './home';
export * from './login-webview';
export * from './price-list';
export * from './home/home';
export * from './login-webview/login-webview';
export * from './navbar/navbar';
export * from './price-list-item/price-list-item';
export * from './stash-tab';
export * from './price-list/price-list';
export * from './stash-tab/stash-tab';

View File

@@ -1,37 +0,0 @@
import { WebviewTag } from 'electron';
import React from 'react';
interface IProps {
onSuccess: () => void;
}
export class LoginWebview extends React.Component<IProps, any> {
private webview: WebviewTag;
constructor(props: IProps) {
super(props);
}
componentDidMount() {
this.webview = this.refs['webview'] as any;
this.webview.addEventListener('did-stop-loading', this.didStopLoading);
}
didStopLoading = (event: any) => {
if ((event.target.src as string).includes('my-account')) {
this.props.onSuccess();
}
};
render() {
return (
<webview
ref="webview"
partition="persist:poe"
src="https://www.pathofexile.com/login"
style={{ height: '500px', width: '100%' }}
/>
);
}
}

View File

@@ -0,0 +1,53 @@
import { WebviewTag } from 'electron';
import * as _ from 'lodash';
import { inject, observer } from 'mobx-react';
import React from 'react';
import { POE_HOME } from '../../constants';
import { AppStore } from '../../stores/app.store';
interface IProps {
appStore?: AppStore;
}
@inject('appStore')
@observer
export class LoginWebview extends React.Component<IProps, any> {
private webview: WebviewTag;
constructor(props: IProps) {
super(props);
}
componentDidMount() {
this.webview = this.refs['webview'] as any;
this.webview.addEventListener('did-stop-loading', this.didStopLoading);
}
// if webview redirect to my-account - means user logged in
didStopLoading = (event: any) => {
if ((event.target.src as string).includes('my-account')) {
this.getCookies();
}
};
// get cookies from login and store username/sessionID
getCookies() {
const session = this.webview.getWebContents().session;
session.cookies.get({ url: POE_HOME }, async (error, cookies) => {
if (error) {
console.error(error);
return;
}
try {
const cookie: any = _.find(cookies, c => c.name === 'POESESSID');
this.props.appStore!.performLogin(cookie.value);
} catch (e) {
this.props.appStore!.resetState();
}
});
}
render() {
return <webview ref="webview" src={`${POE_HOME}/login`} style={{ height: '100%', width: '100%' }} />;
}
}

View File

@@ -0,0 +1,10 @@
@import '../../scss/variables.scss';
.navbar {
background: $dark2;
border-bottom: 1px solid $dark1;
height: 50px;
display: flex;
align-items: center;
padding: 0 20px;
}

View File

@@ -0,0 +1,68 @@
import { inject, observer } from 'mobx-react';
import React from 'react';
import { AppStore } from '../../stores/app.store';
import './navbar.scss';
interface IProps {
appStore?: AppStore;
}
@inject('appStore')
@observer
export class Navbar extends React.Component<IProps, any> {
constructor(props: IProps) {
super(props);
}
onLeagueSelect = (event: any) => {
this.props.appStore!.setActiveLeague(event.target.value);
};
onStashSelect = (event: any) => {
this.props.appStore!.loadItems(event.target.value);
};
renderStashTabSelector() {
const { stashTabs } = this.props.appStore!;
if (stashTabs.length < 1) {
return null;
}
return (
<select defaultValue={stashTabs[0].n} onChange={this.onStashSelect}>
{stashTabs.map((v, k) => (
<option key={k} value={k}>
{v.n}
</option>
))}
</select>
);
}
renderLeagueSelector() {
const { activeLeague, leagues } = this.props.appStore!;
if (!leagues || !activeLeague) {
return null;
}
return (
<select onChange={this.onLeagueSelect} defaultValue={activeLeague.id}>
{leagues!.map((l, k) => {
return (
<option key={k} value={l.id}>
{l.id}
</option>
);
})}
</select>
);
}
render() {
return (
<div className="navbar">
{this.renderLeagueSelector()}
{this.renderStashTabSelector()}
</div>
);
}
}

View File

@@ -1,23 +1,22 @@
@import '~open-color/open-color.scss';
@import '../../scss/variables.scss';
.pli {
padding: 20px;
padding: 10px;
border-radius: 4px;
background: $oc-gray-3;
border-color: $oc-gray-5;
background: $dark3;
border: 1px solid $dark1;
display: flex;
flex-direction: row;
width: 300px;
word-break: break-word;
& + & {
margin-top: 20px;
margin-top: 10px;
}
&__img {
max-width: 100px;
max-width: 50px;
max-height: 50px;
padding-right: 20px;
cursor: pointer;
padding-right: 10px;
}
}

View File

@@ -1,8 +1,12 @@
import React from 'react';
import { FrameType } from '../../model/frame-type';
import { IItem } from '../../model/item';
import { RarityColor } from '../../model/rarity-color';
import { ItemTextService } from '../../services';
import './price-list-item.scss';
interface IProps {
data: any;
data: IItem;
}
interface IState {
@@ -18,16 +22,23 @@ export class PriceListItem extends React.Component<IProps, IState> {
componentDidMount() {}
render() {
const { fullText, icon, priceInfo, typeLine } = this.props.data;
const { icon, priceInfo, stackSize, typeLine, frameType } = this.props.data;
const name = ItemTextService.filterName(typeLine);
const fullText = ItemTextService.parseItem(this.props.data);
const rarityColor = RarityColor[(FrameType[frameType] || '').toLowerCase()];
return (
<div className="pli" title={fullText}>
<div style={{ width: '100px' }}>
<img src={icon} className="pli__img" />
<div className="pli" onClick={() => console.log(this.props.data)}>
<div style={{ width: '60px' }}>
<img title={fullText} src={icon} className="pli__img" />
</div>
<div style={{ flex: 1 }}>
<div style={{ flex: 1 }} className="ellipsis">
<div style={{ marginBottom: '10px' }}>
<b>{typeLine}</b>
<div className="ellipsis" title={name} style={{ color: rarityColor }}>
{name}
</div>
<div className="text-secondary">{stackSize && <small>Stack Size: {stackSize}</small>}</div>
</div>
<div>
{priceInfo ? `${priceInfo.min || priceInfo.min_price} ${priceInfo.currency || priceInfo.currency_rec}` : ''}

View File

@@ -1,25 +0,0 @@
import React from 'react';
import { PriceListItem } from './price-list-item/price-list-item';
interface IProps {
data: any[];
}
export class PriceList extends React.Component<IProps, any> {
constructor(props: IProps) {
super(props);
}
// componentDidMount() {
// console.log(this.props.data);
// }
// componentWillReceiveProps(nextProps: IProps) {
// if (this.props !== nextProps) {
// // do stuff
// console.log(nextProps);
// }
// }
render = () => this.props.data.map((value, index) => <PriceListItem data={value} key={index} />);
}

View File

@@ -0,0 +1,14 @@
import React from 'react';
import { PriceListItem } from '../price-list-item/price-list-item';
interface IProps {
data: any[];
}
export class PriceList extends React.Component<IProps, any> {
constructor(props: IProps) {
super(props);
}
render = () => this.props.data.map((value, index) => <PriceListItem data={value} key={index} />);
}

View File

@@ -1,5 +1,4 @@
import React from 'react';
import { PoeService } from '../services/poe.service';
import './stash-tab.scss';
interface IProps {
@@ -7,13 +6,6 @@ interface IProps {
}
export class StashTab extends React.Component<IProps, any> {
componentDidMount() {
console.log(this.props.data);
PoeService.priceCheck(`Superior Laboratory Map`).then(res => {
console.log(res);
});
}
render() {
return <div style={{ height: '577px', width: '577px' }} className="quad-tab" />;
}

7
app/constants.ts Normal file
View File

@@ -0,0 +1,7 @@
export const POE_HOME = 'https://www.pathofexile.com';
export const POE_LOGIN_URL = `${POE_HOME}/login`;
export const POE_LOGIN_STEAM_URL = `${POE_LOGIN_URL}/steam`;
export const POE_MY_ACCOUNT_URL = `${POE_HOME}/my-account`;
export const POE_GET_CHARACTERS_URL = `${POE_HOME}/character-window/get-characters`;
export const POE_STASH_ITEMS_URL = `${POE_HOME}/character-window/get-stash-items`;
export const POE_LEAGUE_LIST_URL = 'http://api.pathofexile.com/leagues?type=main&compact=1';

View File

@@ -1,3 +1,7 @@
import axios from 'axios';
export const http = axios.create();
export const setHeader = (header: string, value: string) => {
http.defaults.headers[header] = value;
};

1
app/model/index.ts Normal file
View File

@@ -0,0 +1 @@
export * from './league';

21
app/model/item.ts Normal file
View File

@@ -0,0 +1,21 @@
export interface IItem {
category: any[];
descrText: string;
explicitMods: string[];
frameType: number;
h: number;
icon: string;
id: string;
identified: boolean;
ilvl: number;
inventoryId: string;
league: string;
name: string;
properties: any[];
stackSize?: number;
typeLine: string;
verified: boolean;
w: number;
x: number;
y: number;
}

6
app/model/league.ts Normal file
View File

@@ -0,0 +1,6 @@
export interface ILeague {
endAt?: string;
id: string;
startAt: string;
url: string;
}

View File

@@ -0,0 +1,6 @@
export const RarityColor: any = {
unique: '#af6025',
rare: '#a3a314',
magic: 'rgb(117, 117, 255)',
normal: '#eee',
};

18
app/model/stash-tab.ts Normal file
View File

@@ -0,0 +1,18 @@
interface IStashTabColor {
r: number;
g: number;
b: number;
}
export interface IStashTab {
colour: IStashTabColor;
hidden: boolean;
i: number;
id: string;
n: string;
selected: boolean;
srcC: string;
srcL: string;
srcR: string;
type: string;
}

View File

@@ -1,3 +1,27 @@
@import './variables.scss';
html {
font-family: 'Roboto Condensed', sans-serif;
}
html,
body,
#app {
height: 100%;
background: $dark4;
color: $textPrimary;
}
.text-secondary {
color: $textSecondary;
}
small {
font-size: 75%;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

10
app/scss/variables.scss Normal file
View File

@@ -0,0 +1,10 @@
@import '~open-color/open-color.scss';
$dark1: lighten(#0e0e0e, 20%);
$dark2: lighten(#0e0e0e, 15%);
$dark3: lighten(#0e0e0e, 10%);
$dark4: lighten(#0e0e0e, 5%);
$dark5: #0e0e0e;
$textPrimary: $oc-gray-3;
$textSecondary: $oc-gray-5;

View File

@@ -63,14 +63,16 @@ const getSockets = (sockets: any[]): string => {
return content.trim() + '\n';
};
/** filter unwanted characters from item name */
const filterName = (name: string): string => {
const index = name.lastIndexOf('&gt;');
const newString = name.replace(/&gt;/g, '>');
const index = newString.lastIndexOf('>');
if (index < 0) {
return name;
}
return name
.slice(index + 4, name.length)
.slice(index + 1, name.length)
.replace('{', '')
.replace('}', '');
};
@@ -103,5 +105,6 @@ const getProperties = (p?: any[], precedingText?: string): string => {
};
export const ItemTextService = {
filterName,
parseItem,
};

View File

@@ -1,20 +1,44 @@
import PQueue from 'p-queue';
import { POE_HOME, POE_LEAGUE_LIST_URL, POE_STASH_ITEMS_URL } from '../constants';
import { http } from '../http';
export class PoeService {
public static async getStash(): Promise<any> {
const res = await http.get(
'https://pathofexile.com/character-window/get-stash-items?' +
'league=Incursion&tabs=1&tabIndex=6&accountName=DoctorCoctor',
);
return res.data;
}
const queue = new PQueue({ concurrency: 1 });
public static async priceCheck(item: any) {
const res = await http.get(`https://poeprices.info/api?l=Incursion&i=${encodeURI(btoa(item))}`, {
headers: {
'Cache-Control': 'max-age=600',
},
const getStash = async (username: string, league: string, tabIndex: number | string): Promise<any> => {
const res = await http.get(
`${POE_STASH_ITEMS_URL}?league=${league}&tabs=1&tabIndex=${tabIndex}&accountName=${username}`,
);
return res.data;
};
const priceCheck = async (item: any): Promise<any> => {
return new Promise(resolve => {
queue.add(() => {
return http
.get(`https://poeprices.info/api?l=Incursion&i=${encodeURI(btoa(item))}`, {
headers: {
'Cache-Control': 'max-age=600',
},
})
.then(resolve);
});
return res.data;
}
}
});
};
const getUsername = async (): Promise<any> => {
const res = await http.get(POE_HOME);
const username = res.data.match(/\/account\/view-profile\/(.*?)\"/);
return username[1];
};
const getLeagues = async (): Promise<any> => {
const res = await http.get(POE_LEAGUE_LIST_URL);
return res.data;
};
export const PoeService = {
getLeagues,
getStash,
getUsername,
priceCheck,
};

View File

@@ -0,0 +1,25 @@
import Store from 'electron-store';
const store = new Store();
const storeUsername = (username: string) => {
store.set('user', username);
};
const storeSessionID = (sessionID: string) => {
store.set('sessionID', sessionID);
};
const getSessionID = (): string | undefined => {
return store.get('sessionID') || undefined;
};
const getUsername = (): string | undefined => {
return store.get('user') || undefined;
};
export const StorageService = {
getUsername,
getSessionID,
storeUsername,
storeSessionID,
};

114
app/stores/app.store.ts Normal file
View File

@@ -0,0 +1,114 @@
import Store from 'electron-store';
import { action, computed, observable } from 'mobx';
import { setHeader } from '../http';
import { ILeague } from '../model';
import { IItem } from '../model/item';
import { IStashTab } from '../model/stash-tab';
import { PoeService } from '../services';
import { StorageService } from '../services/storage.service';
const store = new Store();
export class AppStore {
@observable
public username?: string;
@observable
public sessionID?: string;
@observable
public activeLeague: ILeague;
@observable
public selectedTabIndex: number = 0;
@observable
public stashTabs: IStashTab[] = [];
@observable
public stashItems: IItem[] = [];
@observable
public leagues: ILeague[] = [];
@observable
public appReady: boolean;
constructor() {
this.bootstrap();
}
private async bootstrap() {
try {
this.username = StorageService.getUsername();
this.sessionID = StorageService.getSessionID();
if (this.sessionID) {
await this.loadLeagues();
}
} catch (e) {
console.error(e);
}
this.appReady = true;
}
@action
private async loadLeagues() {
try {
const leagues = await PoeService.getLeagues();
if (!leagues) {
return;
}
this.leagues = leagues;
// set active league if not set
if (!this.activeLeague && this.leagues!.length > 0) {
this.setActiveLeague(this.leagues[0].id);
}
} catch (e) {
console.error(e);
}
}
@computed
public get isLoggedIn() {
return this.username && this.sessionID;
}
@action
public resetState() {
delete this.username;
delete this.sessionID;
setHeader('Cookie', '');
store.clear();
}
@action
public setSessionID(sessionID: string) {
setHeader('Cookie', `POESESSID=${sessionID}`);
this.sessionID = sessionID;
StorageService.storeSessionID(sessionID);
}
@action
public setUsername(username: string) {
this.username = username;
StorageService.storeUsername(username);
}
@action
public setActiveLeague(id: string) {
const league = this.leagues.find(l => l.id === id);
if (league) {
this.activeLeague = league;
this.stashTabs = [];
this.selectedTabIndex = 0;
this.stashItems = [];
this.loadItems(this.selectedTabIndex);
}
}
@action
public async performLogin(sessionID: string) {
this.setSessionID(sessionID);
const username = await PoeService.getUsername();
this.setUsername(username);
}
@action
public async loadItems(tabIndex: number | string) {
const data = await PoeService.getStash(this.username!, this.activeLeague.id, tabIndex);
this.stashTabs = data.tabs;
this.stashItems = data.items;
}
}

5
app/stores/root.store.ts Normal file
View File

@@ -0,0 +1,5 @@
import { AppStore } from './app.store';
export class RootStore {
public appStore = new AppStore();
}

32
app/wrapper.tsx Normal file
View File

@@ -0,0 +1,32 @@
import { inject, observer } from 'mobx-react';
import React from 'react';
import { Home, LoginWebview } from './components';
import { AppStore } from './stores/app.store';
interface IProps {
appStore?: AppStore;
}
interface IState {}
@inject('appStore')
@observer
export class Wrapper extends React.Component<IProps, IState> {
constructor(props: any) {
super(props);
}
public render() {
const { appStore } = this.props;
if (!appStore!.appReady) {
return null;
}
if (!appStore!.isLoggedIn) {
return <LoginWebview />;
}
return <Home />;
}
}

View File

@@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<title></title>
</head>

106
package-lock.json generated
View File

@@ -84,6 +84,14 @@
"vue-template-es2015-compiler": "1.6.0"
}
},
"@types/electron-store": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@types/electron-store/-/electron-store-1.3.0.tgz",
"integrity": "sha512-PplQbntPl3xNcckjizjoQShPwLot72jFiaI67CZ0JOr+AuGwqXdL73sU3vfuuP+RZecOh8vX1G7yWjmxs4lvBQ==",
"requires": {
"@types/node": "7.0.69"
}
},
"@types/lodash": {
"version": "4.14.116",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.116.tgz",
@@ -94,6 +102,11 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.69.tgz",
"integrity": "sha512-S5NC8HV6HnRipg8nC0j30TPl7ktXjRTKqgyINLNe8K/64UJUI8Lq0sRopXC0hProsV2F5ibj8IqPkl1xpGggrw=="
},
"@types/p-queue": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@types/p-queue/-/p-queue-2.3.1.tgz",
"integrity": "sha512-JyO7uMAtkcMMULmsTQ4t/lCC8nxirTtweGG1xAFNNIAoC1RemmeIxq8PiKghuEy99XdbS6Lwx4zpbXUjfeSSAA=="
},
"@types/prop-types": {
"version": "15.5.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz",
@@ -2621,6 +2634,18 @@
}
}
},
"conf": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/conf/-/conf-2.0.0.tgz",
"integrity": "sha512-iCLzBsGFi8S73EANsEJZz0JnJ/e5VZef/kSaxydYZLAvw0rFNAUx5R7K5leC/CXXR2mZfXWhUvcZOO/dM2D5xg==",
"requires": {
"dot-prop": "4.2.0",
"env-paths": "1.0.0",
"make-dir": "1.3.0",
"pkg-up": "2.0.0",
"write-file-atomic": "2.3.0"
}
},
"console-browserify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
@@ -3523,6 +3548,14 @@
"domelementtype": "1.3.0"
}
},
"dot-prop": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
"integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==",
"requires": {
"is-obj": "1.0.1"
}
},
"ds-store": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/ds-store/-/ds-store-0.1.6.tgz",
@@ -4727,6 +4760,14 @@
"debug": "2.6.9"
}
},
"electron-store": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/electron-store/-/electron-store-2.0.0.tgz",
"integrity": "sha512-1WCFYHsYvZBqDsoaS0Relnz0rd81ZkBAI0Fgx7Nq2UWU77rSNs1qxm4S6uH7TCZ0bV3LQpJFk7id/is/ZgoOPA==",
"requires": {
"conf": "2.0.0"
}
},
"electron-to-chromium": {
"version": "1.3.58",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.58.tgz",
@@ -5055,8 +5096,7 @@
"env-paths": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz",
"integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=",
"dev": true
"integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA="
},
"errno": {
"version": "0.1.7",
@@ -6735,6 +6775,11 @@
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
"dev": true
},
"hoist-non-react-statics": {
"version": "2.5.5",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
},
"home-or-tmp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
@@ -7350,6 +7395,11 @@
"kind-of": "3.2.2"
}
},
"is-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
},
"is-plain-obj": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
@@ -8611,6 +8661,20 @@
}
}
},
"mobx": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/mobx/-/mobx-5.1.0.tgz",
"integrity": "sha512-cQzBmF2gbpcBR2xKwt5jZx0ncDMC9Hg5nYrp3Krv0qHH4GFqWZyR+ZLkRJRcvVF4rqxpy2G96Qbk5YzyQ8tdXw=="
},
"mobx-react": {
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-5.2.5.tgz",
"integrity": "sha512-vSwsjGwmaqTmaEsPWET/APccjirTiIIchQA3YVasKzaxIGv62BNJUHFjrkIAbGBLeqJma+ZgSu158OqQLK0vaQ==",
"requires": {
"hoist-non-react-statics": "2.5.5",
"react-lifecycles-compat": "3.0.4"
}
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -9326,6 +9390,11 @@
"p-limit": "1.3.0"
}
},
"p-queue": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-2.4.2.tgz",
"integrity": "sha512-n8/y+yDJwBjoLQe1GSJbbaYQLTI7QHNZI2+rpmCDbe++WLf9HC3gf6iqj5yfPAV71W4UF3ql5W1+UBPXoXTxng=="
},
"p-try": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
@@ -9536,6 +9605,24 @@
}
}
},
"pkg-up": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
"integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
"requires": {
"find-up": "2.1.0"
},
"dependencies": {
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
"requires": {
"locate-path": "2.0.0"
}
}
}
},
"plist": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/plist/-/plist-2.1.0.tgz",
@@ -10494,6 +10581,11 @@
"prop-types": "15.6.2"
}
},
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
@@ -13504,6 +13596,16 @@
"dev": true,
"optional": true
},
"write-file-atomic": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz",
"integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==",
"requires": {
"graceful-fs": "4.1.11",
"imurmurhash": "0.1.4",
"signal-exit": "3.0.2"
}
},
"xml-name-validator": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",

View File

@@ -47,7 +47,9 @@
}
},
"dependencies": {
"@types/electron-store": "^1.3.0",
"@types/lodash": "^4.14.116",
"@types/p-queue": "^2.3.1",
"@types/react": "^16.4.9",
"@types/react-dom": "^16.0.7",
"autoprefixer": "^9.1.1",
@@ -61,13 +63,17 @@
"electron": "^2.0.7",
"electron-compile": "^6.4.3",
"electron-squirrel-startup": "^1.0.0",
"electron-store": "^2.0.0",
"file-loader": "^1.1.11",
"font-awesome": "^4.7.0",
"html-webpack-plugin": "^3.2.0",
"lodash": "^4.17.10",
"mobx": "^5.1.0",
"mobx-react": "^5.2.5",
"node-sass": "^4.9.3",
"normalize.css": "^8.0.0",
"open-color": "^1.6.3",
"p-queue": "^2.4.2",
"postcss-loader": "^3.0.0",
"react": "^16.4.2",
"react-dom": "^16.4.2",

View File

@@ -3,7 +3,7 @@
"rules": {
"semicolon": [true, "always", "ignore-bound-class-methods"],
"max-line-length": [true, 120],
"variable-name": [true, "ban-keywords", "check-format", "allow-pascal-case"],
"variable-name": [false, "ban-keywords", "check-format", "allow-pascal-case"],
"import-name": false,
"ter-arrow-parens": [true, "as-needed"],
"align": [true, "parameters", "statements"]