おwipですわ
This commit is contained in:
parent
b9575d2c5b
commit
8adeb4fe5b
14 changed files with 245 additions and 30 deletions
|
@ -24,6 +24,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@reduxjs/toolkit": "^1.6.1",
|
||||
"@types/koa-bodyparser": "^4.3.0",
|
||||
"@types/koa-multer": "^1.0.0",
|
||||
"@types/koa-send": "^4.1.3",
|
||||
|
@ -58,6 +59,7 @@
|
|||
"pug": "^3.0.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-redux": "^7.2.4",
|
||||
"react-router-dom": "^5.2.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rndstr": "^1.0.0",
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
import { CurrentUser, Get, JsonController } from 'routing-controllers';
|
||||
import { getScores } from '../functions/get-scores';
|
||||
import { User } from '../models/entities/user';
|
||||
|
||||
@JsonController('/session')
|
||||
|
@ -11,4 +12,9 @@ export class SessionController {
|
|||
@Get() get(@CurrentUser({ required: true }) user: User) {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Get('/score')
|
||||
async getScore(@CurrentUser({ required: true }) user: User) {
|
||||
return getScores(user);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { Entity, Column, PrimaryGeneratedColumn, Index } from 'typeorm';
|
||||
import { AlertMode, alertModes } from '../../../common/types/alert-mode';
|
||||
import { visibilities, Visibility } from '../../../common/types/visibility';
|
||||
import { IUser } from '../../../common/types/user';
|
||||
|
||||
@Entity()
|
||||
@Index(['username', 'host'], { unique: true })
|
||||
export class User {
|
||||
export class User implements IUser {
|
||||
@PrimaryGeneratedColumn()
|
||||
public id: number;
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
|
||||
export type Score = {
|
||||
export interface Score {
|
||||
notesCount: number;
|
||||
followingCount: number;
|
||||
followersCount: number;
|
||||
notesDelta: string;
|
||||
followingDelta: string;
|
||||
followersDelta: string;
|
||||
};
|
||||
}
|
||||
|
|
22
src/common/types/user.ts
Normal file
22
src/common/types/user.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { AlertMode } from './alert-mode';
|
||||
import { Visibility } from './visibility';
|
||||
|
||||
export interface IUser {
|
||||
id: number;
|
||||
username: string;
|
||||
host: string;
|
||||
token: string;
|
||||
misshaiToken: string;
|
||||
prevNotesCount: number;
|
||||
prevFollowingCount: number;
|
||||
prevFollowersCount: number;
|
||||
alertMode: AlertMode;
|
||||
visibility: Visibility;
|
||||
localOnly: boolean;
|
||||
remoteFollowersOnly: boolean;
|
||||
template: string | null;
|
||||
prevRating: number;
|
||||
rating: number;
|
||||
bannedFromRanking: boolean;
|
||||
}
|
||||
|
|
@ -1,16 +1,19 @@
|
|||
import * as React from 'react';
|
||||
import { BrowserRouter, Link, Route, Switch, useLocation } from 'react-router-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { IndexPage } from './pages';
|
||||
import { RankingPage } from './pages/ranking';
|
||||
import { Header } from './components/Header';
|
||||
import { TermPage } from './pages/term';
|
||||
import { store } from './store';
|
||||
|
||||
import 'xeltica-ui/dist/css/xeltica-ui.min.css';
|
||||
import './style.scss';
|
||||
|
||||
const AppInner : React.VFC = () => {
|
||||
const $location = useLocation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="container">
|
||||
|
@ -30,7 +33,9 @@ const AppInner : React.VFC = () => {
|
|||
};
|
||||
|
||||
export const App: React.VFC = () => (
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<AppInner />
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
);
|
||||
|
|
44
src/frontend/components/SessionData.tsx
Normal file
44
src/frontend/components/SessionData.tsx
Normal file
|
@ -0,0 +1,44 @@
|
|||
import React from 'react';
|
||||
import { useGetScoreQuery } from '../services/session';
|
||||
|
||||
export const SessionData: React.VFC = () => {
|
||||
const { data: score, error, isLoading } = useGetScoreQuery(undefined);
|
||||
|
||||
return isLoading ? (
|
||||
<div>Loading...</div>
|
||||
) : score === undefined ? (
|
||||
<div>No score</div>
|
||||
) : (
|
||||
<>
|
||||
<section>
|
||||
<h2>みす廃データ</h2>
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>内容</th>
|
||||
<th>スコア</th>
|
||||
<th>前日比</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ノート</td>
|
||||
<td>{score.notesCount}</td>
|
||||
<td>{score.notesDelta}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>フォロー</td>
|
||||
<td>{score.followingCount}</td>
|
||||
<td>{score.followingDelta}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>フォロワー</td>
|
||||
<td>{score.followersCount}</td>
|
||||
<td>{score.followersDelta}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
export type TabItem = {
|
||||
label: string;
|
||||
|
@ -11,14 +11,14 @@ export type TabProps = {
|
|||
};
|
||||
|
||||
// タブコンポーネント
|
||||
export const Tab: React.FC<TabProps> = (props) => {
|
||||
export const Tab: React.VFC<TabProps> = (props) => {
|
||||
return (
|
||||
<div className="tab">
|
||||
{props.items.map((item, index) => {
|
||||
return (
|
||||
<button
|
||||
key={index}
|
||||
className={'item ' + (index === props.selected ? 'selected' : '')}
|
||||
className={'item ' + (index === props.selected ? 'active' : '')}
|
||||
onClick={() => props.onSelect(index)}
|
||||
>
|
||||
{item.label}
|
||||
|
|
1
src/frontend/const.tsx
Normal file
1
src/frontend/const.tsx
Normal file
|
@ -0,0 +1 @@
|
|||
export const apiEndpoint = `//${location.host}/api/v1/`;
|
|
@ -1,27 +1,42 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
|
||||
import { Header } from '../components/Header';
|
||||
import { SessionData } from '../components/SessionData';
|
||||
import { Tab, TabItem } from '../components/Tab';
|
||||
import { useGetSessionQuery } from '../services/session';
|
||||
|
||||
export const IndexSessionPage: React.VFC = () => {
|
||||
const token = localStorage['token'];
|
||||
const [session, setSession] = useState<Record<string, any> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`//${location.host}/api/v1/session`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
const { data: session, error, isLoading } = useGetSessionQuery(undefined);
|
||||
const [selectedTab, setSelectedTab] = useState<number>(0);
|
||||
const items = useMemo<TabItem[]>(() => ([
|
||||
{
|
||||
label: 'データ',
|
||||
},
|
||||
}).then(s => s.json())
|
||||
.then(setSession);
|
||||
}, []);
|
||||
{
|
||||
label: 'ランキング',
|
||||
},
|
||||
{
|
||||
label: '設定',
|
||||
},
|
||||
]), []);
|
||||
|
||||
return (
|
||||
return isLoading ? (
|
||||
<div>Loading...</div>
|
||||
) : error ? (
|
||||
<div>Error: {error}</div>
|
||||
) : (
|
||||
<>
|
||||
<Header>
|
||||
<article className="mt-4">
|
||||
おかえりなさい、{session?.username}さん。
|
||||
</article>
|
||||
</Header>
|
||||
<div className="xarticle card" style={{borderRadius: 'var(--radius)'}}>
|
||||
<Tab items={items} selected={selectedTab} onSelect={setSelectedTab}/>
|
||||
<article className="container">
|
||||
{selectedTab === 0 && <SessionData /> }
|
||||
</article>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
32
src/frontend/services/session.ts
Normal file
32
src/frontend/services/session.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
|
||||
import { apiEndpoint } from '../const';
|
||||
import { IUser } from '../../common/types/user';
|
||||
import { Score } from '../../common/types/score';
|
||||
|
||||
export const sessionApi = createApi({
|
||||
reducerPath: 'session',
|
||||
baseQuery: fetchBaseQuery({ baseUrl: apiEndpoint + 'session' }),
|
||||
endpoints: (builder) => ({
|
||||
getSession: builder.query<IUser, undefined>({
|
||||
query: () => ({
|
||||
url: '/',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${localStorage['token']}`,
|
||||
}
|
||||
})
|
||||
}),
|
||||
getScore: builder.query<Score, undefined>({
|
||||
query: () => ({
|
||||
url: '/score',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${localStorage['token']}`,
|
||||
}
|
||||
})
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export const {
|
||||
useGetSessionQuery,
|
||||
useGetScoreQuery,
|
||||
} = sessionApi;
|
21
src/frontend/store/index.ts
Normal file
21
src/frontend/store/index.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import { setupListeners } from '@reduxjs/toolkit/dist/query';
|
||||
import { useSelector as useSelectorBase, TypedUseSelectorHook } from 'react-redux';
|
||||
import { sessionApi } from '../services/session';
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
[sessionApi.reducerPath]: sessionApi.reducer,
|
||||
},
|
||||
|
||||
middleware: (defaultMiddleware) => defaultMiddleware()
|
||||
.concat(sessionApi.middleware),
|
||||
});
|
||||
|
||||
export type RootState = ReturnType<typeof store.getState>;
|
||||
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
|
||||
export const useSelector: TypedUseSelectorHook<RootState> = useSelectorBase;
|
||||
|
||||
setupListeners(store.dispatch);
|
|
@ -6,26 +6,38 @@ body {
|
|||
.xarticle {
|
||||
margin: auto;
|
||||
max-width: 720px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tab {
|
||||
display: flex;
|
||||
background: var(--panel);
|
||||
.item {
|
||||
position: relative;
|
||||
padding: var(--margin);
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--fg);
|
||||
padding: calc(var(--margin) / 2) var(--margin);
|
||||
&.active {
|
||||
color: var(--primary);
|
||||
transition: width 0.2s ease;
|
||||
&::after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background: var(--hover);
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
transition: width 0.2s ease;
|
||||
transform-origin: center center;
|
||||
display: block;
|
||||
bottom: 0;
|
||||
height: 2px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
width: 0;
|
||||
background-color: var(--primary);
|
||||
}
|
||||
|
|
64
yarn.lock
64
yarn.lock
|
@ -150,7 +150,7 @@
|
|||
"@babel/plugin-transform-react-jsx-development" "^7.14.5"
|
||||
"@babel/plugin-transform-react-pure-annotations" "^7.14.5"
|
||||
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13":
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.9.2":
|
||||
version "7.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a"
|
||||
integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==
|
||||
|
@ -282,6 +282,16 @@
|
|||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@reduxjs/toolkit@^1.6.1":
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.6.1.tgz#7bc83b47352a663bf28db01e79d17ba54b98ade9"
|
||||
integrity sha512-pa3nqclCJaZPAyBhruQtiRwtTjottRrVJqziVZcWzI73i6L3miLTtUyWfauwv08HWtiXLx1xGyGt+yLFfW/d0A==
|
||||
dependencies:
|
||||
immer "^9.0.1"
|
||||
redux "^4.1.0"
|
||||
redux-thunk "^2.3.0"
|
||||
reselect "^4.0.0"
|
||||
|
||||
"@sindresorhus/is@^0.14.0":
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
|
||||
|
@ -383,7 +393,7 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.9.tgz#1cfb6d60ef3822c589f18e70f8b12f9a28ce8724"
|
||||
integrity sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==
|
||||
|
||||
"@types/hoist-non-react-statics@*":
|
||||
"@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.0":
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
|
||||
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
|
||||
|
@ -534,6 +544,16 @@
|
|||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-redux@^7.1.16":
|
||||
version "7.1.18"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.18.tgz#2bf8fd56ebaae679a90ebffe48ff73717c438e04"
|
||||
integrity sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==
|
||||
dependencies:
|
||||
"@types/hoist-non-react-statics" "^3.3.0"
|
||||
"@types/react" "*"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
redux "^4.0.0"
|
||||
|
||||
"@types/react-router-dom@^5.1.8":
|
||||
version "5.1.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.1.8.tgz#bf3e1c8149b3d62eaa206d58599de82df0241192"
|
||||
|
@ -2486,7 +2506,7 @@ history@^4.9.0:
|
|||
tiny-warning "^1.0.0"
|
||||
value-equal "^1.0.1"
|
||||
|
||||
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0:
|
||||
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
|
@ -2598,6 +2618,11 @@ ignore@^5.1.4:
|
|||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
|
||||
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
|
||||
|
||||
immer@^9.0.1:
|
||||
version "9.0.6"
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.6.tgz#7a96bf2674d06c8143e327cbf73539388ddf1a73"
|
||||
integrity sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ==
|
||||
|
||||
import-fresh@^3.0.0, import-fresh@^3.2.1:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
|
||||
|
@ -4012,7 +4037,7 @@ promise@^7.0.1:
|
|||
dependencies:
|
||||
asap "~2.0.3"
|
||||
|
||||
prop-types@^15.6.2:
|
||||
prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||
|
@ -4245,11 +4270,23 @@ react-dom@^17.0.2:
|
|||
object-assign "^4.1.1"
|
||||
scheduler "^0.20.2"
|
||||
|
||||
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
|
||||
react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-redux@^7.2.4:
|
||||
version "7.2.4"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.4.tgz#1ebb474032b72d806de2e0519cd07761e222e225"
|
||||
integrity sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.1"
|
||||
"@types/react-redux" "^7.1.16"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.7.2"
|
||||
react-is "^16.13.1"
|
||||
|
||||
react-router-dom@^5.2.1:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.0.tgz#da1bfb535a0e89a712a93b97dd76f47ad1f32363"
|
||||
|
@ -4357,6 +4394,18 @@ reconnecting-websocket@^4.4.0:
|
|||
resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783"
|
||||
integrity sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==
|
||||
|
||||
redux-thunk@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
|
||||
integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
|
||||
|
||||
redux@^4.0.0, redux@^4.1.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.1.tgz#76f1c439bb42043f985fbd9bf21990e60bd67f47"
|
||||
integrity sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.9.2"
|
||||
|
||||
reflect-metadata@^0.1.13:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
|
||||
|
@ -4406,6 +4455,11 @@ require-main-filename@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
|
||||
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
|
||||
|
||||
reselect@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
|
||||
integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
|
||||
|
||||
resolve-cwd@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue