From 562adaa795d0ec1a0a186340f6afacb9268643ee Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 28 May 2026 12:03:15 -0400 Subject: [PATCH] feature/IO-3725-RPS-Changes - Make settings look nicer --- .gitignore | 1 + README.md | 2 +- electron/main-src.js | 2 +- hasura/config.yaml | 2 +- hasura/config.yaml.prod | 2 +- .../watcher-status/watcher-status.atom.jsx | 18 +- .../filepath-add/filepath-add.molecule.jsx | 8 +- .../shop-settings-form.molecule.jsx | 42 ++-- .../shop-settings-form.molecule.styles.scss | 42 ++++ .../watcher-start/watcher-start.molecule.jsx | 8 +- .../watcher-stop/watcher-stop.molecule.jsx | 8 +- .../filepaths-list.organism.jsx | 32 ++- .../watcher-manager.organism.jsx | 50 ++++- .../pages/settings/settings.page.jsx | 46 ++++- .../pages/settings/settings.page.styles.scss | 192 ++++++++++++++++++ vite.config.js | 2 +- 16 files changed, 390 insertions(+), 67 deletions(-) create mode 100644 src/components/molecules/shop-settings-form/shop-settings-form.molecule.styles.scss create mode 100644 src/components/pages/settings/settings.page.styles.scss diff --git a/.gitignore b/.gitignore index ab47aa1..217e803 100644 --- a/.gitignore +++ b/.gitignore @@ -116,3 +116,4 @@ deploy.ps1 macbuild.sh Usage.md dist-electron +.idea \ No newline at end of file diff --git a/README.md b/README.md index 3a21f6d..4475bb8 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ In the project directory, you can run: ### `yarn start` Runs the app in the development mode.
-Open [http://localhost:3000](http://localhost:3000) to view it in the browser. +Open [http://localhost:3006](http://localhost:3006) to view it in the browser. The page will reload if you make edits.
You will also see any lint errors in the console. diff --git a/electron/main-src.js b/electron/main-src.js index 766830f..1be7f9d 100644 --- a/electron/main-src.js +++ b/electron/main-src.js @@ -174,7 +174,7 @@ function createWindow() { // and load the index.html of the app. // win.loadFile("index.html"); if (isDev) { - mainWindow.loadURL("http://localhost:3000"); + mainWindow.loadURL("http://localhost:3006"); } else { const indexPath = path.join(appPath, "build", "index.html"); mainWindow.loadFile(indexPath); diff --git a/hasura/config.yaml b/hasura/config.yaml index e0ce1c4..4d86930 100644 --- a/hasura/config.yaml +++ b/hasura/config.yaml @@ -14,7 +14,7 @@ migrations_directory: migrations seeds_directory: seeds actions: kind: synchronous - handler_webhook_baseurl: http://localhost:3000 + handler_webhook_baseurl: http://localhost:3006 codegen: framework: "" output_dir: "" diff --git a/hasura/config.yaml.prod b/hasura/config.yaml.prod index 73e3fe3..a31b57d 100644 --- a/hasura/config.yaml.prod +++ b/hasura/config.yaml.prod @@ -14,7 +14,7 @@ migrations_directory: migrations seeds_directory: seeds actions: kind: synchronous - handler_webhook_baseurl: http://localhost:3000 + handler_webhook_baseurl: http://localhost:3006 codegen: framework: "" output_dir: "" diff --git a/src/components/atoms/watcher-status/watcher-status.atom.jsx b/src/components/atoms/watcher-status/watcher-status.atom.jsx index 97868ac..d782911 100644 --- a/src/components/atoms/watcher-status/watcher-status.atom.jsx +++ b/src/components/atoms/watcher-status/watcher-status.atom.jsx @@ -1,4 +1,4 @@ -import { Alert } from "antd"; +import { Alert, Typography } from "antd"; import React from "react"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; @@ -15,13 +15,17 @@ const mapStateToProps = createStructuredSelector({ }); export function WatcherStatusAtom({ watcherStatus, watcherError }) { + const statusClassName = + watcherStatus === "Started" + ? "settings-watcher-status settings-watcher-status--started" + : "settings-watcher-status settings-watcher-status--stopped"; + return ( -
ipcRenderer.send("test")} - style={{ color: watcherStatus === "Started" ? "green" : "tomato" }} - > - {watcherStatus} - {watcherError && } +
ipcRenderer.send("test")}> +
+ {watcherStatus || "Unknown"} +
+ {watcherError && }
); } diff --git a/src/components/molecules/filepath-add/filepath-add.molecule.jsx b/src/components/molecules/filepath-add/filepath-add.molecule.jsx index 8c942e6..80f2adc 100644 --- a/src/components/molecules/filepath-add/filepath-add.molecule.jsx +++ b/src/components/molecules/filepath-add/filepath-add.molecule.jsx @@ -3,9 +3,13 @@ import React from "react"; import ipcTypes from "../../../ipc.types"; const { ipcRenderer } = window; -export default function FilepathAddMolecule() { +export default function FilepathAddMolecule(buttonProps) { const handleClick = () => { ipcRenderer.send(ipcTypes.fileWatcher.toMain.addPath); }; - return ; + return ( + + ); } diff --git a/src/components/molecules/shop-settings-form/shop-settings-form.molecule.jsx b/src/components/molecules/shop-settings-form/shop-settings-form.molecule.jsx index d09464c..a31eb3f 100644 --- a/src/components/molecules/shop-settings-form/shop-settings-form.molecule.jsx +++ b/src/components/molecules/shop-settings-form/shop-settings-form.molecule.jsx @@ -1,21 +1,29 @@ -import { Button, Form, Input, InputNumber, Popconfirm, Select, Space, Switch, Typography } from "antd"; +import { Button, Flex, Form, Input, InputNumber, Popconfirm, Select, Switch, Typography } from "antd"; import React from "react"; import LayoutFormRow from "../../atoms/layout-form-row/layout-form-row.atom"; +import "./shop-settings-form.molecule.styles.scss"; export default function ShopSettingsFormMolecule({ form, saveLoading }) { return ( - - Shop Settings - form.submit()} - > - - +
+ +
+ Shop Settings + + Update the defaults RPS uses when calculating and syncing shop data. + +
+ form.submit()} + > + + +
- + - + + - + - - + +
); } diff --git a/src/components/molecules/shop-settings-form/shop-settings-form.molecule.styles.scss b/src/components/molecules/shop-settings-form/shop-settings-form.molecule.styles.scss new file mode 100644 index 0000000..e3a662e --- /dev/null +++ b/src/components/molecules/shop-settings-form/shop-settings-form.molecule.styles.scss @@ -0,0 +1,42 @@ +.shop-settings-form { + display: flex; + flex-direction: column; + gap: 16px; +} + +.shop-settings-form__header { + width: 100%; +} + +.shop-settings-form__header .ant-typography { + margin-bottom: 0; +} + +.shop-settings-form__header .ant-typography + .ant-typography { + margin-top: 4px; + max-width: 640px; +} + +.shop-settings-form__row .ant-form-item { + margin-bottom: 12px; +} + +.shop-settings-form__row .ant-form-item-label > label { + white-space: normal; + line-height: 1.3; +} + +.shop-settings-form__row .ant-input-number, +.shop-settings-form__row .ant-select { + width: 100%; +} + +@media (max-width: 768px) { + .shop-settings-form__header { + align-items: stretch !important; + } + + .shop-settings-form__header .ant-btn { + width: 100%; + } +} diff --git a/src/components/molecules/watcher-start/watcher-start.molecule.jsx b/src/components/molecules/watcher-start/watcher-start.molecule.jsx index aa28435..2a95390 100644 --- a/src/components/molecules/watcher-start/watcher-start.molecule.jsx +++ b/src/components/molecules/watcher-start/watcher-start.molecule.jsx @@ -3,14 +3,10 @@ import React from "react"; import ipcTypes from "../../../ipc.types"; const { ipcRenderer } = window; -export default function WatcherStartMolecule() { +export default function WatcherStartMolecule(buttonProps) { const handleClick = () => { ipcRenderer.send(ipcTypes.fileWatcher.toMain.start); }; - return ( -
- -
- ); + return ; } diff --git a/src/components/molecules/watcher-stop/watcher-stop.molecule.jsx b/src/components/molecules/watcher-stop/watcher-stop.molecule.jsx index 6e3c51a..5498022 100644 --- a/src/components/molecules/watcher-stop/watcher-stop.molecule.jsx +++ b/src/components/molecules/watcher-stop/watcher-stop.molecule.jsx @@ -3,14 +3,10 @@ import React from "react"; import ipcTypes from "../../../ipc.types"; const { ipcRenderer } = window; -export default function WatcherStopMolecule() { +export default function WatcherStopMolecule(buttonProps) { const handleClick = () => { ipcRenderer.send(ipcTypes.fileWatcher.toMain.stop); }; - return ( -
- -
- ); + return ; } diff --git a/src/components/organisms/filepaths-list/filepaths-list.organism.jsx b/src/components/organisms/filepaths-list/filepaths-list.organism.jsx index 37fe898..e24cbaf 100644 --- a/src/components/organisms/filepaths-list/filepaths-list.organism.jsx +++ b/src/components/organisms/filepaths-list/filepaths-list.organism.jsx @@ -1,4 +1,4 @@ -import { List, Typography } from "antd"; +import { Empty, Flex, List, Typography } from "antd"; import React, { useEffect } from "react"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; @@ -22,10 +22,32 @@ export function FilePathsList({ watchedPaths }) { }, []); return ( -
- Watcher File Paths - - +
+ +
+ Watcher File Paths + + {watchedPaths && watchedPaths.length + ? `${watchedPaths.length} path${watchedPaths.length === 1 ? "" : "s"} being watched` + : "Choose the folders the watcher should monitor."} + +
+ +
+ + ), + }} + />
); } diff --git a/src/components/organisms/watcher-manager/watcher-manager.organism.jsx b/src/components/organisms/watcher-manager/watcher-manager.organism.jsx index 791466f..b8b0a9d 100644 --- a/src/components/organisms/watcher-manager/watcher-manager.organism.jsx +++ b/src/components/organisms/watcher-manager/watcher-manager.organism.jsx @@ -1,16 +1,48 @@ -import { Typography } from "antd"; +import { Button, Flex, Typography } from "antd"; import React from "react"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import ipcTypes from "../../../ipc.types"; +import { selectWatcherStatus } from "../../../redux/application/application.selectors"; import WatcherStatusAtom from "../../atoms/watcher-status/watcher-status.atom"; -import WatcherStartMolecule from "../../molecules/watcher-start/watcher-start.molecule"; -import WatcherStopMolecule from "../../molecules/watcher-stop/watcher-stop.molecule"; +const { ipcRenderer } = window; + +const mapStateToProps = createStructuredSelector({ + watcherStatus: selectWatcherStatus, +}); + +export function WatcherManagerOrganism({ watcherStatus }) { + const watcherStarted = watcherStatus === "Started"; + const handleWatcherToggle = () => { + ipcRenderer.send( + watcherStarted + ? ipcTypes.fileWatcher.toMain.stop + : ipcTypes.fileWatcher.toMain.start + ); + }; -export default function WatcherManagerOrganism() { return ( -
- Watcher Status - - - +
+
+ Watcher Status + + Start or stop the watcher without leaving settings. + +
+ + + +
); } + +export default connect(mapStateToProps)(WatcherManagerOrganism); diff --git a/src/components/pages/settings/settings.page.jsx b/src/components/pages/settings/settings.page.jsx index 2b0911b..7793e43 100644 --- a/src/components/pages/settings/settings.page.jsx +++ b/src/components/pages/settings/settings.page.jsx @@ -1,4 +1,4 @@ -import { Col, Row } from "antd"; +import { Card, Col, Row, Space, Typography } from "antd"; import React, { useEffect } from "react"; import ipcTypes from "../../../ipc.types"; import NotificationsToggleAtom from "../../atoms/notifications-toggle/notifications-toggle.atom"; @@ -7,6 +7,7 @@ import WatcherPollingMolecule from "../../molecules/watcher-polling/watcher-poll import FilePathsListOrganism from "../../organisms/filepaths-list/filepaths-list.organism"; import ShopSettingsOrganism from "../../organisms/shop-settings/shop-settings.organism"; import WatcherManagerOrganism from "../../organisms/watcher-manager/watcher-manager.organism"; +import "./settings.page.styles.scss"; const { ipcRenderer } = window; export default function SettingsPage() { @@ -15,20 +16,43 @@ export default function SettingsPage() { }, []); return ( -
- - - +
+
+ Settings + + Manage watcher behavior, notifications, and shop defaults in one compact workspace. + +
+ + + + + + - - - - - + + + + + + + Automation + + Fine-tune polling, startup behavior, and desktop notifications. + + + + + + + + - + + +
); } diff --git a/src/components/pages/settings/settings.page.styles.scss b/src/components/pages/settings/settings.page.styles.scss new file mode 100644 index 0000000..79afbf3 --- /dev/null +++ b/src/components/pages/settings/settings.page.styles.scss @@ -0,0 +1,192 @@ +.settings-page-container { + height: 100%; + overflow-y: auto; + display: flex; + flex-direction: column; + gap: 16px; + padding-bottom: 16px; +} + +.settings-page__hero { + padding: 18px 24px; + border-radius: 18px; + background: linear-gradient(135deg, #ffffff 0%, #f5f9ff 55%, #eef4ff 100%); + border: 1px solid #dbe7ff; + box-shadow: 0 10px 24px rgba(23, 43, 77, 0.06); + + .ant-typography { + margin-bottom: 0; + } + + .ant-typography + .ant-typography { + margin-top: 4px; + } +} + +.settings-page__side-stack { + width: 100%; +} + +.settings-page__side-stack > .ant-space-item, +.settings-page__controls > .ant-space-item { + width: 100%; +} + +.settings-page__card { + border-radius: 18px; + box-shadow: 0 10px 24px rgba(15, 23, 42, 0.06); + + .ant-card-body { + padding: 18px 20px; + } + + .ant-typography:last-child { + margin-bottom: 0; + } +} + +.settings-page__card--filepaths { + .ant-card-body { + padding-bottom: 14px; + } +} + +.settings-page__card--automation { + .ant-typography + .ant-typography { + margin-top: 2px; + } +} + +.settings-page__controls { + width: 100%; +} + +.settings-page__controls > .ant-space-item > * { + padding: 10px 12px; + border-radius: 12px; + background: #fafcff; + border: 1px solid #edf2ff; +} + +.settings-page__controls > .ant-space-item > * > div { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + flex-wrap: wrap; +} + +.settings-page__controls > .ant-space-item > * > div + div { + margin-top: 8px; +} + +.settings-page__controls > .ant-space-item > * > div > div:first-child { + flex: 1; + min-width: 0; +} + +.settings-page__controls .ant-input-number { + width: 96px; +} + +.settings-filepaths { + display: flex; + flex-direction: column; + gap: 14px; +} + +.settings-filepaths__header { + width: 100%; +} + +.settings-filepaths__header .ant-typography { + margin-bottom: 0; +} + +.settings-filepaths__list { + overflow: hidden; + border: 1px solid #edf2ff; + border-radius: 14px; + background: #fafcff; +} + +.settings-filepaths__list .ant-list-item { + padding: 12px 16px; +} + +.settings-filepaths__list .ant-list-empty-text { + padding: 28px 16px; +} + +.settings-filepaths__list .ant-empty { + margin-block: 8px; +} + +.settings-watcher-manager { + display: flex; + flex-direction: column; + gap: 12px; +} + +.settings-watcher-manager__header .ant-typography { + margin-bottom: 0; +} + +.settings-watcher-manager__content { + width: 100%; +} + +.settings-watcher-manager__toggle { + min-width: 112px; +} + +.settings-watcher-status-wrap { + display: flex; + flex-direction: column; + gap: 10px; +} + +.settings-watcher-status { + display: inline-flex; + align-items: center; + padding: 6px 12px; + border-radius: 999px; + border: 1px solid transparent; +} + +.settings-watcher-status--started { + color: #389e0d; + background: #f6ffed; + border-color: #b7eb8f; +} + +.settings-watcher-status--stopped { + color: #cf1322; + background: #fff1f0; + border-color: #ffa39e; +} + +.settings-watcher-status__error { + max-width: 100%; +} + +@media (max-width: 768px) { + .settings-page-container { + gap: 16px; + padding-bottom: 16px; + } + + .settings-page__hero, + .settings-page__card .ant-card-body { + padding: 20px; + } + + .settings-filepaths__header, + .settings-watcher-manager__content { + align-items: stretch !important; + } + + .settings-watcher-manager__toggle { + flex: 1; + } +} diff --git a/vite.config.js b/vite.config.js index 56cf54e..1a89bd5 100644 --- a/vite.config.js +++ b/vite.config.js @@ -19,7 +19,7 @@ export default defineConfig({ }, server: { host: true, - port: 3000, + port: 3006, open: true }, build: {