diff --git a/.gitignore b/.gitignore index d72450a45..8ce1380b1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ !.env.example .env* .vagrant/ -.vscode/ storage/framework/* /.idea /nbproject diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..00500d00b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..91e51467f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "prettier.endOfLine": "lf", + "editor.formatOnSave": true, + "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"], + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + } +} diff --git a/resources/scripts/components/auth/ForgotPasswordContainer.tsx b/resources/scripts/components/auth/ForgotPasswordContainer.tsx index e8fa5d550..6c419b936 100644 --- a/resources/scripts/components/auth/ForgotPasswordContainer.tsx +++ b/resources/scripts/components/auth/ForgotPasswordContainer.tsx @@ -13,6 +13,7 @@ import requestPasswordResetEmail from '@/api/auth/requestPasswordResetEmail'; import { httpErrorToHuman } from '@/api/http'; import useFlash from '@/plugins/useFlash'; + import Logo from '../elements/PyroLogo'; interface Values { diff --git a/resources/scripts/components/dashboard/AccountApiContainer.tsx b/resources/scripts/components/dashboard/AccountApiContainer.tsx index 9c976dda3..d9db7a24a 100644 --- a/resources/scripts/components/dashboard/AccountApiContainer.tsx +++ b/resources/scripts/components/dashboard/AccountApiContainer.tsx @@ -1,4 +1,5 @@ import { faTrashAlt } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { format } from 'date-fns'; import { useEffect, useState } from 'react'; @@ -15,8 +16,6 @@ import getApiKeys, { ApiKey } from '@/api/account/getApiKeys'; import { useFlashKey } from '@/plugins/useFlash'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; - export default () => { const [deleteIdentifier, setDeleteIdentifier] = useState(''); const [keys, setKeys] = useState([]); @@ -46,12 +45,12 @@ export default () => { return ( {/* Flash messages will now appear at the top of the page */} - -
- + +
+ setKeys((s) => [...s!, key])} /> - + { All requests using the {deleteIdentifier} key will be invalidated. {keys.length === 0 ? ( -

+

{loading ? 'Loading...' : 'No API keys exist for this account.'}

) : ( keys.map((key) => ( -
-
-
-

{key.description}

-

- Last used: {key.lastUsedAt ? format(key.lastUsedAt, 'MMM d, yyyy HH:mm') : 'Never'} +

+
+
+

{key.description}

+

+ Last used:{' '} + {key.lastUsedAt ? format(key.lastUsedAt, 'MMM d, yyyy HH:mm') : 'Never'}

-

- +

+ {key.identifier}

diff --git a/resources/scripts/components/dashboard/ApiKeyModal.tsx b/resources/scripts/components/dashboard/ApiKeyModal.tsx index 8528adfdf..eb16b78aa 100644 --- a/resources/scripts/components/dashboard/ApiKeyModal.tsx +++ b/resources/scripts/components/dashboard/ApiKeyModal.tsx @@ -1,11 +1,12 @@ -import { faClone } from '@fortawesome/free-solid-svg-icons'; -import { useContext } from 'react'; import ModalContext from '@/context/ModalContext'; +import { faClone } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useContext } from 'react'; +import FlashMessageRender from '@/components/FlashMessageRender'; import Button from '@/components/elements/Button'; import CopyOnClick from '@/components/elements/CopyOnClick'; -import FlashMessageRender from '@/components/FlashMessageRender'; + import asModal from '@/hoc/asModal'; interface Props { @@ -16,39 +17,40 @@ const ApiKeyModal = ({ apiKey }: Props) => { const { dismiss } = useContext(ModalContext); return ( -
+
{/* Flash message section */} - + {/* Modal Header */} -

- The API key you have requested is shown below. Please store it in a safe place, as it will not be shown again. +

+ The API key you have requested is shown below. Please store it in a safe place, as it will not be shown + again.

{/* API Key Display Section */} -
-
+            
+
                     
-                        {apiKey}
+                        {apiKey}
                     
 
                     {/* Copy button with icon */}
-                    
+
{/* Action Buttons */} -
+
@@ -61,6 +63,6 @@ ApiKeyModal.displayName = 'ApiKeyModal'; export default asModal({ title: 'Your API Key', - closeOnEscape: true, // Allows closing the modal by pressing Escape - closeOnBackground: true, // Allows closing by clicking outside the modal + closeOnEscape: true, // Allows closing the modal by pressing Escape + closeOnBackground: true, // Allows closing by clicking outside the modal })(ApiKeyModal); diff --git a/resources/scripts/components/dashboard/forms/CreateApiKeyForm.tsx b/resources/scripts/components/dashboard/forms/CreateApiKeyForm.tsx index cb9710504..870e8e653 100644 --- a/resources/scripts/components/dashboard/forms/CreateApiKeyForm.tsx +++ b/resources/scripts/components/dashboard/forms/CreateApiKeyForm.tsx @@ -3,12 +3,12 @@ import { Field, Form, Formik, FormikHelpers } from 'formik'; import { useState } from 'react'; import { object, string } from 'yup'; +import FlashMessageRender from '@/components/FlashMessageRender'; import ApiKeyModal from '@/components/dashboard/ApiKeyModal'; import Button from '@/components/elements/Button'; import FormikFieldWrapper from '@/components/elements/FormikFieldWrapper'; import Input from '@/components/elements/Input'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; -import FlashMessageRender from '@/components/FlashMessageRender'; import createApiKey from '@/api/account/createApiKey'; import { ApiKey } from '@/api/account/getApiKeys'; @@ -45,7 +45,7 @@ export default ({ onKeyCreated }: { onKeyCreated: (key: ApiKey) => void }) => { return ( <> {/* Flash Messages */} - + {/* Modal for API Key */} 0} onModalDismissed={() => setApiKey('')} apiKey={apiKey} /> @@ -60,33 +60,33 @@ export default ({ onKeyCreated }: { onKeyCreated: (key: ApiKey) => void }) => { })} > {({ isSubmitting }) => ( -
+ {/* Show spinner overlay when submitting */} {/* Description Field */} - + {/* Allowed IPs Field */} - + {/* Submit Button below form fields */} -
+
diff --git a/resources/scripts/components/dashboard/ssh/CreateSSHKeyForm.tsx b/resources/scripts/components/dashboard/ssh/CreateSSHKeyForm.tsx index f0ecc4a52..b4d517c61 100644 --- a/resources/scripts/components/dashboard/ssh/CreateSSHKeyForm.tsx +++ b/resources/scripts/components/dashboard/ssh/CreateSSHKeyForm.tsx @@ -3,11 +3,11 @@ import { Field, Form, Formik, FormikHelpers } from 'formik'; import { useState } from 'react'; import { object, string } from 'yup'; +import FlashMessageRender from '@/components/FlashMessageRender'; import Button from '@/components/elements/Button'; import FormikFieldWrapper from '@/components/elements/FormikFieldWrapper'; import Input from '@/components/elements/Input'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; -import FlashMessageRender from '@/components/FlashMessageRender'; import { createSSHKey } from '@/api/account/ssh-keys'; import { useSSHKeys } from '@/api/account/ssh-keys'; @@ -32,7 +32,7 @@ export default () => { resetForm(); setSubmitting(false); setSshKey(`${key.name}`); - mutate((data) => (data || []).concat(key)); // Update the list of SSH keys after creation + mutate((data) => (data || []).concat(key)); // Update the list of SSH keys after creation }) .catch((error) => { console.error(error); @@ -44,7 +44,7 @@ export default () => { return ( <> {/* Flash Messages */} - + {/* Modal for SSH Key */} {/* Add your modal logic here to display the SSH key details after creation */} @@ -59,33 +59,33 @@ export default () => { })} > {({ isSubmitting }) => ( - + {/* Show spinner overlay when submitting */} {/* SSH Key Name Field */} - + {/* Public Key Field */} - + {/* Submit Button below form fields */} -
+
+ ); }; diff --git a/resources/scripts/components/elements/hugeicons/Api.tsx b/resources/scripts/components/elements/hugeicons/Api.tsx index be3ae72d3..1c8552521 100644 --- a/resources/scripts/components/elements/hugeicons/Api.tsx +++ b/resources/scripts/components/elements/hugeicons/Api.tsx @@ -2,12 +2,36 @@ import { HugeIconProps } from './props'; const HugeIconsApi = (props: HugeIconProps) => { return ( - - - - - - + + + + + + ); }; diff --git a/resources/scripts/components/elements/hugeicons/Ssh.tsx b/resources/scripts/components/elements/hugeicons/Ssh.tsx index f3e246db0..5a7183b7d 100644 --- a/resources/scripts/components/elements/hugeicons/Ssh.tsx +++ b/resources/scripts/components/elements/hugeicons/Ssh.tsx @@ -2,10 +2,30 @@ import { HugeIconProps } from './props'; const HugeIconsSsh = (props: HugeIconProps) => { return ( - - - - + + + + ); }; diff --git a/resources/scripts/components/server/users/RemoveSubuserButton.tsx b/resources/scripts/components/server/users/RemoveSubuserButton.tsx index 6632a2320..0ea49846a 100644 --- a/resources/scripts/components/server/users/RemoveSubuserButton.tsx +++ b/resources/scripts/components/server/users/RemoveSubuserButton.tsx @@ -1,3 +1,5 @@ +import { faTrashAlt } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Actions, useStoreActions } from 'easy-peasy'; import { useState } from 'react'; @@ -9,8 +11,6 @@ import deleteSubuser from '@/api/server/users/deleteSubuser'; import { ApplicationStore } from '@/state'; import { ServerContext } from '@/state/server'; import { Subuser } from '@/state/server/subusers'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faTrashAlt } from '@fortawesome/free-solid-svg-icons'; export default ({ subuser }: { subuser: Subuser }) => { const [loading, setLoading] = useState(false); diff --git a/resources/scripts/routers/DashboardRouter.tsx b/resources/scripts/routers/DashboardRouter.tsx index ad1209b0c..7fab63150 100644 --- a/resources/scripts/routers/DashboardRouter.tsx +++ b/resources/scripts/routers/DashboardRouter.tsx @@ -16,24 +16,21 @@ import MainSidebar from '@/components/elements/MainSidebar'; import MainWrapper from '@/components/elements/MainWrapper'; import Logo from '@/components/elements/PyroLogo'; import { NotFound } from '@/components/elements/ScreenBlock'; +import HugeIconsApi from '@/components/elements/hugeicons/Api'; import HugeIconsDashboardSettings from '@/components/elements/hugeicons/DashboardSettings'; import HugeIconsHome from '@/components/elements/hugeicons/Home'; -import HugeIconsApi from '@/components/elements/hugeicons/Api'; import HugeIconsSsh from '@/components/elements/hugeicons/Ssh'; import http from '@/api/http'; - - - export default () => { const location = useLocation(); const rootAdmin = useStoreState((state) => state.user.data!.rootAdmin); - const [isSidebarVisible, setSidebarVisible] = useState(false); + const [isSidebarVisible, setSidebarVisible] = useState(false); const toggleSidebar = () => { - setSidebarVisible(!isSidebarVisible); // Toggle sidebar visibility + setSidebarVisible(!isSidebarVisible); // Toggle sidebar visibility }; const onTriggerLogout = () => { @@ -72,7 +69,6 @@ export default () => { return '0'; }; - const top = calculateTop(location.pathname); const [height, setHeight] = useState('40px'); @@ -83,21 +79,28 @@ export default () => { return () => clearTimeout(timeoutId); }, [top]); - - - - return ( @@ -163,7 +166,7 @@ export default () => { -

Api Keys

+

API Keys

@@ -173,9 +176,7 @@ export default () => {

Settings

- - @@ -201,7 +202,6 @@ export default () => { -
- ); - + + ); };