From 27a7dd2fb93aba89ab6f05cb051cad23e39f83c7 Mon Sep 17 00:00:00 2001 From: Sean Edmunds Date: Fri, 21 Mar 2025 10:33:50 -0500 Subject: [PATCH] Updated WoL Settings --- .../components/Applications/AppItem.tsx | 6 +- .../Applications/AppSettingsItem.tsx | 74 ++++++ .../components/Applications/Applications.tsx | 162 ++++++------ .../Applications/DebouncedApplication.tsx | 59 +++-- .../components/Messages/DebouncedMessage.tsx | 2 +- .../settings/components/Messages/Messages.tsx | 7 +- .../components/WoL/DebouncedWolClient.tsx | 154 ++++++++++++ .../components/WoL/WolClientSettingsItem.tsx | 22 ++ .../settings/components/WoL/WolClients.tsx | 234 ++++++++++++++++-- src/styles/Box.module.css | 34 +++ src/styles/Card.module.css | 14 +- src/styles/index.ts | 4 +- 12 files changed, 637 insertions(+), 135 deletions(-) create mode 100644 src/pages/settings/components/Applications/AppSettingsItem.tsx create mode 100644 src/pages/settings/components/WoL/DebouncedWolClient.tsx create mode 100644 src/pages/settings/components/WoL/WolClientSettingsItem.tsx create mode 100644 src/styles/Box.module.css diff --git a/src/pages/homepage/components/Applications/AppItem.tsx b/src/pages/homepage/components/Applications/AppItem.tsx index 9cb2629..8c62c1e 100644 --- a/src/pages/homepage/components/Applications/AppItem.tsx +++ b/src/pages/homepage/components/Applications/AppItem.tsx @@ -4,14 +4,16 @@ import { useCommonHooks } from 'hooks'; import { useState } from 'react'; import { stackClasses, textClasses } from 'styles'; -function AppItem({ url, icon, name, linkDisabled }: any) { +function AppItem({ url, icon, name }: any) { const [textDecoration, setTextDecoration] = useState('none'); const [hover, setHover] = useState(false); const { isMobile } = useCommonHooks(); + const validUrl = + url.startsWith('http://') || url.startsWith('https://') ? url : `http://${url}`; return ( { setTextDecoration('underline'); setHover(true); diff --git a/src/pages/settings/components/Applications/AppSettingsItem.tsx b/src/pages/settings/components/Applications/AppSettingsItem.tsx new file mode 100644 index 0000000..e33cc35 --- /dev/null +++ b/src/pages/settings/components/Applications/AppSettingsItem.tsx @@ -0,0 +1,74 @@ +import { Icon } from '@iconify/react'; +import { Box, Stack, Text } from '@mantine/core'; +import { useCommonHooks } from 'hooks'; +import { useState } from 'react'; +import { boxClasses, textClasses } from 'styles'; + +function AppSettingsItem({ url, icon, name }: any) { + const [textDecoration, setTextDecoration] = useState('none'); + const [hover, setHover] = useState(false); + const { isMobile } = useCommonHooks(); + return ( + { + setTextDecoration('underline'); + setHover(true); + }} + onMouseOut={() => { + setTextDecoration('none'); + setHover(false); + }} + className={boxClasses.appItemBox} + > + {hover && ( + + + + )} + + + + + + {name} + + + {url} + + + + ); +} + +export default AppSettingsItem; diff --git a/src/pages/settings/components/Applications/Applications.tsx b/src/pages/settings/components/Applications/Applications.tsx index d2fd646..5ac3a8a 100644 --- a/src/pages/settings/components/Applications/Applications.tsx +++ b/src/pages/settings/components/Applications/Applications.tsx @@ -15,7 +15,6 @@ import { } from '@mantine/core'; import { useDebouncedValue, useDisclosure } from '@mantine/hooks'; import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; -import AppItem from 'pages/homepage/components/Applications/AppItem'; import { useEffect, useState } from 'react'; import { FiHelpCircle, FiPlus } from 'react-icons/fi'; import { @@ -25,6 +24,7 @@ import { textClasses, textInputClasses, } from 'styles'; +import AppSettingsItem from './AppSettingsItem'; import DebouncedApplication from './DebouncedApplication'; const ApplicationSettings = () => { @@ -34,9 +34,6 @@ const ApplicationSettings = () => { }); const [applicationData, setApplicationData] = useState([]); const { theme } = useCommonHooks(); - const [application, setApplication] = useState({}); - const [update, setUpdate] = useState({}); - const [debounced] = useDebouncedValue(update, 1000); const [newApplication, setNewApplication] = useState({ name: '', url: '', @@ -62,18 +59,6 @@ const ApplicationSettings = () => { } }, [apps, isAppsFetching, debouncedSearch]); - useEffect(() => { - if (Object.keys(debounced).length) { - mutateAsync({ method: 'PATCH', endpoint: endpoint, body: debounced }); - } - }, [debounced]); - - useEffect(() => { - if (update !== application && Object.keys(update).length > 0) { - setApplication(update); - } - }, [update]); - return ( { - { - setNewApplication({ - ...newApplication, - name: event.target.value, - }); - }} - /> - { - setNewApplication({ - ...newApplication, - url: event.target.value, - }); - }} - /> - { - setNewApplication({ - ...newApplication, - icon: event.target.value, - }); - }} - /> - { - setNewApplication({ - ...newApplication, - baseUrl: event.target.value, - }); - }} - /> - { - setNewApplication({ - ...newApplication, - filterName: event.target.value, - }); - }} - /> + + { + setNewApplication({ + ...newApplication, + name: event.target.value, + }); + }} + /> + { + setNewApplication({ + ...newApplication, + baseUrl: event.target.value, + }); + }} + /> + + + { + setNewApplication({ + ...newApplication, + url: event.target.value, + }); + }} + /> + + + { + setNewApplication({ + ...newApplication, + icon: event.target.value, + }); + }} + /> + { + setNewApplication({ + ...newApplication, + filterName: event.target.value, + }); + }} + /> + + + + + + + + + + { + openModal(); + }} + > + + + + + { + setUpdate({ + ...client, + hostname: event.target.value, + }); + }} + /> + { + setUpdate({ + ...client, + macAddress: event.target.value, + }); + }} + /> + + + ); +} + +export default DebouncedWolClient; diff --git a/src/pages/settings/components/WoL/WolClientSettingsItem.tsx b/src/pages/settings/components/WoL/WolClientSettingsItem.tsx new file mode 100644 index 0000000..8748c8a --- /dev/null +++ b/src/pages/settings/components/WoL/WolClientSettingsItem.tsx @@ -0,0 +1,22 @@ +import { Card, Stack, Text } from '@mantine/core'; +import { FaLaptop } from 'react-icons/fa'; +import { cardClasses } from 'styles'; + +function WolClientSettingsItem({ client }: any) { + return ( + + + + {client.hostname} + {client.macAddress} + + + ); +} + +export default WolClientSettingsItem; diff --git a/src/pages/settings/components/WoL/WolClients.tsx b/src/pages/settings/components/WoL/WolClients.tsx index c88447d..77a3082 100644 --- a/src/pages/settings/components/WoL/WolClients.tsx +++ b/src/pages/settings/components/WoL/WolClients.tsx @@ -1,8 +1,31 @@ -import { Stack, Text } from '@mantine/core'; -import { DataTable, WolClientColumns } from 'components'; -import { useQueryAPI } from 'hooks'; +import { + ActionIcon, + Box, + Button, + Divider, + Grid, + GridCol, + Group, + Highlight, + Modal, + Popover, + Stack, + Text, + TextInput, +} from '@mantine/core'; +import { useDebouncedValue, useDisclosure } from '@mantine/hooks'; +import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; import { useEffect, useState } from 'react'; -import { textClasses } from 'styles'; +import { FiHelpCircle, FiPlus } from 'react-icons/fi'; +import { + actionIconClasses, + buttonClasses, + modalClasses, + textClasses, + textInputClasses, +} from 'styles'; +import DebouncedWolClient from './DebouncedWolClient'; +import WolClientSettingsItem from './WolClientSettingsItem'; const WolClientSettings = () => { const endpoint = 'api/wolClients'; @@ -15,26 +38,201 @@ const WolClientSettings = () => { endpoint: endpoint, }); const [wolClients, setWolClients] = useState([]); - + const { mutateAsync } = useMutationAPI(); + const { theme } = useCommonHooks(); + const [newWolClient, setNewWolClient] = useState({ + name: '', + url: '', + icon: '', + baseUrl: '', + filterName: '', + }); + const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); + const [searchValue, setSearchValue] = useState(''); + const [debouncedSearch] = useDebouncedValue(searchValue, 500); + const handleDelete = (application: any) => { + mutateAsync({ method: 'DELETE', endpoint: endpoint, body: application }); + }; useEffect(() => { if (wolClientsData && wolClientsIsFetched) { - setWolClients(wolClientsData); + setWolClients( + wolClientsData.filter((a: any) => + a.hostname.toLowerCase().includes(debouncedSearch.toLowerCase()), + ), + ); } - }, [wolClientsData, wolClientsIsFetched]); + }, [wolClientsData, wolClientsIsFetched, debouncedSearch]); return ( - - WoL Clients - - + { + closeModal(); + }} + style={{ + '--color-text-pri': theme.primaryColor, + '--color-text-acc': theme.accentColor, + '--color-background': theme.backgroundColor, + '--color-border': theme.borderColor, + '--color-search-background': theme.searchColor, + '--image-background': `url(${theme.backgroundImage})`, + }} + closeOnEscape + closeOnClickOutside + > + + + + Add a new application + + + + + + { + setNewWolClient({ + ...newWolClient, + hostname: event.target.value, + }); + }} + /> + { + setNewWolClient({ + ...newWolClient, + macAddress: event.target.value, + }); + }} + /> + + + + + + + + + + + + + WoL Clients + + + + + + + + + + + {'Wake on Lan clients can be configured here.'} + + + {'Clients can be powered on from the settings button the homepage.'} + + + + + + { + setSearchValue(event.target.value); + }} + /> + + + + {wolClients?.map((client: any) => ( + + + + { + e.stopPropagation(); + }} + > + + + + + + + + + ))} + + ); }; diff --git a/src/styles/Box.module.css b/src/styles/Box.module.css new file mode 100644 index 0000000..c0daae2 --- /dev/null +++ b/src/styles/Box.module.css @@ -0,0 +1,34 @@ +.appItemBox { + display: flex; + flex-direction: row; + flex-wrap: wrap; + height: 128px; + margin: 0; + backdrop-filter: blur(10px) brightness(1.2); + border-radius: 6px; + font-size: 2em; + font-weight: 400; + text-transform: uppercase; +} + +.appItemBox rect { + border-radius: 6px; + stroke-dasharray: 260; + stroke-width: 10px; + fill: transparent; + stroke: var(--color-search-background); + animation: svgAnimation 1.5s linear infinite; +} + +.appItemBox rect::after { + filter: blur(10px); +} + +@keyframes svgAnimation { + from { + stroke-dashoffset: 0; + } + to { + stroke-dashoffset: 1000; + } +} \ No newline at end of file diff --git a/src/styles/Card.module.css b/src/styles/Card.module.css index e85516f..dd30f94 100644 --- a/src/styles/Card.module.css +++ b/src/styles/Card.module.css @@ -2,6 +2,18 @@ &.root { color: var(--color-text-pri); background-color: transparent; - backdrop-filter: blur(10px) brightness(0.75) !important; + backdrop-filter: blur(10px) brightness(1.25) !important; } } + +.settingsItemHover { + &.root { + color: var(--color-text-pri); + background-color: transparent; + backdrop-filter: blur(10px) brightness(1.25) !important; + cursor: pointer; + &:hover { + color: var(--color-text-acc); + } + } +} \ No newline at end of file diff --git a/src/styles/index.ts b/src/styles/index.ts index 30d41dd..06bb626 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1,4 +1,5 @@ import actionIconClasses from './ActionIcon.module.css'; +import boxClasses from './Box.module.css'; import buttonClasses from './Button.module.css'; import cardClasses from './Card.module.css'; import menuClasses from './Menu.module.css'; @@ -14,8 +15,9 @@ import textInputClasses from './TextInput.module.css'; export { actionIconClasses, - cardClasses, + boxClasses, buttonClasses, + cardClasses, menuClasses, modalClasses, multiSelectClasses,