From 476a55614e19c7ccea61ecd2d365ee7e1e4f2c63 Mon Sep 17 00:00:00 2001 From: Rishi Ghan Date: Thu, 16 Sep 2021 09:24:06 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A8=20Implemented=20a=20notification?= =?UTF-8?q?=20system=20for=20background=20import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- src/client/actions/fileops.actions.tsx | 22 ++- src/client/assets/scss/App.scss | 12 +- src/client/components/App.tsx | 97 ++++++++---- src/client/components/Import.tsx | 209 +++++++++---------------- src/client/reducers/fileops.reducer.ts | 1 + src/client/reducers/index.js | 2 + yarn.lock | 47 ++++-- 8 files changed, 202 insertions(+), 191 deletions(-) diff --git a/package.json b/package.json index b1a3910..81d45c1 100644 --- a/package.json +++ b/package.json @@ -56,8 +56,9 @@ "react-dom": "^17.0.1", "react-fast-compare": "^3.2.0", "react-final-form": "^6.5.3", - "react-hot-toast": "^2.1.1", "react-loader-spinner": "^4.0.0", + "react-notification-system": "^0.4.0", + "react-notification-system-redux": "^2.0.1", "react-select": "^4.3.1", "react-sliding-pane": "^7.0.0", "react-table": "^7.7.0", diff --git a/src/client/actions/fileops.actions.tsx b/src/client/actions/fileops.actions.tsx index 3d54c67..b34057b 100644 --- a/src/client/actions/fileops.actions.tsx +++ b/src/client/actions/fileops.actions.tsx @@ -16,6 +16,13 @@ import { import { refineQuery } from "../shared/utils/filenameparser.utils"; import sortBy from "array-sort-by"; import { io } from "socket.io-client"; +import { + success, + error, + warning, + info, + removeAll, +} from "react-notification-system-redux"; export async function walkFolder(path: string): Promise> { return axios @@ -71,7 +78,16 @@ export const fetchComicBookMetadata = (options) => async (dispatch) => { }, }; const walkedFolders = await walkFolder("./comics"); - + dispatch( + success({ + // uid: 'once-please', // you can specify your own uid if required + title: "Import Started", + message: `${socket.id} connected. ${walkedFolders.length} comics scanned.`, + dismissible: "click", + position: "tr", + autoDismiss: 0, + }), + ); await axios .request({ url: "http://localhost:8050/api/getComicCovers", @@ -87,6 +103,10 @@ export const fetchComicBookMetadata = (options) => async (dispatch) => { socket.on("coverExtracted", (data) => { console.log(data); + dispatch({ + type: IMS_COMICBOOK_METADATA_FETCHED, + data, + }); }); }; diff --git a/src/client/assets/scss/App.scss b/src/client/assets/scss/App.scss index b4f96bb..a9e24de 100644 --- a/src/client/assets/scss/App.scss +++ b/src/client/assets/scss/App.scss @@ -79,7 +79,8 @@ $border-color: red; .card-title { margin-bottom: 0.4rem; } - .cv-icon, i { + .cv-icon, + i { margin: 4px 4px 4px 0; } padding: 0.5rem 1rem; @@ -152,8 +153,9 @@ $border-color: red; } } -// Comic Detail +// Import +// Comic Detail .comic-detail { dl { dd { @@ -161,9 +163,9 @@ $border-color: red; } } .button { - .airdcpp-text { - margin: 0 0 0 0.2rem; - } + .airdcpp-text { + margin: 0 0 0 0.2rem; + } } } // Search diff --git a/src/client/components/App.tsx b/src/client/components/App.tsx index d120129..6d4ec9c 100644 --- a/src/client/components/App.tsx +++ b/src/client/components/App.tsx @@ -1,4 +1,5 @@ -import * as React from "react"; +import React, { ReactElement } from "react"; +import { useSelector } from "react-redux"; import { hot } from "react-hot-loader"; import Dashboard from "./Dashboard"; @@ -11,38 +12,68 @@ import Settings from "./Settings"; import { Switch, Route } from "react-router"; import Navbar from "./Navbar"; import "../assets/scss/App.scss"; +import Notifications from "react-notification-system-redux"; -class App extends React.Component { - public render() { - return ( -
- - - - - - - - - - - - - - - - - - - -
- ); - } -} - -declare let module: Record; +//Optional styling +const style = { + Containers: { + DefaultStyle: { + fontFamily: "inherit", + position: "fixed", + padding: "0 10px 10px 10px", + zIndex: 9998, + WebkitBoxSizing: "border-box", + MozBoxSizing: "border-box", + boxSizing: "border-box", + height: "auto", + }, + tr: { + top: "40px", + }, + }, + NotificationItem: { + // Override the notification item + success: { + // Applied to every notification, regardless of the notification level + borderTop: "none", + backgroundColor: "none", + borderRadius: "0.4rem", + WebkitBoxShadow: "-7px 11px 25px -9px rgba(0, 0, 0, 0.3)", + MozBoxShadow: "-7px 11px 25px -9px rgba(0, 0, 0, 0.3)", + boxShadow: "-7px 11px 25px -9px rgba(0, 0, 0, 0.3)", + }, + }, +}; +export const App = (): ReactElement => { + const notifications = useSelector((state: RootState) => state.notifications); + return ( +
+ + + + + + + + + + + + + + + + + + + + +
+ ); +}; export default hot(module)(App); diff --git a/src/client/components/Import.tsx b/src/client/components/Import.tsx index ec92773..952bd72 100644 --- a/src/client/components/Import.tsx +++ b/src/client/components/Import.tsx @@ -1,153 +1,86 @@ -import * as React from "react"; -import { isUndefined } from "lodash"; -import { connect } from "react-redux"; +import React, { ReactElement, useCallback } from "react"; +import { isNil, isUndefined } from "lodash"; +import { useSelector, useDispatch } from "react-redux"; import { fetchComicBookMetadata } from "../actions/fileops.actions"; import { IFolderData } from "threetwo-ui-typings"; import DynamicList, { createCache } from "react-window-dynamic-list"; -import toast, { Toaster } from "react-hot-toast"; +; interface IProps { - matches: unknown; - fetchComicMetadata: any; + matches?: unknown; + fetchComicMetadata?: any; path: string; - covers: any; + covers?: any; } -interface IState { - folderWalkResults?: Array; - searchPaneIndex: number; - fileOps: any; -} -class Import extends React.Component { - /** - * Returns the average of two numbers. - * - * @remarks - * This method is part of the {@link core-library#Statistics | Statistics subsystem}. - * - * @param x - The first input number - * @param y - The second input number - * @returns The arithmetic mean of `x` and `y` - * - * @beta - */ - constructor(props: IProps) { - super(props); - this.state = { - folderWalkResults: [], - searchPaneIndex: 0, - fileOps: [], - }; - } - public toggleSearchResultsPane(paneId: number): void { - this.setState({ - searchPaneIndex: paneId, - }); - } +/** + * Returns the average of two numbers. + * + * @remarks + * This method is part of the {@link core-library#Statistics | Statistics subsystem}. + * + * @param x - The first input number + * @param y - The second input number + * @returns The arithmetic mean of `x` and `y` + * + * @beta + */ - public initiateImport = () => { - if (typeof this.props.path !== "undefined") { - this.props.fetchComicMetadata(); - toast.custom( -
-
Saokaaate
-
, - { - position: "top-right", - }, - ); +export const Import = (props: IProps): ReactElement => { + const dispatch = useDispatch(); + const isSocketConnected = useSelector((state: RootState) => { + console.log(state); + return state.fileOps.isSocketConnected; + }); + + const initiateImport = useCallback(() => { + if (typeof props.path !== "undefined") { + console.log("asdasd"); + dispatch(fetchComicBookMetadata(props.path)); } - }; + }, [dispatch]); - public cache = createCache(); + return ( +
+
+

Import

+ {isSocketConnected} +
+
+

+ + Import Only + + will add comics identified from the mapped folder into the local + db. +

+

+ + Import and Tag + + will scan the ComicVine, shortboxed APIs and import comics from + the mapped folder with the additional metadata. +

+
+
+

+ - public renderRow = ({ index, style }) => ( -

- {index} -
- cover - - {this.props.covers[index].comicBookCoverMetadata.name} - -
- imported from -
- path - - {this.props.covers[index].comicBookCoverMetadata.path} - -
-
-
-          
-            
-          
-          {JSON.stringify(this.props.covers[index].dbImportResult, null, 2)}
-        
-
+ +

+
); +}; - public render() { - return ( -
-
-

Import

- -
-
-

- - Import Only - - will add comics identified from the mapped folder into the local - db. -

-

- - Import and Tag - - will scan the ComicVine, shortboxed APIs and import comics from - the mapped folder with the additional metadata. -

-
-
- -

- - - -

- - {!isUndefined(this.state.folderWalkResults) ?
: null} -
-
- ); - } -} - -function mapStateToProps(state: IState) { - console.log("state", state); - return { - // matches: state.comicInfo.searchResults, - // covers: state.fileOps.comicBookMetadata, - }; -} - -const mapDispatchToProps = (dispatch, ownProps) => ({ - fetchComicMetadata() { - dispatch(fetchComicBookMetadata(ownProps.path)); - }, -}); - -export default connect(mapStateToProps, mapDispatchToProps)(Import); +export default Import; diff --git a/src/client/reducers/fileops.reducer.ts b/src/client/reducers/fileops.reducer.ts index 2c005df..85c632d 100644 --- a/src/client/reducers/fileops.reducer.ts +++ b/src/client/reducers/fileops.reducer.ts @@ -33,6 +33,7 @@ function fileOpsReducer(state = initialState, action) { return { ...state, isSocketConnected: action.isSocketConnected, + socketId: action.socketId, }; case IMS_RAW_IMPORT_SUCCESSFUL: return { diff --git a/src/client/reducers/index.js b/src/client/reducers/index.js index 30af12b..8b62d53 100644 --- a/src/client/reducers/index.js +++ b/src/client/reducers/index.js @@ -3,9 +3,11 @@ import { connectRouter } from "connected-react-router"; import comicinfoReducer from "../reducers/comicinfo.reducer"; import fileOpsReducer from "../reducers/fileops.reducer"; import airdcppReducer from "../reducers/airdcpp.reducer"; +import { reducer as notifications } from "react-notification-system-redux"; export default (history) => combineReducers({ + notifications, comicInfo: comicinfoReducer, fileOps: fileOpsReducer, airdcpp: airdcppReducer, diff --git a/yarn.lock b/yarn.lock index f75f47a..7b4317d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4191,6 +4191,14 @@ create-error-class@^3.0.0: dependencies: capture-stack-trace "^1.0.0" +create-react-class@^15.5.1: + version "15.7.0" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.7.0.tgz#7499d7ca2e69bb51d13faf59bd04f0c65a1d6c1e" + integrity sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng== + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz" @@ -6306,11 +6314,6 @@ globule@^1.0.0: lodash "~4.17.10" minimatch "~3.0.2" -goober@^2.0.35: - version "2.0.41" - resolved "https://registry.yarnpkg.com/goober/-/goober-2.0.41.tgz#0a3d786ff9917bcf2a096eef703bf717838cbec9" - integrity sha512-kwjegMT5018zWydhOQlQneCgCtrKJaPsru7TaBWmTYV0nsMeUrM6L6O8JmNYb9UbPMgWcmtf+9p4Y3oJabIH1A== - got@^6.7.1: version "6.7.1" resolved "https://registry.npmjs.org/got/-/got-6.7.1.tgz" @@ -10499,7 +10502,7 @@ promzard@^0.3.0: dependencies: read "1" -prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -10907,13 +10910,6 @@ react-hot-loader@^4.13.0: shallowequal "^1.1.0" source-map "^0.7.3" -react-hot-toast@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.1.1.tgz#56409ab406b534e9e58274cf98d80355ba0fdda0" - integrity sha512-Odrp4wue0fHh0pOfZt5H+9nWCMtqs3wdlFSzZPp7qsxfzmbE26QmGWIh6hG43CukiPeOjA8WQhBJU8JwtWvWbQ== - dependencies: - goober "^2.0.35" - react-input-autosize@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-3.0.0.tgz#6b5898c790d4478d69420b55441fcc31d5c50a85" @@ -10953,6 +10949,31 @@ react-modal@^3.12.1: react-lifecycles-compat "^3.0.0" warning "^4.0.3" +react-notification-system-redux@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/react-notification-system-redux/-/react-notification-system-redux-2.0.1.tgz#e1f47e788d344fac9b5183402bb96c73033e5854" + integrity sha512-Ed/IgnuXDc+dNDsnn/qPdZdpGN/2xJgiJY/y3z1UFRHbOUklDE+WLdk/JNhe5Xx33MBCqqfQClAc8cIl+wHnoA== + dependencies: + prop-types "^15.6.0" + react-notification-system "^0.2.x" + +react-notification-system@^0.2.x: + version "0.2.17" + resolved "https://registry.yarnpkg.com/react-notification-system/-/react-notification-system-0.2.17.tgz#a60eddbb62225ad8f9fc5d7837546bf6cdb36818" + integrity sha1-pg7du2IiWtj5/F14N1Rr9s2zaBg= + dependencies: + create-react-class "^15.5.1" + object-assign "^4.0.1" + prop-types "^15.5.6" + +react-notification-system@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/react-notification-system/-/react-notification-system-0.4.0.tgz#30db3963a176ee103b4a3bb1494c2b5578d5c024" + integrity sha512-5WhXnjkYC07zqXruCiUXDU9iHjVxZlL1zgHpNgXk91A5ghV1AHrWVrJYo1XM4SnwlKy5NLdftkaTl+pTuVFAqw== + dependencies: + object-assign "^4.0.1" + prop-types "^15.5.6" + react-redux@^7.2.3: version "7.2.4" resolved "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz"