Skip to content

Commit

Permalink
fix: linting + ssh & api icons
Browse files Browse the repository at this point in the history
  • Loading branch information
he3als committed Nov 17, 2024
1 parent 6939add commit c95d6c4
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 118 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
!.env.example
.env*
.vagrant/
.vscode/
storage/framework/*
/.idea
/nbproject
Expand Down
3 changes: 3 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
}
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"prettier.endOfLine": "lf",
"editor.formatOnSave": true,
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
34 changes: 17 additions & 17 deletions resources/scripts/components/dashboard/AccountApiContainer.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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<ApiKey[]>([]);
Expand Down Expand Up @@ -46,12 +45,12 @@ export default () => {
return (
<PageContentBlock title={'Account API'}>
{/* Flash messages will now appear at the top of the page */}
<FlashMessageRender byKey="account" />
<div className="md:flex flex-nowrap my-10 space-x-8">
<ContentBox title={'Create API Key'} className="flex-none w-full md:w-1/2">
<FlashMessageRender byKey='account' />
<div className='md:flex flex-nowrap my-10 space-x-8'>
<ContentBox title={'Create API Key'} className='flex-none w-full md:w-1/2'>
<CreateApiKeyForm onKeyCreated={(key) => setKeys((s) => [...s!, key])} />
</ContentBox>
<ContentBox title={'API Keys'} className="flex-1 overflow-hidden mt-8 md:mt-0">
<ContentBox title={'API Keys'} className='flex-1 overflow-hidden mt-8 md:mt-0'>
<SpinnerOverlay visible={loading} />
<Dialog.Confirm
title={'Delete API Key'}
Expand All @@ -63,29 +62,30 @@ export default () => {
All requests using the <Code>{deleteIdentifier}</Code> key will be invalidated.
</Dialog.Confirm>
{keys.length === 0 ? (
<p className="text-center text-sm text-gray-500">
<p className='text-center text-sm text-gray-500'>
{loading ? 'Loading...' : 'No API keys exist for this account.'}
</p>
) : (
keys.map((key) => (
<div key={key.identifier} className="flex flex-col mb-6 space-y-4">
<div className="flex items-center justify-between space-x-4 border border-gray-300 rounded-lg p-4 transition duration-200">
<div className="flex-1">
<p className="text-sm font-medium">{key.description}</p>
<p className="text-xs text-gray-500 uppercase">
Last used: {key.lastUsedAt ? format(key.lastUsedAt, 'MMM d, yyyy HH:mm') : 'Never'}
<div key={key.identifier} className='flex flex-col mb-6 space-y-4'>
<div className='flex items-center justify-between space-x-4 border border-gray-300 rounded-lg p-4 transition duration-200'>
<div className='flex-1'>
<p className='text-sm font-medium'>{key.description}</p>
<p className='text-xs text-gray-500 uppercase'>
Last used:{' '}
{key.lastUsedAt ? format(key.lastUsedAt, 'MMM d, yyyy HH:mm') : 'Never'}
</p>
</div>
<p className="text-sm text-gray-600 hidden md:block">
<code className="font-mono py-1 px-2 bg-gray-800 rounded text-white">
<p className='text-sm text-gray-600 hidden md:block'>
<code className='font-mono py-1 px-2 bg-gray-800 rounded text-white'>
{key.identifier}
</code>
</p>
<button
className="p-2 text-red-500 hover:text-red-700"
className='p-2 text-red-500 hover:text-red-700'
onClick={() => setDeleteIdentifier(key.identifier)}
>
<FontAwesomeIcon icon={faTrashAlt} size="lg" />
<FontAwesomeIcon icon={faTrashAlt} size='lg' />
</button>
</div>
</div>
Expand Down
38 changes: 20 additions & 18 deletions resources/scripts/components/dashboard/ApiKeyModal.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -16,39 +17,40 @@ const ApiKeyModal = ({ apiKey }: Props) => {
const { dismiss } = useContext(ModalContext);

return (
<div className="p-6 space-y-6 max-w-lg mx-auto rounded-lg shadow-lg ">
<div className='p-6 space-y-6 max-w-lg mx-auto rounded-lg shadow-lg '>
{/* Flash message section */}
<FlashMessageRender byKey="account" />
<FlashMessageRender byKey='account' />

{/* Modal Header */}
<p className="text-sm text-white-600 mt-2 ">
The API key you have requested is shown below. Please store it in a safe place, as it will not be shown again.
<p className='text-sm text-white-600 mt-2 '>
The API key you have requested is shown below. Please store it in a safe place, as it will not be shown
again.
</p>

{/* API Key Display Section */}
<div className="relative mt-6">
<pre className="bg-gray-900 text-white p-4 rounded-lg font-mono overflow-x-auto">
<div className='relative mt-6'>
<pre className='bg-gray-900 text-white p-4 rounded-lg font-mono overflow-x-auto'>
<CopyOnClick text={apiKey}>
<code className="text-sm break-words">{apiKey}</code>
<code className='text-sm break-words'>{apiKey}</code>
</CopyOnClick>

{/* Copy button with icon */}
<div className="absolute top-2 right-2">
<div className='absolute top-2 right-2'>
<FontAwesomeIcon
icon={faClone}
size="lg"
className="text-gray-400 hover:text-gray-600 cursor-pointer"
size='lg'
className='text-gray-400 hover:text-gray-600 cursor-pointer'
/>
</div>
</pre>
</div>

{/* Action Buttons */}
<div className="flex justify-end space-x-4">
<div className='flex justify-end space-x-4'>
<Button
type="button"
type='button'
onClick={() => dismiss()}
className="bg-red-600 text-white hover:bg-red-700 px-6 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-gray-500"
className='bg-red-600 text-white hover:bg-red-700 px-6 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-gray-500'
>
Close
</Button>
Expand All @@ -61,6 +63,6 @@ ApiKeyModal.displayName = 'ApiKeyModal';

export default asModal<Props>({
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);
28 changes: 14 additions & 14 deletions resources/scripts/components/dashboard/forms/CreateApiKeyForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -45,7 +45,7 @@ export default ({ onKeyCreated }: { onKeyCreated: (key: ApiKey) => void }) => {
return (
<>
{/* Flash Messages */}
<FlashMessageRender byKey="account" />
<FlashMessageRender byKey='account' />

{/* Modal for API Key */}
<ApiKeyModal visible={apiKey.length > 0} onModalDismissed={() => setApiKey('')} apiKey={apiKey} />
Expand All @@ -60,33 +60,33 @@ export default ({ onKeyCreated }: { onKeyCreated: (key: ApiKey) => void }) => {
})}
>
{({ isSubmitting }) => (
<Form className="space-y-6">
<Form className='space-y-6'>
{/* Show spinner overlay when submitting */}
<SpinnerOverlay visible={isSubmitting} />

{/* Description Field */}
<FormikFieldWrapper
label="Description"
name="description"
description="A description of this API key."
label='Description'
name='description'
description='A description of this API key.'
>
<Field name="description" as={Input} />
<Field name='description' as={Input} />
</FormikFieldWrapper>

{/* Allowed IPs Field */}
<FormikFieldWrapper
label="Allowed IPs"
name="allowedIps"
description="Leave blank to allow any IP address to use this API key, otherwise provide each IP address on a new line."
label='Allowed IPs'
name='allowedIps'
description='Leave blank to allow any IP address to use this API key, otherwise provide each IP address on a new line.'
>
<Field name="allowedIps" as={Input} />
<Field name='allowedIps' as={Input} />
</FormikFieldWrapper>

{/* Submit Button below form fields */}
<div className="flex justify-end mt-6">
<div className='flex justify-end mt-6'>
<Button
type="submit"
className="bg-red-600 text-white hover:bg-red-700 px-6 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-gray-500"
type='submit'
className='bg-red-600 text-white hover:bg-red-700 px-6 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-gray-500'
disabled={isSubmitting}
>
{isSubmitting ? 'Creating...' : 'Create API Key'}
Expand Down
30 changes: 15 additions & 15 deletions resources/scripts/components/dashboard/ssh/AccountSSHContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { format } from 'date-fns';
import { useEffect, useState } from 'react';

import FlashMessageRender from '@/components/FlashMessageRender';
import CreateSSHKeyForm from '@/components/dashboard/ssh/CreateSSHKeyForm';
import DeleteSSHKeyButton from '@/components/dashboard/ssh/DeleteSSHKeyButton';
import Code from '@/components/elements/Code';
import ContentBox from '@/components/elements/ContentBox';
import PageContentBlock from '@/components/elements/PageContentBlock';
Expand All @@ -13,8 +15,6 @@ import { Dialog } from '@/components/elements/dialog';
import { useSSHKeys } from '@/api/account/ssh-keys';

import { useFlashKey } from '@/plugins/useFlash';
import DeleteSSHKeyButton from '@/components/dashboard/ssh/DeleteSSHKeyButton';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

export default () => {
const [deleteIdentifier, setDeleteIdentifier] = useState('');
Expand All @@ -36,14 +36,14 @@ export default () => {
return (
<PageContentBlock title={'SSH Keys'}>
<FlashMessageRender byKey={'account'} />
<div className="md:flex flex-nowrap my-10 space-x-8">
<div className='md:flex flex-nowrap my-10 space-x-8'>
{/* Create SSH Key Section */}
<ContentBox title={'Add SSH Key'} className="flex-none w-full md:w-1/2">
<ContentBox title={'Add SSH Key'} className='flex-none w-full md:w-1/2'>
<CreateSSHKeyForm />
</ContentBox>

{/* SSH Keys List Section */}
<ContentBox title={'SSH Keys'} className="flex-1 overflow-hidden mt-8 md:mt-0">
<ContentBox title={'SSH Keys'} className='flex-1 overflow-hidden mt-8 md:mt-0'>
<SpinnerOverlay visible={!data && isValidating} />
<Dialog.Confirm
title={'Delete SSH Key'}
Expand All @@ -55,29 +55,29 @@ export default () => {
Deleting this key will revoke access for any system using it.
</Dialog.Confirm>
{!data || data.length === 0 ? (
<p className="text-center text-sm text-gray-500">
<p className='text-center text-sm text-gray-500'>
{!data ? 'Loading...' : 'No SSH keys exist for this account.'}
</p>
) : (
data.map((key) => (
<div key={key.fingerprint} className="flex flex-col mb-6 space-y-4">
<div className="flex items-center justify-between space-x-4 border border-gray-300 rounded-lg p-4 transition duration-200">
<div className="flex-1">
<p className="text-sm font-medium">{key.name}</p>
<p className="text-xs text-gray-500 uppercase">
<div key={key.fingerprint} className='flex flex-col mb-6 space-y-4'>
<div className='flex items-center justify-between space-x-4 border border-gray-300 rounded-lg p-4 transition duration-200'>
<div className='flex-1'>
<p className='text-sm font-medium'>{key.name}</p>
<p className='text-xs text-gray-500 uppercase'>
Added on: {format(key.createdAt, 'MMM d, yyyy HH:mm')}
</p>
</div>
<p className="text-sm text-gray-600 hidden md:block">
<code className="font-mono py-1 px-2 bg-gray-800 rounded text-white">
<p className='text-sm text-gray-600 hidden md:block'>
<code className='font-mono py-1 px-2 bg-gray-800 rounded text-white'>
SHA256: {key.fingerprint}
</code>
</p>
<button
className="p-2 text-red-500 hover:text-red-700"
className='p-2 text-red-500 hover:text-red-700'
onClick={() => setDeleteIdentifier(key.fingerprint)}
>
<FontAwesomeIcon icon={faTrashAlt} size="lg" />
<FontAwesomeIcon icon={faTrashAlt} size='lg' />
</button>
</div>
</div>
Expand Down
Loading

0 comments on commit c95d6c4

Please sign in to comment.