working-ish

This commit is contained in:
Marks Polakovs 2019-11-26 10:01:26 +00:00
parent 8952f9da4a
commit 9b60cd178f
13 changed files with 1127 additions and 46 deletions

2
.gitignore vendored
View file

@ -21,3 +21,5 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.env.local

View file

@ -3,13 +3,26 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.0.4",
"@types/jest": "24.0.22",
"@types/lodash": "^4.14.149",
"@types/node": "12.12.7",
"@types/qs": "^6.9.0",
"@types/react": "16.9.11",
"@types/react-beautiful-dnd": "^11.0.3",
"@types/react-dom": "16.9.4",
"react": "^16.11.0",
"react-dom": "^16.11.0",
"@types/react-redux": "^7.1.5",
"@types/webpack-env": "^1.14.1",
"lodash": "^4.17.15",
"qs": "^6.9.1",
"react": "^0.0.0-experimental-38dd17ab9",
"react-beautiful-dnd": "^12.1.1",
"react-dnd": "^9.4.0",
"react-dnd-html5-backend": "^9.4.0",
"react-dom": "^0.0.0-experimental-38dd17ab9",
"react-redux": "^7.1.3",
"react-scripts": "3.2.0",
"redux": "^4.0.4",
"typescript": "3.7.2"
},
"scripts": {

View file

@ -20,3 +20,45 @@
.App-link {
color: #09d3ac;
}
.sp-container {
display: flex;
flex-direction: column;
height: 100%;
}
.sp {
flex: 1;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
.sp-col {
display: block;
flex: 1;
border: 1px solid black;
height: calc(100% - 60px);
overflow-y: scroll;
}
.sp-track {
display: block;
/* overflow-x: hidden; */
/* height: 1.6em; */
margin: 0.2em 0;
/* overflow: hidden; */
/* height: 1.3em; */
cursor: pointer;
}
.sp-track:hover {
background-color: #78acf1;
}
html, body, #root {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}

View file

@ -1,26 +1,44 @@
import React from 'react';
import logo from './logo.svg';
import './App.css';
import React, { useReducer, useState, Suspense } from "react";
import qs from "qs";
import "./App.css";
import Showplanner from "./showplanner";
const App: React.FC = () => {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
const forceReducer = (state: boolean) => !state;
function useForceUpdate() {
const [_, action] = useReducer(forceReducer, false);
return () => action(null);
}
const App: React.FC = () => {
const [inputVal, setInputVal] = useState("");
const force = useForceUpdate();
function cont() {
window.location.search = `?timeslot_id=${inputVal}`;
force();
}
const q = qs.parse(window.location.search, { ignoreQueryPrefix: true });
if ("timeslot_id" in q) {
return (
<Suspense fallback={<div>Loading...</div>}>
<Showplanner timeslotId={q.timeslot_id} />
</Suspense>
);
} else {
return (
<div>
<h1>Welcome to showplanner2</h1>
<input
type="text"
placeholder="enter a timeslot id"
value={inputVal}
onChange={e => setInputVal(e.target.value)}
/>
<button onClick={cont}>Continue</button>
</div>
);
}
};
export default App;

176
src/api.ts Normal file
View file

@ -0,0 +1,176 @@
import qs from "qs";
import { convertModelToFormData, urlEncode } from "./lib/utils";
const MYRADIO_BASE_URL =
process.env.REACT_APP_MYRADIO_BASE || "https://ury.org.uk/api/v2";
const MYRADIO_API_KEY = process.env.REACT_APP_MYRADIO_KEY!;
class ApiException extends Error {}
export async function myradioApiRequest(
endpoint: string,
method: "GET" | "POST" | "PUT",
params: any
): Promise<any> {
let req = null;
if (method === "GET") {
req = fetch(
MYRADIO_BASE_URL +
endpoint +
qs.stringify(
{
...params,
api_key: MYRADIO_API_KEY
},
{ addQueryPrefix: true }
)
);
} else {
const body = JSON.stringify(params);
console.log(body);
req = fetch(MYRADIO_BASE_URL + endpoint + "?api_key=" + MYRADIO_API_KEY, {
method,
body,
headers: {
"Content-Type": "application/json; charset=UTF-8"
}
});
}
const json = await (await req).json();
if (json.status === "OK") {
return json.payload;
} else {
console.error(json.payload);
throw new ApiException("Request failed!");
}
}
interface Album {
title: string;
recordid: number;
artist: string;
cdid: number | null;
date_added: string;
date_released: string;
// TODO
}
interface TimeslotItemBase {
timeslotitemid: string;
channel: number;
weight: number;
title: string;
length: string;
trackid: number;
}
interface TimeslotItemCentral {
type: "central";
artist: string;
intro: number;
clean: boolean;
digitised: boolean;
album: Album;
}
interface TimeslotItemAux {
type: "aux";
summary: string;
recordid: string;
auxid: string;
}
export type TimeslotItem = TimeslotItemBase &
(TimeslotItemCentral | TimeslotItemAux);
export type Showplan = TimeslotItem[][];
export function getShowplan(showId: number): Promise<Showplan> {
return myradioApiRequest(
`/timeslot/${showId.toString(10)}/showplan`,
"GET",
{}
).then(res => {
console.log(res);
return Object.keys(res).map(x => res[x]);
});
}
function wrapPromise<T, TArgs>(factory: (...args: TArgs[]) => Promise<T>) {
let status = "pending";
let result: T;
let suspender: Promise<void>;
return {
read(...args: TArgs[]) {
if (!(suspender instanceof Promise)) {
suspender = factory(...args).then(
r => {
status = "success";
result = r;
},
e => {
status = "error";
result = e;
}
);
}
if (status === "pending") {
throw suspender;
} else if (status === "error") {
throw result;
} else if (status === "success") {
return result;
} else {
throw new Error("Can't happen.");
}
}
};
}
export interface Track {
title: string;
artist: string;
album: Album;
trackid: number;
length: string;
intro: number;
clean: boolean;
digitised: boolean;
}
export const showPlanResource = wrapPromise<Showplan, number>(getShowplan);
export function searchForTracks(
artist: string,
title: string
): Promise<Array<Track>> {
return myradioApiRequest("/track/search", "GET", {
artist,
title,
limit: 100,
digitised: true
});
}
export type UpdateOp = {
op: "MoveItem";
timeslotitemid: string;
oldchannel: number;
oldweight: number;
channel: number;
weight: number;
};
interface OpResult {
status: boolean;
timeslotitemid?: string;
}
export function updateShowplan(
timeslotid: number,
ops: UpdateOp[]
): Promise<OpResult[]> {
return myradioApiRequest(`/timeslot/${timeslotid}/updateshowplan`, "PUT", {
set: ops
});
}

View file

@ -1,10 +1,21 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
ReactDOM.render(<App />, document.getElementById('root'));
import store from "./store";
import { Provider } from "react-redux";
function render() {
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
}
render();
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.

35
src/lib/useDebounce.ts Normal file
View file

@ -0,0 +1,35 @@
import React, { useState, useEffect } from 'react';
// Our hook
export default function useDebounce<T>(value: T, delay: number) {
// State and setters for debounced value
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(
() => {
// Set debouncedValue to value (passed in) after the specified delay
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
// Return a cleanup function that will be called every time ...
// ... useEffect is re-called. useEffect will only be re-called ...
// ... if value changes (see the inputs array below).
// This is how we prevent debouncedValue from changing if value is ...
// ... changed within the delay period. Timeout gets cleared and restarted.
// To put it in context, if the user is typing within our app's ...
// ... search box, we don't want the debouncedValue to update until ...
// ... they've stopped typing for more than 500ms.
return () => {
clearTimeout(handler);
};
},
// Only re-call effect if value changes
// You could also add the "delay" var to inputs array if you ...
// ... need to be able to change that dynamically.
[value]
);
return debouncedValue;
}

38
src/lib/utils.ts Normal file
View file

@ -0,0 +1,38 @@
export function convertModelToFormData(
model: any,
form: FormData | null = null,
namespace = ""
): FormData {
let formData = form || new FormData();
let formKey;
for (let propertyName in model) {
if (!model.hasOwnProperty(propertyName) || !model[propertyName]) continue;
let formKey = namespace ? `${namespace}[${propertyName}]` : propertyName;
if (model[propertyName] instanceof Date)
formData.append(formKey, model[propertyName].toISOString());
else if (model[propertyName] instanceof Array) {
model[propertyName].forEach((element: any, index: number) => {
const tempFormKey = `${formKey}[${index}]`;
convertModelToFormData(element, formData, tempFormKey);
});
} else if (
typeof model[propertyName] === "object" &&
!(model[propertyName] instanceof File)
)
convertModelToFormData(model[propertyName], formData, formKey);
else formData.append(formKey, model[propertyName].toString());
}
return formData;
}
export function urlEncode(element: any, key?: string, list?: any[]) {
list = list || [];
if (typeof element == "object") {
for (var idx in element)
urlEncode(element[idx], key ? key + "[" + idx + "]" : idx, list);
} else {
list.push(key + "=" + encodeURIComponent(element));
}
return list.join("&");
}

11
src/rootReducer.ts Normal file
View file

@ -0,0 +1,11 @@
import { combineReducers } from "@reduxjs/toolkit";
import ShowplanReducer from "./showplanner/state";
const rootReducer = combineReducers({
showplan: ShowplanReducer
});
export type RootState = ReturnType<typeof rootReducer>;
export default rootReducer;

208
src/showplanner/index.tsx Normal file
View file

@ -0,0 +1,208 @@
import React, { useState, useReducer, useRef, useEffect } from "react";
import { DndProvider, useDrag, useDrop } from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";
import {
showPlanResource,
Showplan,
TimeslotItem,
Track,
searchForTracks
} from "../api";
import { XYCoord } from "dnd-core";
import {
Droppable,
DragDropContext,
Draggable,
DropResult,
ResponderProvided
} from "react-beautiful-dnd";
import useDebounce from "../lib/useDebounce";
import { useSelector, useDispatch } from "react-redux";
import { RootState } from "../rootReducer";
import { Plan, PlanItem, getShowplan, itemId, moveItem } from "./state";
const CML_CACHE: { [recordid_trackid: string]: Track } = {};
function Item({ item: x, index }: { item: PlanItem | Track; index: number }) {
const id = itemId(x);
return (
<Draggable draggableId={id} index={index} isDragDisabled={"ghostid" in x}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
key={id}
className="sp-track"
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{x.title}
{"artist" in x && " - " + x.artist}
<code>
{itemId(x)} {"channel" in x && x.channel + "/" + x.weight}
</code>
</div>
)}
</Draggable>
);
}
function Column({ id, data }: { id: number; data: PlanItem[] }) {
return (
<Droppable droppableId={id.toString(10)}>
{(provided, snapshot) => (
<div
className="sp-col"
ref={provided.innerRef}
{...provided.droppableProps}
>
{typeof data[id] === "undefined"
? null
: data
.filter(x => x.channel === id)
.sort((a, b) => a.weight - b.weight)
.map((x, index) => (
<Item key={itemId(x)} item={x} index={index} />
))}
{provided.placeholder}
</div>
)}
</Droppable>
);
}
function CentralMusicLibrary() {
const [track, setTrack] = useState("");
const debouncedTrack = useDebounce(track, 1000);
const [items, setItems] = useState<Track[]>([]);
useEffect(() => {
if (debouncedTrack === "") {
return;
}
searchForTracks("", track).then(tracks => {
tracks.forEach(track => {
const id =
track.album.recordid.toString(10) + "-" + track.trackid.toString(10);
if (!(id in CML_CACHE)) {
CML_CACHE[id] = track;
}
});
setItems(tracks);
});
}, [debouncedTrack]);
return (
<>
<input
type="text"
placeholder="Filter by track..."
value={track}
onChange={e => setTrack(e.target.value)}
/>
<Droppable droppableId="$CML">
{(provided, snapshot) => (
<div ref={provided.innerRef} {...provided.droppableProps}>
{items.map((item, index) => (
<Item key={item.trackid} item={item} index={index} />
))}
{provided.placeholder}
</div>
)}
</Droppable>
</>
);
}
function LibraryColumn() {
const [sauce, setSauce] = useState("None");
return (
<div className="sp-col">
<select
style={{ width: "100%" }}
value={sauce}
onChange={e => setSauce(e.target.value)}
>
<option value={"None"} disabled>
Choose a library
</option>
<option value={"CentralMusicLibrary"}>Central Music Library</option>
</select>
{sauce === "CentralMusicLibrary" && <CentralMusicLibrary />}
</div>
);
}
const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) {
const {
plan: showplan,
planLoadError,
planLoading,
planSaveError,
planSaving
} = useSelector((state: RootState) => state.showplan);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getShowplan(timeslotId));
}, [timeslotId]);
async function onDragEnd(result: DropResult, provider: ResponderProvided) {
if (result.destination!.droppableId[0] === "$") {
// pseudo-channel
return;
}
if (result.draggableId[0] === "T") {
// this is a track from the CML
//TODO
} else {
// this is a normal move (ghosts aren't draggable)
dispatch(
moveItem(timeslotId, result.draggableId, [
parseInt(result.destination!.droppableId, 10),
result.destination!.index
])
);
}
}
if (showplan === null) {
return (
<div className="sp-container">
<h1>Show Planner</h1>
{planLoading && (
<b>Your plan is loading, please wait just a second...</b>
)}
{planLoadError !== null && (
<>
<b>Plan load failed!</b> Please tell Comp that something broke.
<p>
<code>{planLoadError}</code>
</p>
</>
)}
</div>
);
}
return (
<div className="sp-container">
<h1>Show Planner</h1>
<div className="sp-status">
{planSaving && <em>Plan saving...</em>}
{planSaveError && (
<b>
Catastrophe! <code>{planSaveError}</code>
</b>
)}
</div>
<div className="sp">
<DragDropContext onDragEnd={onDragEnd}>
<Column id={0} data={showplan} />
<Column id={1} data={showplan} />
<Column id={2} data={showplan} />
<LibraryColumn />
</DragDropContext>
</div>
</div>
);
};
export default Showplanner;

273
src/showplanner/state.ts Normal file
View file

@ -0,0 +1,273 @@
import { TimeslotItem, Track, Showplan } from "../api";
import * as api from "../api";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { AppThunk } from "../store";
import { cloneDeep } from "lodash";
export interface ItemGhost {
title: string;
ghostid: string;
channel: number;
weight: number;
}
export type PlanItem = TimeslotItem | ItemGhost;
export type Plan = PlanItem[][];
export function itemId(item: PlanItem | Track) {
if ("timeslotitemid" in item) {
return item.timeslotitemid;
}
if ("ghostid" in item) {
return "G" + item.ghostid;
}
if ("trackid" in item) {
return "T" + item.album.recordid + "-" + item.trackid;
}
throw new Error();
}
interface ShowplanState {
planLoading: boolean;
planLoadError: string | null;
plan: null | PlanItem[];
planSaving: boolean;
planSaveError: string | null;
}
const initialState: ShowplanState = {
planLoading: true,
planLoadError: null,
plan: null,
planSaving: false,
planSaveError: null
};
const showplan = createSlice({
name: "showplan",
initialState,
reducers: {
getShowplanStarting(state, action) {
state.planLoadError = null;
state.planLoading = true;
},
getShowplanSuccess(state, action: PayloadAction<PlanItem[]>) {
state.plan = action.payload;
state.planLoading = false;
},
getShowplanError(state, action: PayloadAction<string>) {
state.planLoading = false;
state.planLoadError = action.payload;
},
setPlanSaving(state, action: PayloadAction<boolean>) {
state.planSaving = action.payload;
},
planSaveError(state, action: PayloadAction<string>) {
state.planSaving = false;
state.planSaveError = action.payload;
},
applyOps(state, action: PayloadAction<api.UpdateOp[]>) {
if (!state.plan) {
return;
}
action.payload.forEach(op => {
switch (op.op) {
case "MoveItem":
const item = state.plan!.find(
x => itemId(x) === op.timeslotitemid
)!;
item.channel = op.channel;
item.weight = op.weight;
break;
default:
throw new Error();
}
});
}
}
});
export default showplan.reducer;
export const moveItem = (
timeslotid: number,
itemid: string,
to: [number, number]
): AppThunk => async (dispatch, getState) => {
// Make a copy of the plan, because we are about to engage in FUCKERY.
const plan = cloneDeep(getState().showplan.plan!);
const itemToMove = plan.find(x => itemId(x) === itemid)!;
if (itemToMove.channel === to[0] && itemToMove.weight === to[1]) {
return;
}
console.log(
`Moving item ${itemId(itemToMove)} from ${itemToMove.channel}x${
itemToMove.weight
} to ${to[0]}x${to[1]}`
);
dispatch(showplan.actions.setPlanSaving(true));
const oldChannel = itemToMove.channel;
const oldWeight = itemToMove.weight;
const [newChannel, newWeight] = to;
const inc: string[] = [];
const dec: string[] = [];
if (oldChannel === newChannel) {
// Moving around in the same channel
const itemChan = plan
.filter(x => x.channel === oldChannel)
.sort((a, b) => a.weight - b.weight);
if (oldWeight < newWeight) {
// moved the item down (incremented) - everything in between needs decrementing
for (let i = oldWeight + 1; i <= newWeight; i++) {
dec.push(itemId(itemChan[i]));
itemChan[i].weight -= 1;
}
} else {
// moved the item up (decremented) - everything in between needs incrementing
for (let i = newWeight; i < oldWeight; i++) {
inc.push(itemId(itemChan[i]));
itemChan[i].weight += 1;
}
}
itemToMove.channel = newChannel;
itemToMove.weight = newWeight;
} else {
// Moving between channels
// So here's the plan.
// We're going to temporarily remove the item we're actually moving from the plan
// This is because its position becomes nondeterministic when we move it around.
plan.splice(plan.indexOf(itemToMove), 1);
itemToMove.channel = newChannel;
itemToMove.weight = newWeight;
// First, decrement everything between the old weight and the end of the old channel
// (inclusive of old weight, because we've removed the item)
const oldChannelData = plan
.filter(x => x.channel === oldChannel)
.sort((a, b) => a.weight - b.weight);
for (let i = oldWeight; i < oldChannelData.length; i++) {
const movingItem = oldChannelData[i];
movingItem.weight -= 1;
dec.push(itemId(movingItem));
}
// Then, increment everything between the new weight and the end of the new channel
// (again, inclusive)
const newChannelData = plan
.filter(x => x.channel === newChannel)
.sort((a, b) => a.weight - b.weight);
for (let i = newWeight; i < newChannelData.length; i++) {
const movingItem = newChannelData[i];
movingItem.weight += 1;
inc.push(itemId(movingItem));
}
}
const ops: api.UpdateOp[] = [];
console.log("Inc, dec:", inc, dec);
inc.forEach(id => {
const item = plan.find(x => itemId(x) === id)!;
ops.push({
op: "MoveItem",
timeslotitemid: itemId(item),
oldchannel: item.channel,
oldweight: item.weight - 1,
channel: item.channel,
weight: item.weight
});
});
dec.forEach(id => {
const item = plan.find(x => itemId(x) === id)!;
ops.push({
op: "MoveItem",
timeslotitemid: itemId(item),
oldchannel: item.channel,
oldweight: item.weight + 1,
channel: item.channel,
weight: item.weight
});
});
// Then, and only then, put the item in its new place
console.log("Moving over");
ops.push({
op: "MoveItem",
timeslotitemid: (itemToMove as TimeslotItem).timeslotitemid,
oldchannel: oldChannel,
oldweight: oldWeight,
channel: newChannel,
weight: newWeight
});
console.log(
"TL;DR of opset is\r\n" +
ops
.map(x => `${x.oldchannel}x${x.oldweight} -> ${x.channel}x${x.weight}`)
.join(";\r\n")
);
dispatch(showplan.actions.applyOps(ops));
const result = await api.updateShowplan(timeslotid, ops);
if (!result.every(x => x.status)) {
dispatch(showplan.actions.planSaveError("Server says no!"));
} else {
dispatch(showplan.actions.setPlanSaving(false));
}
};
export const getShowplan = (timeslotId: number): AppThunk => async dispatch => {
dispatch(showplan.actions.getShowplanStarting());
try {
const plan = await api.getShowplan(timeslotId);
// Sanity check
const ops: api.UpdateOp[] = [];
for (let colIndex = 0; colIndex < plan.length; colIndex++) {
// Sort the column
plan[colIndex] = plan[colIndex].sort((a, b) => {
const weightRes = a.weight - b.weight;
if (weightRes !== 0) {
return weightRes;
}
return parseInt(a.timeslotitemid, 10) - parseInt(b.timeslotitemid, 10);
});
// If anything is out of place, budge it over
const col = plan[colIndex];
for (let itemIndex = 0; itemIndex < col.length; itemIndex++) {
const item = col[itemIndex];
if (item.weight !== itemIndex) {
// arse.
ops.push({
op: "MoveItem",
timeslotitemid: item.timeslotitemid,
oldchannel: colIndex,
channel: colIndex,
oldweight: item.weight,
weight: itemIndex
});
plan[colIndex][itemIndex].weight = itemIndex;
}
}
}
if (ops.length > 0) {
console.log("Repairing showplan", ops);
const updateResult = await api.updateShowplan(timeslotId, ops);
if (!updateResult.every(x => x.status)) {
console.error("Repair failed!");
dispatch(showplan.actions.getShowplanError("Repair failed!"));
return;
}
}
dispatch(showplan.actions.getShowplanSuccess(plan.flat(2)));
} catch (e) {
console.error(e);
dispatch(showplan.actions.getShowplanError(e.toString()));
}
};

18
src/store.ts Normal file
View file

@ -0,0 +1,18 @@
import rootReducer, { RootState } from "./rootReducer";
import { configureStore, Action } from "@reduxjs/toolkit";
import { ThunkAction } from "redux-thunk";
const store = configureStore({
reducer: rootReducer
});
if (process.env.NODE_ENV === "development" && module.hot) {
module.hot.accept("./rootReducer", () => {
const newRootReducer = require("./rootReducer").default;
store.replaceReducer(newRootReducer);
});
}
export type AppDispatch = typeof store.dispatch;
export type AppThunk = ThunkAction<void, RootState, null, Action<string>>;
export default store;

268
yarn.lock
View file

@ -839,6 +839,14 @@
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-transform-typescript" "^7.6.0"
"@babel/runtime-corejs2@^7.6.3":
version "7.7.2"
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.7.2.tgz#5a8c4e2f8688ce58adc9eb1d8320b6e7341f96ce"
integrity sha512-GfVnHchOBvIMsweQ13l4jd9lT4brkevnavnVOej5g2y7PpTRY+R4pcQlCjWMZoUla5rMLFzaS/Ll2s59cB1TqQ==
dependencies:
core-js "^2.6.5"
regenerator-runtime "^0.13.2"
"@babel/runtime@7.6.0":
version "7.6.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.0.tgz#4fc1d642a9fd0299754e8b5de62c631cf5568205"
@ -853,6 +861,13 @@
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.5.5":
version "7.7.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.2.tgz#111a78002a5c25fc8e3361bedc9529c696b85a6a"
integrity sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==
dependencies:
regenerator-runtime "^0.13.2"
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0":
version "7.6.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6"
@ -1097,6 +1112,18 @@
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
"@reduxjs/toolkit@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.0.4.tgz#cec88446a22a98b48808af7ab19a58aa93e6f5f9"
integrity sha512-nyCZ9/CpnMXFZ//0wm1mNPSEl0J0bCghY2qeHM8zuubaBBMBr6KsIaLLms1jThbOJ1O+Ej0Tl11z5naE9czfzA==
dependencies:
immer "^4.0.1"
redux "^4.0.0"
redux-devtools-extension "^2.13.8"
redux-immutable-state-invariant "^2.1.0"
redux-thunk "^2.3.0"
reselect "^4.0.0"
"@svgr/babel-plugin-add-jsx-attribute@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1"
@ -1200,6 +1227,11 @@
"@svgr/plugin-svgo" "^4.3.1"
loader-utils "^1.2.3"
"@types/asap@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/asap/-/asap-2.0.0.tgz#d529e9608c83499a62ae08c871c5e62271aa2963"
integrity sha512-upIS0Gt9Mc8eEpCbYMZ1K8rhNosfKUtimNcINce+zLwJF5UpM3Vv7yz3S5l/1IX+DxTa8lTkUjqynvjRXyJzsg==
"@types/babel__core@^7.1.0":
version "7.1.3"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.3.tgz#e441ea7df63cd080dfcd02ab199e6d16a735fc30"
@ -1238,6 +1270,19 @@
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==
"@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1":
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==
dependencies:
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
"@types/invariant@^2.2.30":
version "2.2.30"
resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.30.tgz#20efa342807606ada5483731a8137cb1561e5fe9"
integrity sha512-98fB+yo7imSD2F7PF7GIpELNgtLNgo5wjivu0W5V4jx+KVVJxo6p/qN4zdzSTBWy4/sN3pPyXwnhRSD28QX+ag==
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
@ -1275,6 +1320,11 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636"
integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==
"@types/lodash@^4.14.149":
version "4.14.149"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440"
integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==
"@types/node@12.12.7":
version "12.12.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.7.tgz#01e4ea724d9e3bd50d90c11fd5980ba317d8fa11"
@ -1290,6 +1340,18 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
"@types/qs@^6.9.0":
version "6.9.0"
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.0.tgz#2a5fa918786d07d3725726f7f650527e1cfeaffd"
integrity sha512-c4zji5CjWv1tJxIZkz1oUtGcdOlsH3aza28Nqmm+uNDWBRHoMsjooBEN4czZp1V3iXPihE/VRUOBqg+4Xq0W4g==
"@types/react-beautiful-dnd@^11.0.3":
version "11.0.3"
resolved "https://registry.yarnpkg.com/@types/react-beautiful-dnd/-/react-beautiful-dnd-11.0.3.tgz#51d9f37942dd18cc4aa10da98a5c883664e7ee46"
integrity sha512-7ZbT/7mNJu+uRrUGdTQ1hAINtqg909L4NHrXyspV42fvVgBgda6ysiBzoDUMENmQ/RlRJdpyrcp8Dtd/77bp9Q==
dependencies:
"@types/react" "*"
"@types/react-dom@16.9.4":
version "16.9.4"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.4.tgz#0b58df09a60961dcb77f62d4f1832427513420df"
@ -1297,6 +1359,16 @@
dependencies:
"@types/react" "*"
"@types/react-redux@^7.1.5":
version "7.1.5"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.5.tgz#c7a528d538969250347aa53c52241051cf886bd3"
integrity sha512-ZoNGQMDxh5ENY7PzU7MVonxDzS1l/EWiy8nUhDqxFqUZn4ovboCyvk4Djf68x6COb7vhGTKjyjxHxtFdAA5sUA==
dependencies:
"@types/hoist-non-react-statics" "^3.3.0"
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
redux "^4.0.0"
"@types/react@*", "@types/react@16.9.11":
version "16.9.11"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.11.tgz#70e0b7ad79058a7842f25ccf2999807076ada120"
@ -1305,11 +1377,21 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/shallowequal@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/shallowequal/-/shallowequal-1.1.1.tgz#aad262bb3f2b1257d94c71d545268d592575c9b1"
integrity sha512-Lhni3aX80zbpdxRuWhnuYPm8j8UQaa571lHP/xI4W+7BAFhSIhRReXnqjEgT/XzPoXZTJkCqstFMJ8CZTK6IlQ==
"@types/stack-utils@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
"@types/webpack-env@^1.14.1":
version "1.14.1"
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.14.1.tgz#0d8a53f308f017c53a5ddc3d07f4d6fa76b790d7"
integrity sha512-0Ki9jAAhKDSuLDXOIMADg54Hu60SuBTEsWaJGGy5cV+SSUQ63J2a+RrYYGrErzz39fXzTibhKrAQJAb8M7PNcA==
"@types/yargs-parser@*":
version "13.1.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-13.1.0.tgz#c563aa192f39350a1d18da36c5a8da382bbd8228"
@ -1760,7 +1842,7 @@ arrify@^1.0.1:
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
asap@~2.0.6:
asap@^2.0.6, asap@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
@ -2760,6 +2842,11 @@ core-js@^2.4.0:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
core-js@^2.6.5:
version "2.6.10"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.10.tgz#8a5b8391f8cc7013da703411ce5b585706300d7f"
integrity sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@ -2841,6 +2928,13 @@ css-blank-pseudo@^0.1.4:
dependencies:
postcss "^7.0.5"
css-box-model@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.0.tgz#3a26377b4162b3200d2ede4b064ec5b6a75186d0"
integrity sha512-lri0br+jSNV0kkkiGEp9y9y3Njq2PmpqbeGWRFQJuZteZzY9iC9GZhQ8Y4WpPwM/2YocjHePxy14igJY7YKzkA==
dependencies:
tiny-invariant "^1.0.6"
css-color-names@0.0.4, css-color-names@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
@ -3275,6 +3369,17 @@ dir-glob@2.0.0:
arrify "^1.0.1"
path-type "^3.0.0"
dnd-core@^9.4.0:
version "9.4.0"
resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-9.4.0.tgz#ccf605d36887f18cdde8fd5576ca3145d2e69fa8"
integrity sha512-Kg+8VwU8s7TgdR/BUYGUHrvFiS+5ePMZ0Q0XD7p+cFVJvgKqykBaeQDuaziuauFMPm8QxtnUy8Pncey9flXW3Q==
dependencies:
"@types/asap" "^2.0.0"
"@types/invariant" "^2.2.30"
asap "^2.0.6"
invariant "^2.2.4"
redux "^4.0.4"
dns-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@ -4533,6 +4638,13 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
hoist-non-react-statics@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b"
integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==
dependencies:
react-is "^16.7.0"
hosted-git-info@^2.1.4:
version "2.8.4"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.4.tgz#44119abaf4bc64692a16ace34700fed9c03e2546"
@ -4745,6 +4857,11 @@ immer@1.10.0:
resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==
immer@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/immer/-/immer-4.0.2.tgz#9ff0fcdf88e06f92618a5978ceecb5884e633559"
integrity sha512-Q/tm+yKqnKy4RIBmmtISBlhXuSDrB69e9EKTYiIenIKQkXBQir43w+kN/eGiax3wt1J0O1b2fYcNqLSbEcXA7w==
import-cwd@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
@ -4872,7 +4989,7 @@ internal-ip@^4.2.0:
default-gateway "^4.2.0"
ipaddr.js "^1.9.0"
invariant@^2.2.2, invariant@^2.2.4:
invariant@^2.1.0, invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
@ -5744,7 +5861,7 @@ json-stable-stringify@^1.0.1:
dependencies:
jsonify "~0.0.0"
json-stringify-safe@~5.0.1:
json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
@ -6081,6 +6198,11 @@ mem@^4.0.0:
mimic-fn "^2.0.0"
p-is-promise "^2.0.0"
memoize-one@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==
memory-fs@^0.4.0, memory-fs@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
@ -7921,6 +8043,11 @@ qs@6.7.0:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
qs@^6.9.1:
version "6.9.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9"
integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==
qs@~6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
@ -7949,6 +8076,11 @@ querystringify@^2.1.1:
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
raf-schd@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.2.tgz#bd44c708188f2e84c810bf55fcea9231bcaed8a0"
integrity sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ==
raf@3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
@ -8008,6 +8140,19 @@ react-app-polyfill@^1.0.4:
regenerator-runtime "0.13.3"
whatwg-fetch "3.0.0"
react-beautiful-dnd@^12.1.1:
version "12.1.1"
resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-12.1.1.tgz#810f9b9d94f667b15b253793e853d016a0f3f07c"
integrity sha512-w/mpIXMEXowc53PCEnMoFyAEYFgxMfygMK5msLo5ifJ2/CiSACLov9A79EomnPF7zno3N207QGXsraBxAJnyrw==
dependencies:
"@babel/runtime-corejs2" "^7.6.3"
css-box-model "^1.2.0"
memoize-one "^5.1.1"
raf-schd "^4.0.2"
react-redux "^7.1.1"
redux "^4.0.4"
use-memo-one "^1.1.1"
react-dev-utils@^9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-9.1.0.tgz#3ad2bb8848a32319d760d0a84c56c14bdaae5e81"
@ -8039,26 +8184,66 @@ react-dev-utils@^9.1.0:
strip-ansi "5.2.0"
text-table "0.2.0"
react-dom@16.11.0:
version "16.11.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.11.0.tgz#7e7c4a5a85a569d565c2462f5d345da2dd849af5"
integrity sha512-nrRyIUE1e7j8PaXSPtyRKtz+2y9ubW/ghNgqKFHHAHaeP0fpF5uXR+sq8IMRHC+ZUxw7W9NyCDTBtwWxvkb0iA==
react-dnd-html5-backend@^9.4.0:
version "9.4.0"
resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-9.4.0.tgz#5b1d192f57d103298657cde1fe0eabdbf2726311"
integrity sha512-gehPwLp505F6RoFkQiDX7Q4mbpbyfyT0TbIoZop/m4vkBw6yUE/QLrnxBQdNpDPSwL/9XkZxxd/PrbeMCQ+WrQ==
dependencies:
dnd-core "^9.4.0"
react-dnd@^9.4.0:
version "9.4.0"
resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-9.4.0.tgz#eec87035c6360fb33a44932326b3369af011a41c"
integrity sha512-jnLF8qKowCKTqSddfCiLx5+sb+HxO1qgdiAgbBeL8yuo5tRYNtKxZYn7+wVwNoyZuWEuM1Gw/Wsdhr+yb2RELQ==
dependencies:
"@types/hoist-non-react-statics" "^3.3.1"
"@types/shallowequal" "^1.1.1"
dnd-core "^9.4.0"
hoist-non-react-statics "^3.3.0"
shallowequal "^1.1.0"
react-dom@^0.0.0-experimental-38dd17ab9:
version "0.0.0-experimental-38dd17ab9"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-38dd17ab9.tgz#74e040bb234bf8df4ea129814e6f099ccd31639e"
integrity sha512-PemrIDeg/5hhkU0Ota8vWPm9noyrQ2qQTpPFS2EAyNz3Nb499dM/+STaczkVgLmfoiwd8zQdHWM7Q7ijHyT56A==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.17.0"
scheduler "0.0.0-experimental-38dd17ab9"
react-error-overlay@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.3.tgz#c378c4b0a21e88b2e159a3e62b2f531fd63bf60d"
integrity sha512-bOUvMWFQVk5oz8Ded9Xb7WVdEi3QGLC8tH7HmYP0Fdp4Bn3qw0tRFmr5TW6mvahzvmrK4a6bqWGfCevBflP+Xw==
react-is@^16.7.0:
version "16.11.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa"
integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw==
react-is@^16.8.1, react-is@^16.8.4:
version "16.10.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.10.1.tgz#0612786bf19df406502d935494f0450b40b8294f"
integrity sha512-BXUMf9sIOPXXZWqr7+c5SeOKJykyVr2u0UDzEf4LNGc6taGkQe1A9DFD07umCIXz45RLr9oAAwZbAJ0Pkknfaw==
react-is@^16.9.0:
version "16.12.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c"
integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==
react-redux@^7.1.1, react-redux@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.1.3.tgz#717a3d7bbe3a1b2d535c94885ce04cdc5a33fc79"
integrity sha512-uI1wca+ECG9RoVkWQFF4jDMqmaw0/qnvaSvOoL/GA4dNxf6LoV8sUAcNDvE5NWKs4hFpn0t6wswNQnY3f7HT3w==
dependencies:
"@babel/runtime" "^7.5.5"
hoist-non-react-statics "^3.3.0"
invariant "^2.2.4"
loose-envify "^1.4.0"
prop-types "^15.7.2"
react-is "^16.9.0"
react-scripts@3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.2.0.tgz#58ccd6b4ffa27f1b4d2986cbdcaa916660e9e33c"
@ -8120,10 +8305,10 @@ react-scripts@3.2.0:
optionalDependencies:
fsevents "2.0.7"
react@16.11.0:
version "16.11.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.11.0.tgz#d294545fe62299ccee83363599bf904e4a07fdbb"
integrity sha512-M5Y8yITaLmU0ynd0r1Yvfq98Rmll6q8AxaEe88c8e7LxO8fZ2cNgmFt0aGAS9wzf1Ao32NKXtCl+/tVVtkxq6g==
react@^0.0.0-experimental-38dd17ab9:
version "0.0.0-experimental-38dd17ab9"
resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-38dd17ab9.tgz#d2cc104de47fa58abb4297f27bcc54854e20581a"
integrity sha512-rPEXj4mppahrDR+jpDd/sYAkRiwhgTvxtehM5kNDPtTnzz6RChflHZ9U8inQpVdX/nkcnO6r92JyBxJaR+6tVg==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
@ -8208,6 +8393,32 @@ recursive-readdir@2.2.2:
dependencies:
minimatch "3.0.4"
redux-devtools-extension@^2.13.8:
version "2.13.8"
resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1"
integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg==
redux-immutable-state-invariant@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/redux-immutable-state-invariant/-/redux-immutable-state-invariant-2.1.0.tgz#308fd3cc7415a0e7f11f51ec997b6379c7055ce1"
integrity sha512-3czbDKs35FwiBRsx/3KabUk5zSOoTXC+cgVofGkpBNv3jQcqIe5JrHcF5AmVt7B/4hyJ8MijBIpCJ8cife6yJg==
dependencies:
invariant "^2.1.0"
json-stringify-safe "^5.0.1"
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.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.4.tgz#4ee1aeb164b63d6a1bcc57ae4aa0b6e6fa7a3796"
integrity sha512-vKv4WdiJxOWKxK0yRoaK3Y4pxxB0ilzVx6dszU2W8wLxlb2yikRph4iV/ymtdJ6ZxpBLFbyrxklnT5yBbQSl3Q==
dependencies:
loose-envify "^1.4.0"
symbol-observable "^1.2.0"
regenerate-unicode-properties@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
@ -8379,6 +8590,11 @@ requires-port@^1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
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@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
@ -8573,10 +8789,10 @@ saxes@^3.1.9:
dependencies:
xmlchars "^2.1.1"
scheduler@^0.17.0:
version "0.17.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.17.0.tgz#7c9c673e4ec781fac853927916d1c426b6f3ddfe"
integrity sha512-7rro8Io3tnCPuY4la/NuI5F2yfESpnfZyT6TtkXnSWVkcu0BCDJ+8gk5ozUaFaxpIyNuWAPXrH0yFcSi28fnDA==
scheduler@0.0.0-experimental-38dd17ab9:
version "0.0.0-experimental-38dd17ab9"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-38dd17ab9.tgz#59e1ab1df3a92e270ad0c94b474284185740b01d"
integrity sha512-F2OVE+lm5Pxv5DlxB/c9xs0qBYBIUexxpJEi7yjic2aW1iiP4FrYnJNS9D4mWDHvwV0H5spDEURW5resrgsY+g==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
@ -8722,6 +8938,11 @@ shallow-clone@^3.0.0:
dependencies:
kind-of "^6.0.2"
shallowequal@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@ -9231,6 +9452,11 @@ svgo@^1.0.0, svgo@^1.2.2:
unquote "~1.1.1"
util.promisify "~1.0.0"
symbol-observable@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
symbol-tree@^3.2.2:
version "3.2.4"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
@ -9338,6 +9564,11 @@ timsort@^0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
tiny-invariant@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73"
integrity sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@ -9625,6 +9856,11 @@ url@^0.11.0:
punycode "1.3.2"
querystring "0.2.0"
use-memo-one@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.1.tgz#39e6f08fe27e422a7d7b234b5f9056af313bd22c"
integrity sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ==
use@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"