Skip to content

Commit bcf0a05

Browse files
committed
Support textareas and cleanup API page
1 parent baf35be commit bcf0a05

File tree

5 files changed

+53
-41
lines changed

5 files changed

+53
-41
lines changed

resources/scripts/components/dashboard/AccountApiContainer.tsx

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import FlashMessageRender from '@/components/FlashMessageRender';
1414
import { httpErrorToHuman } from '@/api/http';
1515
import format from 'date-fns/format';
1616
import PageContentBlock from '@/components/elements/PageContentBlock';
17+
import tw from 'twin.macro';
18+
import GreyRowBox from '@/components/elements/GreyRowBox';
1719

1820
export default () => {
1921
const [ deleteIdentifier, setDeleteIdentifier ] = useState('');
@@ -48,18 +50,18 @@ export default () => {
4850

4951
return (
5052
<PageContentBlock>
51-
<FlashMessageRender byKey={'account'} className={'mb-4'}/>
52-
<div className={'flex'}>
53-
<ContentBox title={'Create API Key'} className={'flex-1'}>
53+
<FlashMessageRender byKey={'account'} css={tw`mb-4`}/>
54+
<div css={tw`flex`}>
55+
<ContentBox title={'Create API Key'} css={tw`flex-1`}>
5456
<CreateApiKeyForm onKeyCreated={key => setKeys(s => ([ ...s!, key ]))}/>
5557
</ContentBox>
56-
<ContentBox title={'API Keys'} className={'ml-10 flex-1'}>
58+
<ContentBox title={'API Keys'} css={tw`ml-10 flex-1`}>
5759
<SpinnerOverlay visible={loading}/>
5860
{deleteIdentifier &&
5961
<ConfirmationModal
62+
visible
6063
title={'Confirm key deletion'}
6164
buttonText={'Yes, delete key'}
62-
visible={true}
6365
onConfirmed={() => {
6466
doDeletion(deleteIdentifier);
6567
setDeleteIdentifier('');
@@ -72,38 +74,38 @@ export default () => {
7274
}
7375
{
7476
keys.length === 0 ?
75-
<p className={'text-center text-sm'}>
77+
<p css={tw`text-center text-sm`}>
7678
{loading ? 'Loading...' : 'No API keys exist for this account.'}
7779
</p>
7880
:
79-
keys.map(key => (
80-
<div
81+
keys.map((key, index) => (
82+
<GreyRowBox
8183
key={key.identifier}
82-
className={'grey-row-box bg-neutral-600 mb-2 flex items-center'}
84+
css={[ tw`bg-neutral-600 flex items-center`, index > 0 && tw`mt-2` ]}
8385
>
84-
<FontAwesomeIcon icon={faKey} className={'text-neutral-300'}/>
85-
<div className={'ml-4 flex-1'}>
86-
<p className={'text-sm'}>{key.description}</p>
87-
<p className={'text-2xs text-neutral-300 uppercase'}>
88-
Last
89-
used: {key.lastUsedAt ? format(key.lastUsedAt, 'MMM Do, YYYY HH:mm') : 'Never'}
86+
<FontAwesomeIcon icon={faKey} css={tw`text-neutral-300`}/>
87+
<div css={tw`ml-4 flex-1`}>
88+
<p css={tw`text-sm`}>{key.description}</p>
89+
<p css={tw`text-2xs text-neutral-300 uppercase`}>
90+
Last used:&nbsp;
91+
{key.lastUsedAt ? format(key.lastUsedAt, 'MMM do, yyyy HH:mm') : 'Never'}
9092
</p>
9193
</div>
92-
<p className={'text-sm ml-4'}>
93-
<code className={'font-mono py-1 px-2 bg-neutral-900 rounded'}>
94+
<p css={tw`text-sm ml-4`}>
95+
<code css={tw`font-mono py-1 px-2 bg-neutral-900 rounded`}>
9496
{key.identifier}
9597
</code>
9698
</p>
9799
<button
98-
className={'ml-4 p-2 text-sm'}
100+
css={tw`ml-4 p-2 text-sm`}
99101
onClick={() => setDeleteIdentifier(key.identifier)}
100102
>
101103
<FontAwesomeIcon
102104
icon={faTrashAlt}
103-
className={'text-neutral-400 hover:text-red-400 transition-colors duration-150'}
105+
css={tw`text-neutral-400 hover:text-red-400 transition-colors duration-150`}
104106
/>
105107
</button>
106-
</div>
108+
</GreyRowBox>
107109
))
108110
}
109111
</ContentBox>

resources/scripts/components/dashboard/forms/CreateApiKeyForm.tsx

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import { ApplicationStore } from '@/state';
99
import { httpErrorToHuman } from '@/api/http';
1010
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
1111
import { ApiKey } from '@/api/account/getApiKeys';
12+
import tw from 'twin.macro';
13+
import Button from '@/components/elements/Button';
14+
import Input, { Textarea } from '@/components/elements/Input';
1215

1316
interface Values {
1417
description: string;
@@ -44,22 +47,21 @@ export default ({ onKeyCreated }: { onKeyCreated: (key: ApiKey) => void }) => {
4447
closeOnEscape={false}
4548
closeOnBackground={false}
4649
>
47-
<h3 className={'mb-6'}>Your API Key</h3>
48-
<p className={'text-sm mb-6'}>
50+
<h3 css={tw`mb-6`}>Your API Key</h3>
51+
<p css={tw`text-sm mb-6`}>
4952
The API key you have requested is shown below. Please store this in a safe location, it will not be
5053
shown again.
5154
</p>
52-
<pre className={'text-sm bg-neutral-900 rounded py-2 px-4 font-mono'}>
53-
<code className={'font-mono'}>{apiKey}</code>
55+
<pre css={tw`text-sm bg-neutral-900 rounded py-2 px-4 font-mono`}>
56+
<code css={tw`font-mono`}>{apiKey}</code>
5457
</pre>
55-
<div className={'flex justify-end mt-6'}>
56-
<button
58+
<div css={tw`flex justify-end mt-6`}>
59+
<Button
5760
type={'button'}
58-
className={'btn btn-secondary btn-sm'}
5961
onClick={() => setApiKey('')}
6062
>
6163
Close
62-
</button>
64+
</Button>
6365
</div>
6466
</Modal>
6567
<Formik
@@ -80,25 +82,19 @@ export default ({ onKeyCreated }: { onKeyCreated: (key: ApiKey) => void }) => {
8082
label={'Description'}
8183
name={'description'}
8284
description={'A description of this API key.'}
83-
className={'mb-6'}
85+
css={tw`mb-6`}
8486
>
85-
<Field name={'description'} className={'input-dark'}/>
87+
<Field name={'description'} as={Input}/>
8688
</FormikFieldWrapper>
8789
<FormikFieldWrapper
8890
label={'Allowed IPs'}
8991
name={'allowedIps'}
9092
description={'Leave blank to allow any IP address to use this API key, otherwise provide each IP address on a new line.'}
9193
>
92-
<Field
93-
as={'textarea'}
94-
name={'allowedIps'}
95-
className={'input-dark h-32'}
96-
/>
94+
<Field as={Textarea} name={'allowedIps'} css={tw`h-32`}/>
9795
</FormikFieldWrapper>
98-
<div className={'flex justify-end mt-6'}>
99-
<button className={'btn btn-primary btn-sm'}>
100-
Create
101-
</button>
96+
<div css={tw`flex justify-end mt-6`}>
97+
<Button>Create</Button>
10298
</div>
10399
</Form>
104100
)}

resources/scripts/components/elements/Input.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const light = css<Props>`
1616
}
1717
`;
1818

19-
const Input = styled.input<Props>`
19+
const inputStyle = css<Props>`
2020
// Reset to normal styling.
2121
${tw`appearance-none w-full min-w-0`};
2222
${tw`p-3 border rounded text-sm transition-all duration-150`};
@@ -43,4 +43,8 @@ const Input = styled.input<Props>`
4343
${props => props.isLight && light};
4444
`;
4545

46+
const Input = styled.input<Props>`${inputStyle}`;
47+
const Textarea = styled.textarea<Props>`${inputStyle}`;
48+
49+
export { Textarea };
4650
export default Input;

resources/scripts/components/elements/PageContentBlock.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import ContentContainer from '@/components/elements/ContentContainer';
33
import { CSSTransition } from 'react-transition-group';
44
import tw from 'twin.macro';
55

6-
export default ({ children }): React.FC => (
6+
const PageContentBlock: React.FC = ({ children }) => (
77
<CSSTransition timeout={250} classNames={'fade'} appear in>
88
<>
99
<ContentContainer css={tw`my-10`}>
@@ -25,3 +25,5 @@ export default ({ children }): React.FC => (
2525
</>
2626
</CSSTransition>
2727
);
28+
29+
export default PageContentBlock;

tailwind.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,13 @@ module.exports = {
112112
900: 'hsl(125, 97%, 14%)',
113113
},
114114
},
115+
extend: {
116+
fontSize: {
117+
'2xs': '0.625rem',
118+
},
119+
borderColor: theme => ({
120+
default: theme('colors.neutral.400', 'cuurrentColor'),
121+
}),
122+
},
115123
},
116124
};

0 commit comments

Comments
 (0)