ui(admin): update button components, fix Editor for eggs

This commit is contained in:
Matthew Penner 2022-12-21 14:27:50 -07:00
parent 4e56f6dbea
commit 089860b721
No known key found for this signature in database
35 changed files with 363 additions and 623 deletions

View file

@ -35,7 +35,7 @@ interface PropsWithoutIcon extends Props {
}
export const SubNavigationLink = ({ to, name, icon: IconComponent, children }: PropsWithIcon | PropsWithoutIcon) => (
<NavLink to={to}>
<NavLink to={to} end>
{IconComponent ? <IconComponent /> : children}
{name}
</NavLink>

View file

@ -1,9 +1,11 @@
import { Actions, useStoreActions } from 'easy-peasy';
import type { Actions } from 'easy-peasy';
import { useStoreActions } from 'easy-peasy';
import { useState } from 'react';
import tw from 'twin.macro';
import deleteDatabase from '@/api/admin/databases/deleteDatabase';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import { Shape } from '@/components/elements/button/types';
import ConfirmationModal from '@/components/elements/ConfirmationModal';
import type { ApplicationStore } from '@/state';
@ -52,7 +54,7 @@ export default ({ databaseId, onDeleted }: Props) => {
created on this host but not the databases themselves.
</ConfirmationModal>
<Button type={'button'} size={'xsmall'} color={'red'} onClick={() => setVisible(true)}>
<Button.Danger type="button" shape={Shape.IconSquare} onClick={() => setVisible(true)}>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
@ -67,7 +69,7 @@ export default ({ databaseId, onDeleted }: Props) => {
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</Button>
</Button.Danger>
</>
);
};

View file

@ -14,7 +14,7 @@ import AdminContentBlock from '@/components/admin/AdminContentBlock';
import Spinner from '@/components/elements/Spinner';
import FlashMessageRender from '@/components/FlashMessageRender';
import AdminBox from '@/components/admin/AdminBox';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import Field from '@/components/elements/Field';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import DatabaseDeleteButton from '@/components/admin/databases/DatabaseDeleteButton';
@ -115,7 +115,7 @@ export const InformationContainer = ({ title, initialValues, children, onSubmit
<div css={tw`w-full flex flex-row items-center mt-6`}>
{children}
<div css={tw`flex ml-auto`}>
<Button type={'submit'} disabled={isSubmitting || !isValid}>
<Button type="submit" disabled={isSubmitting || !isValid}>
Save Changes
</Button>
</div>

View file

@ -10,17 +10,18 @@ import FlashMessageRender from '@/components/FlashMessageRender';
import AdminCheckbox from '@/components/admin/AdminCheckbox';
import AdminContentBlock from '@/components/admin/AdminContentBlock';
import AdminTable, {
ContentWrapper,
Loading,
NoItems,
Pagination,
TableBody,
TableHead,
TableHeader,
TableRow,
Pagination,
Loading,
NoItems,
ContentWrapper,
useTableHooks,
} from '@/components/admin/AdminTable';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import { Size } from '@/components/elements/button/types';
import CopyOnClick from '@/components/elements/CopyOnClick';
const RowCheckbox = ({ id }: { id: number }) => {
@ -93,7 +94,7 @@ const DatabasesContainer = () => {
<div css={tw`flex ml-auto pl-4`}>
<NavLink to="/admin/databases/new">
<Button type={'button'} size={'large'} css={tw`h-10 px-4 py-0 whitespace-nowrap`}>
<Button type="button" size={Size.Large} css={tw`h-10 px-4 py-0 whitespace-nowrap`}>
New Database Host
</Button>
</NavLink>

View file

@ -4,7 +4,8 @@ import { useState } from 'react';
import tw from 'twin.macro';
import deleteLocation from '@/api/admin/locations/deleteLocation';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import { Shape } from '@/components/elements/button/types';
import ConfirmationModal from '@/components/elements/ConfirmationModal';
import type { ApplicationStore } from '@/state';
@ -53,7 +54,7 @@ export default ({ locationId, onDeleted }: Props) => {
to it.
</ConfirmationModal>
<Button type={'button'} size={'xsmall'} color={'red'} onClick={() => setVisible(true)}>
<Button.Danger type="button" shape={Shape.IconSquare} onClick={() => setVisible(true)}>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
@ -68,7 +69,7 @@ export default ({ locationId, onDeleted }: Props) => {
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</Button>
</Button.Danger>
</>
);
};

View file

@ -13,7 +13,7 @@ import updateLocation from '@/api/admin/locations/updateLocation';
import AdminBox from '@/components/admin/AdminBox';
import AdminContentBlock from '@/components/admin/AdminContentBlock';
import LocationDeleteButton from '@/components/admin/locations/LocationDeleteButton';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import Field from '@/components/elements/Field';
import Spinner from '@/components/elements/Spinner';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
@ -99,7 +99,7 @@ const EditInformationContainer = () => {
</div>
<div css={tw`flex ml-auto`}>
<Button type={'submit'} disabled={isSubmitting || !isValid}>
<Button type="submit" disabled={isSubmitting || !isValid}>
Save Changes
</Button>
</div>

View file

@ -24,7 +24,7 @@ import FlashMessageRender from '@/components/FlashMessageRender';
import useFlash from '@/plugins/useFlash';
import { AdminContext } from '@/state/admin';
const RowCheckbox = ({ id }: { id: number }) => {
function RowCheckbox({ id }: { id: number }) {
const isChecked = AdminContext.useStoreState(state => state.locations.selectedLocations.indexOf(id) >= 0);
const appendSelectedLocation = AdminContext.useStoreActions(actions => actions.locations.appendSelectedLocation);
const removeSelectedLocation = AdminContext.useStoreActions(actions => actions.locations.removeSelectedLocation);
@ -42,9 +42,9 @@ const RowCheckbox = ({ id }: { id: number }) => {
}}
/>
);
};
}
const LocationsContainer = () => {
function LocationsContainer() {
const { page, setPage, setFilters, sort, setSort, sortDirection } = useContext(LocationsContext);
const { clearFlashes, clearAndAddHttpError } = useFlash();
const { data: locations, error, isValidating } = getLocations();
@ -173,7 +173,7 @@ const LocationsContainer = () => {
</AdminTable>
</AdminContentBlock>
);
};
}
export default () => {
const hooks = useTableHooks<Filters>();

View file

@ -6,7 +6,8 @@ import { object, string } from 'yup';
import createLocation from '@/api/admin/locations/createLocation';
import getLocations from '@/api/admin/locations/getLocations';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import { Size, Variant } from '@/components/elements/button/types';
import Field from '@/components/elements/Field';
import Modal from '@/components/elements/Modal';
import FlashMessageRender from '@/components/FlashMessageRender';
@ -82,14 +83,14 @@ export default () => {
</div>
<div css={tw`flex flex-wrap justify-end mt-6`}>
<Button
type={'button'}
isSecondary
<Button.Text
type="button"
variant={Variant.Secondary}
css={tw`w-full sm:w-auto sm:mr-2`}
onClick={() => setVisible(false)}
>
Cancel
</Button>
</Button.Text>
<Button css={tw`w-full mt-4 sm:w-auto sm:mt-0`} type={'submit'}>
Create Location
</Button>
@ -100,8 +101,8 @@ export default () => {
</Formik>
<Button
type={'button'}
size={'large'}
type="button"
size={Size.Large}
css={tw`h-10 px-4 py-0 whitespace-nowrap`}
onClick={() => setVisible(true)}
>

View file

@ -4,7 +4,7 @@ import { useState } from 'react';
import tw from 'twin.macro';
import deleteMount from '@/api/admin/mounts/deleteMount';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import ConfirmationModal from '@/components/elements/ConfirmationModal';
import type { ApplicationStore } from '@/state';
@ -52,7 +52,7 @@ export default ({ mountId, onDeleted }: Props) => {
Are you sure you want to delete this mount? Deleting a mount will not delete files on any nodes.
</ConfirmationModal>
<Button type={'button'} size={'xsmall'} color={'red'} onClick={() => setVisible(true)}>
<Button.Danger type="button" onClick={() => setVisible(true)}>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
@ -67,7 +67,7 @@ export default ({ mountId, onDeleted }: Props) => {
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</Button>
</Button.Danger>
</>
);
};

View file

@ -1,10 +1,11 @@
import type { FormikHelpers } from 'formik';
import { Field as FormikField, Form, Formik } from 'formik';
import type { ReactNode } from 'react';
import tw from 'twin.macro';
import { boolean, object, string } from 'yup';
import AdminBox from '@/components/admin/AdminBox';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import Field from '@/components/elements/Field';
import Label from '@/components/elements/Label';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
@ -25,7 +26,7 @@ interface Props {
onSubmit: (values: Values, helpers: FormikHelpers<Values>) => void;
children?: React.ReactNode;
children?: ReactNode;
}
function MountForm({ action, title, initialValues, children, onSubmit }: Props) {
@ -118,7 +119,7 @@ function MountForm({ action, title, initialValues, children, onSubmit }: Props)
{children}
<div css={tw`flex ml-auto`}>
<Button type={'submit'} disabled={isSubmitting || !isValid}>
<Button type="submit" disabled={isSubmitting || !isValid}>
{action}
</Button>
</div>

View file

@ -18,7 +18,8 @@ import AdminTable, {
ContentWrapper,
useTableHooks,
} from '@/components/admin/AdminTable';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import { Size } from '@/components/elements/button/types';
import CopyOnClick from '@/components/elements/CopyOnClick';
import FlashMessageRender from '@/components/FlashMessageRender';
import useFlash from '@/plugins/useFlash';
@ -94,7 +95,7 @@ const MountsContainer = () => {
<div css={tw`flex ml-auto pl-4`}>
<NavLink to={`/admin/mounts/new`}>
<Button type={'button'} size={'large'} css={tw`h-10 px-4 py-0 whitespace-nowrap`}>
<Button type={'button'} size={Size.Large} css={tw`h-10 px-4 py-0 whitespace-nowrap`}>
New Mount
</Button>
</NavLink>

View file

@ -1,13 +1,17 @@
import { LanguageDescription } from '@codemirror/language';
import { json } from '@codemirror/lang-json';
import { useState } from 'react';
import { useParams } from 'react-router-dom';
import tw from 'twin.macro';
import getEggs from '@/api/admin/nests/getEggs';
import importEgg from '@/api/admin/nests/importEgg';
import useFlash from '@/plugins/useFlash';
// import { Editor } from '@/components/elements/editor';
import { useState } from 'react';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import { Size, Variant } from '@/components/elements/button/types';
import { Editor } from '@/components/elements/editor';
import Modal from '@/components/elements/Modal';
import FlashMessageRender from '@/components/FlashMessageRender';
import { useParams } from 'react-router-dom';
import tw from 'twin.macro';
export default ({ className }: { className?: string }) => {
const [visible, setVisible] = useState(false);
@ -43,24 +47,24 @@ export default ({ className }: { className?: string }) => {
<h2 css={tw`mb-6 text-2xl text-neutral-100`}>Import Egg</h2>
{/*<Editor*/}
{/* // overrides={tw`h-64 rounded`}*/}
{/* initialContent={''}*/}
{/* // language={jsonLanguage}*/}
{/* fetchContent={value => {*/}
{/* fetchFileContent = value;*/}
{/* }}*/}
{/*/>*/}
<Editor
className="h-64 overflow-hidden rounded"
initialContent={''}
fetchContent={value => {
fetchFileContent = value;
}}
language={LanguageDescription.of({ name: 'json', support: json() })}
/>
<div css={tw`flex flex-wrap justify-end mt-4 sm:mt-6`}>
<Button
type={'button'}
<Button.Text
type="button"
variant={Variant.Secondary}
css={tw`w-full sm:w-auto sm:mr-2`}
onClick={() => setVisible(false)}
isSecondary
>
Cancel
</Button>
</Button.Text>
<Button css={tw`w-full sm:w-auto mt-4 sm:mt-0`} onClick={submit}>
Import Egg
</Button>
@ -68,12 +72,12 @@ export default ({ className }: { className?: string }) => {
</Modal>
<Button
type={'button'}
size={'large'}
type="button"
size={Size.Large}
variant={Variant.Secondary}
css={tw`h-10 px-4 py-0 whitespace-nowrap`}
className={className}
onClick={() => setVisible(true)}
isSecondary
>
Import
</Button>

View file

@ -4,7 +4,8 @@ import { useState } from 'react';
import tw from 'twin.macro';
import deleteNest from '@/api/admin/nests/deleteNest';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import { Shape } from '@/components/elements/button/types';
import ConfirmationModal from '@/components/elements/ConfirmationModal';
import type { ApplicationStore } from '@/state';
@ -52,7 +53,7 @@ export default ({ nestId, onDeleted }: Props) => {
Are you sure you want to delete this nest? Deleting a nest will delete all eggs assigned to it.
</ConfirmationModal>
<Button type={'button'} size={'xsmall'} color={'red'} onClick={() => setVisible(true)}>
<Button.Danger type="button" shape={Shape.IconSquare} onClick={() => setVisible(true)}>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
@ -67,7 +68,7 @@ export default ({ nestId, onDeleted }: Props) => {
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</Button>
</Button.Danger>
</>
);
};

View file

@ -14,7 +14,8 @@ import FlashMessageRender from '@/components/FlashMessageRender';
import type { Nest } from '@/api/admin/nests/getNests';
import getNest from '@/api/admin/nests/getNest';
import updateNest from '@/api/admin/nests/updateNest';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import { Size } from '@/components/elements/button/types';
import Field from '@/components/elements/Field';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import AdminBox from '@/components/admin/AdminBox';
@ -117,7 +118,7 @@ const EditInformationContainer = () => {
</div>
<div css={tw`flex ml-auto`}>
<Button type={'submit'} disabled={isSubmitting || !isValid}>
<Button type="submit" disabled={isSubmitting || !isValid}>
Save Changes
</Button>
</div>
@ -222,7 +223,7 @@ const NestEditContainer = () => {
<ImportEggButton css={tw`mr-4`} />
<NavLink to={`/admin/nests/${params.nestId}/new`}>
<Button type={'button'} size={'large'} css={tw`h-10 px-4 py-0 whitespace-nowrap`}>
<Button type={'button'} size={Size.Large} css={tw`h-10 px-4 py-0 whitespace-nowrap`}>
New Egg
</Button>
</NavLink>

View file

@ -15,7 +15,7 @@ import {
EggProcessContainerRef,
EggStartupContainer,
} from '@/components/admin/nests/eggs/EggSettingsContainer';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import FlashMessageRender from '@/components/FlashMessageRender';
import useFlash from '@/plugins/useFlash';
@ -45,7 +45,16 @@ export default () => {
values.configStartup = (await ref.current?.getStartupConfiguration()) || '';
values.configFiles = (await ref.current?.getFilesConfiguration()) || '';
createEgg({ ...values, dockerImages: values.dockerImages.split('\n'), nestId })
const dockerImages: Record<string, string> = {};
values.dockerImages.split('\n').forEach(v => {
dockerImages[v] = v;
});
createEgg({
...values,
dockerImages,
nestId,
})
.then(egg => navigate(`/admin/nests/${nestId}/eggs/${egg.id}`))
.catch(error => {
console.error(error);
@ -97,12 +106,7 @@ export default () => {
<div css={tw`bg-neutral-700 rounded shadow-md py-2 px-6 mb-16`}>
<div css={tw`flex flex-row`}>
<Button
type="submit"
size="small"
css={tw`ml-auto`}
disabled={isSubmitting || !isValid}
>
<Button type="submit" css={tw`ml-auto`} disabled={isSubmitting || !isValid}>
Create
</Button>
</div>

View file

@ -1,4 +1,9 @@
import React, { useState } from 'react';
import type { FormikHelpers } from 'formik';
import { Form, Formik } from 'formik';
import { useState } from 'react';
import tw from 'twin.macro';
import { object, string } from 'yup';
import createNest from '@/api/admin/nests/createNest';
import getNests from '@/api/admin/nests/getNests';
import Button from '@/components/elements/Button';
@ -6,25 +11,19 @@ import Field from '@/components/elements/Field';
import Modal from '@/components/elements/Modal';
import FlashMessageRender from '@/components/FlashMessageRender';
import useFlash from '@/plugins/useFlash';
import { Form, Formik, FormikHelpers } from 'formik';
import { object, string } from 'yup';
import tw from 'twin.macro';
interface Values {
name: string,
description: string,
name: string;
description: string;
}
const schema = object().shape({
name: string()
.required('A nest name must be provided.')
.max(32, 'Nest name must not exceed 32 characters.'),
description: string()
.max(255, 'Nest description must not exceed 255 characters.'),
name: string().required('A nest name must be provided.').max(32, 'Nest name must not exceed 32 characters.'),
description: string().max(255, 'Nest description must not exceed 255 characters.'),
});
export default () => {
const [ visible, setVisible ] = useState(false);
const [visible, setVisible] = useState(false);
const { clearFlashes, clearAndAddHttpError } = useFlash();
const { mutate } = getNests();
@ -33,7 +32,7 @@ export default () => {
setSubmitting(true);
createNest(name, description)
.then(async (nest) => {
.then(async nest => {
await mutate(data => ({ ...data!, items: data!.items.concat(nest) }), false);
setVisible(false);
})
@ -45,66 +44,65 @@ export default () => {
return (
<>
<Formik
onSubmit={submit}
initialValues={{ name: '', description: '' }}
validationSchema={schema}
>
{
({ isSubmitting, resetForm }) => (
<Modal
visible={visible}
dismissable={!isSubmitting}
showSpinnerOverlay={isSubmitting}
onDismissed={() => {
resetForm();
setVisible(false);
}}
>
<FlashMessageRender byKey={'nest:create'} css={tw`mb-6`}/>
<Formik onSubmit={submit} initialValues={{ name: '', description: '' }} validationSchema={schema}>
{({ isSubmitting, resetForm }) => (
<Modal
visible={visible}
dismissable={!isSubmitting}
showSpinnerOverlay={isSubmitting}
onDismissed={() => {
resetForm();
setVisible(false);
}}
>
<FlashMessageRender byKey={'nest:create'} css={tw`mb-6`} />
<h2 css={tw`mb-6 text-2xl text-neutral-100`}>New Nest</h2>
<h2 css={tw`mb-6 text-2xl text-neutral-100`}>New Nest</h2>
<Form css={tw`m-0`}>
<Form css={tw`m-0`}>
<Field
type={'text'}
id={'name'}
name={'name'}
label={'Name'}
description={'A short name used to identify this nest.'}
autoFocus
/>
<div css={tw`mt-6`}>
<Field
type={'text'}
id={'name'}
name={'name'}
label={'Name'}
description={'A short name used to identify this nest.'}
autoFocus
id={'description'}
name={'description'}
label={'Description'}
description={'A description for this nest.'}
/>
</div>
<div css={tw`mt-6`}>
<Field
type={'text'}
id={'description'}
name={'description'}
label={'Description'}
description={'A description for this nest.'}
/>
</div>
<div css={tw`flex flex-wrap justify-end mt-6`}>
<Button
type={'button'}
isSecondary
css={tw`w-full sm:w-auto sm:mr-2`}
onClick={() => setVisible(false)}
>
Cancel
</Button>
<Button css={tw`w-full mt-4 sm:w-auto sm:mt-0`} type={'submit'}>
Create Nest
</Button>
</div>
</Form>
</Modal>
)
}
<div css={tw`flex flex-wrap justify-end mt-6`}>
<Button
type={'button'}
isSecondary
css={tw`w-full sm:w-auto sm:mr-2`}
onClick={() => setVisible(false)}
>
Cancel
</Button>
<Button css={tw`w-full mt-4 sm:w-auto sm:mt-0`} type={'submit'}>
Create Nest
</Button>
</div>
</Form>
</Modal>
)}
</Formik>
<Button type={'button'} size={'large'} css={tw`h-10 px-4 py-0 whitespace-nowrap`} onClick={() => setVisible(true)}>
<Button
type={'button'}
size={'large'}
css={tw`h-10 px-4 py-0 whitespace-nowrap`}
onClick={() => setVisible(true)}
>
New Nest
</Button>
</>

View file

@ -4,7 +4,8 @@ import { useState } from 'react';
import tw from 'twin.macro';
import deleteEgg from '@/api/admin/eggs/deleteEgg';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import { Shape } from '@/components/elements/button/types';
import ConfirmationModal from '@/components/elements/ConfirmationModal';
import type { ApplicationStore } from '@/state';
@ -52,7 +53,7 @@ export default ({ eggId, onDeleted }: Props) => {
Are you sure you want to delete this egg? You may only delete an egg with no servers using it.
</ConfirmationModal>
<Button type={'button'} size={'xsmall'} color={'red'} onClick={() => setVisible(true)}>
<Button.Danger type="button" shape={Shape.IconSquare} onClick={() => setVisible(true)}>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
@ -67,7 +68,7 @@ export default ({ eggId, onDeleted }: Props) => {
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</Button>
</Button.Danger>
</>
);
};

View file

@ -1,22 +1,25 @@
import { exportEgg } from '@/api/admin/egg';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import useFlash from '@/plugins/useFlash';
// import { jsonLanguage } from '@codemirror/lang-json';
// import Editor from '@/components/elements/Editor';
import { LanguageDescription } from '@codemirror/language';
import { json } from '@codemirror/lang-json';
import { useEffect, useState } from 'react';
import Button from '@/components/elements/Button';
import Modal from '@/components/elements/Modal';
import FlashMessageRender from '@/components/FlashMessageRender';
import { useParams } from 'react-router-dom';
import tw from 'twin.macro';
import { exportEgg } from '@/api/admin/egg';
import FlashMessageRender from '@/components/FlashMessageRender';
import { Button } from '@/components/elements/button';
import { Variant } from '@/components/elements/button/types';
import { Editor } from '@/components/elements/editor';
import Modal from '@/components/elements/Modal';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import useFlash from '@/plugins/useFlash';
export default ({ className }: { className?: string }) => {
const params = useParams<'id'>();
const { clearAndAddHttpError, clearFlashes } = useFlash();
const [visible, setVisible] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(true);
const [_content, setContent] = useState<Record<string, any> | null>(null);
const [content, setContent] = useState<string | undefined>(undefined);
useEffect(() => {
if (!visible) {
@ -45,21 +48,22 @@ export default ({ className }: { className?: string }) => {
<h2 css={tw`mb-6 text-2xl text-neutral-100`}>Export Egg</h2>
<FlashMessageRender byKey={'egg:export'} css={tw`mb-6`} />
{/*<Editor*/}
{/* overrides={tw`h-[32rem] rounded`}*/}
{/* initialContent={content !== null ? JSON.stringify(content, null, '\t') : ''}*/}
{/* mode={jsonLanguage}*/}
{/*/>*/}
<Editor
className="h-[32rem] overflow-scroll rounded"
initialContent={content ?? ''}
language={LanguageDescription.of({ name: 'json', support: json() })}
/>
<div css={tw`flex flex-wrap justify-end mt-4 sm:mt-6`}>
<Button
type={'button'}
<Button.Text
type="button"
variant={Variant.Secondary}
css={tw`w-full sm:w-auto sm:mr-2`}
onClick={() => setVisible(false)}
isSecondary
>
Close
</Button>
</Button.Text>
<Button
css={tw`w-full sm:w-auto mt-4 sm:mt-0`}
// onClick={submit}
@ -70,16 +74,14 @@ export default ({ className }: { className?: string }) => {
</div>
</Modal>
<Button
type={'button'}
size={'small'}
<Button.Text
type="button"
css={tw`px-4 py-0 whitespace-nowrap`}
className={className}
onClick={() => setVisible(true)}
isSecondary
>
Export
</Button>
</Button.Text>
</>
);
};

View file

@ -1,15 +1,18 @@
import { LanguageDescription, LanguageSupport, StreamLanguage } from '@codemirror/language';
import { shell } from '@codemirror/legacy-modes/mode/shell';
import { faScroll } from '@fortawesome/free-solid-svg-icons';
import type { FormikHelpers } from 'formik';
import { Form, Formik } from 'formik';
import tw from 'twin.macro';
import { useEggFromRoute } from '@/api/admin/egg';
import updateEgg from '@/api/admin/eggs/updateEgg';
import Field from '@/components/elements/Field';
import useFlash from '@/plugins/useFlash';
// import { shell } from '@codemirror/legacy-modes/mode/shell';
import { faScroll } from '@fortawesome/free-solid-svg-icons';
import { Form, Formik, FormikHelpers } from 'formik';
import tw from 'twin.macro';
import AdminBox from '@/components/admin/AdminBox';
import Button from '@/components/elements/Button';
// import Editor from '@/components/elements/Editor';
import { Button } from '@/components/elements/button';
import { Editor } from '@/components/elements/editor';
import Field from '@/components/elements/Field';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import useFlash from '@/plugins/useFlash';
interface Values {
scriptContainer: string;
@ -60,14 +63,17 @@ export default function EggInstallContainer() {
<SpinnerOverlay visible={isSubmitting} />
<Form>
{/*<Editor*/}
{/* overrides={tw`h-96 mb-4`}*/}
{/* initialContent={egg.scriptInstall || ''}*/}
{/* mode={shell}*/}
{/* fetchContent={value => {*/}
{/* fetchFileContent = value;*/}
{/* }}*/}
{/*/>*/}
<Editor
className="mb-4 h-96 overflow-scroll"
initialContent={egg.scriptInstall || ''}
fetchContent={value => {
fetchFileContent = value;
}}
language={LanguageDescription.of({
name: 'shell',
support: new LanguageSupport(StreamLanguage.define(shell)),
})}
/>
<div css={tw`mx-6 mb-4`}>
<div css={tw`grid grid-cols-3 gap-x-8 gap-y-6`}>
@ -92,12 +98,7 @@ export default function EggInstallContainer() {
</div>
<div css={tw`flex flex-row border-t border-neutral-600`}>
<Button
type={'submit'}
size={'small'}
css={tw`ml-auto mr-6 mt-4`}
disabled={isSubmitting || !isValid}
>
<Button type="submit" css={tw`ml-auto mr-6 mt-4`} disabled={isSubmitting || !isValid}>
Save Changes
</Button>
</div>

View file

@ -1,23 +1,26 @@
import { LanguageDescription } from '@codemirror/language';
import { json } from '@codemirror/lang-json';
import { faDocker } from '@fortawesome/free-brands-svg-icons';
import { faEgg, faFireAlt, faMicrochip, faTerminal } from '@fortawesome/free-solid-svg-icons';
import type { FormikHelpers } from 'formik';
import { Form, Formik, useFormikContext } from 'formik';
import { forwardRef, useImperativeHandle, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import tw from 'twin.macro';
import { object } from 'yup';
import { useEggFromRoute } from '@/api/admin/egg';
import updateEgg from '@/api/admin/eggs/updateEgg';
import AdminBox from '@/components/admin/AdminBox';
import EggDeleteButton from '@/components/admin/nests/eggs/EggDeleteButton';
import EggExportButton from '@/components/admin/nests/eggs/EggExportButton';
import Button from '@/components/elements/Button';
// import Editor from '@/components/elements/Editor';
import { Button } from '@/components/elements/button';
import { Editor } from '@/components/elements/editor';
import Field, { TextareaField } from '@/components/elements/Field';
import Input from '@/components/elements/Input';
import Label from '@/components/elements/Label';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import useFlash from '@/plugins/useFlash';
// import { jsonLanguage } from '@codemirror/lang-json';
import { faDocker } from '@fortawesome/free-brands-svg-icons';
import { faEgg, faFireAlt, faMicrochip, faTerminal } from '@fortawesome/free-solid-svg-icons';
import { forwardRef, useImperativeHandle, useRef } from 'react';
import AdminBox from '@/components/admin/AdminBox';
import { useNavigate } from 'react-router-dom';
import tw from 'twin.macro';
import { object } from 'yup';
import { Form, Formik, FormikHelpers, useFormikContext } from 'formik';
export function EggInformationContainer() {
const { isSubmitting } = useFormikContext();
@ -104,8 +107,7 @@ export const EggProcessContainer = forwardRef<any, EggProcessContainerProps>(fun
{ className },
ref,
) {
// const { isSubmitting, values } = useFormikContext<Values>();
const { isSubmitting } = useFormikContext<Values>();
const { isSubmitting, values } = useFormikContext<Values>();
let fetchStartupConfiguration: (() => Promise<string>) | null = null;
let fetchFilesConfiguration: (() => Promise<string>) | null = null;
@ -132,26 +134,26 @@ export const EggProcessContainer = forwardRef<any, EggProcessContainerProps>(fun
<div css={tw`mb-5`}>
<Label>Startup Configuration</Label>
{/*<Editor*/}
{/* mode={jsonLanguage}*/}
{/* initialContent={values.configStartup}*/}
{/* overrides={tw`h-32 rounded`}*/}
{/* fetchContent={value => {*/}
{/* fetchStartupConfiguration = value;*/}
{/* }}*/}
{/*/>*/}
<Editor
className="h-32 overflow-scroll rounded"
initialContent={values.configStartup}
fetchContent={value => {
fetchStartupConfiguration = value;
}}
language={LanguageDescription.of({ name: 'json', support: json() })}
/>
</div>
<div css={tw`mb-1`}>
<Label>Configuration Files</Label>
{/*<Editor*/}
{/* mode={jsonLanguage}*/}
{/* initialContent={values.configFiles}*/}
{/* overrides={tw`h-48 rounded`}*/}
{/* fetchContent={value => {*/}
{/* fetchFilesConfiguration = value;*/}
{/* }}*/}
{/*/>*/}
<Editor
className="h-48 overflow-scroll rounded"
initialContent={values.configFiles}
fetchContent={value => {
fetchFilesConfiguration = value;
}}
language={LanguageDescription.of({ name: 'json', support: json() })}
/>
</div>
</AdminBox>
);
@ -233,7 +235,7 @@ export default function EggSettingsContainer() {
<div css={tw`flex flex-row`}>
<EggDeleteButton eggId={egg.id} onDeleted={() => navigate('/admin/nests')} />
<EggExportButton css={tw`ml-auto mr-4`} />
<Button type="submit" size="small" disabled={isSubmitting || !isValid}>
<Button type="submit" disabled={isSubmitting || !isValid}>
Save Changes
</Button>
</div>

View file

@ -13,11 +13,12 @@ import type { EggVariable } from '@/api/admin/egg';
import { useEggFromRoute } from '@/api/admin/egg';
import NewVariableButton from '@/components/admin/nests/eggs/NewVariableButton';
import AdminBox from '@/components/admin/AdminBox';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import Checkbox from '@/components/elements/Checkbox';
import Field, { FieldRow, TextareaField } from '@/components/elements/Field';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import useFlash from '@/plugins/useFlash';
import Label from '@/components/elements/Label';
export const validationSchema = object().shape({
name: string().required().min(1).max(191),
@ -59,14 +60,23 @@ export function EggVariableForm({ prefix }: { prefix: string }) {
</FieldRow>
<div css={tw`flex flex-row mb-6`}>
<Checkbox id={`${prefix}isUserViewable`} name={`${prefix}isUserViewable`} label={'User Viewable'} />
<div className="ml-auto flex flex-row">
{/* TODO: fix Checkbox component, current one is designed for subuser permissions and not for individual values */}
<Checkbox id={`${prefix}isUserViewable`} name={`${prefix}isUserViewable`} />
<Checkbox
id={`${prefix}isUserEditable`}
name={`${prefix}isUserEditable`}
label={'User Editable'}
css={tw`ml-auto`}
/>
<div css={tw`flex-1`}>
<Label>User Viewable</Label>
</div>
</div>
<div className="ml-auto flex flex-row">
{/* TODO: fix Checkbox component, current one is designed for subuser permissions and not for individual values */}
<Checkbox id={`${prefix}isUserEditable`} name={`${prefix}isUserEditable`} />
<div css={tw`flex-1`}>
<Label>User Editable</Label>
</div>
</div>
</div>
<Field
@ -111,7 +121,7 @@ function EggVariableDeleteButton({ onClick }: { onClick: (success: () => void) =
css={tw`ml-auto text-neutral-500 hover:text-neutral-300`}
onClick={() => setVisible(true)}
>
<TrashIcon css={tw`h-5 w-5`} />
<TrashIcon className="h-5 w-5" />
</button>
</>
);
@ -200,12 +210,7 @@ export default function EggVariablesContainer() {
<div css={tw`flex flex-row`}>
<NewVariableButton />
<Button
type={'submit'}
size={'small'}
css={tw`ml-auto`}
disabled={isSubmitting || !isValid}
>
<Button type="submit" className="ml-auto" disabled={isSubmitting || !isValid}>
Save Changes
</Button>
</div>

View file

@ -9,8 +9,9 @@ import { useEggFromRoute } from '@/api/admin/egg';
import { EggVariableForm, validationSchema } from '@/components/admin/nests/eggs/EggVariablesContainer';
import Modal from '@/components/elements/Modal';
import FlashMessageRender from '@/components/FlashMessageRender';
import Button from '@/components/elements/Button';
import { Button } from '@/components/elements/button';
import useFlash from '@/plugins/useFlash';
import { Variant } from '@/components/elements/button/types';
export default function NewVariableButton() {
const { setValues } = useFormikContext();
@ -75,16 +76,16 @@ export default function NewVariableButton() {
<div css={tw`flex flex-wrap justify-end mt-6`}>
<Button
type={'button'}
isSecondary
type="button"
variant={Variant.Secondary}
css={tw`w-full sm:w-auto sm:mr-2`}
onClick={() => setVisible(false)}
>
Cancel
</Button>
<Button
type="submit"
css={tw`w-full mt-4 sm:w-auto sm:mt-0`}
type={'submit'}
disabled={isSubmitting || !isValid}
>
Create Variable
@ -95,7 +96,8 @@ export default function NewVariableButton() {
)}
</Formik>
<Button type={'button'} color={'green'} onClick={() => setVisible(true)}>
{/* TODO: make button green */}
<Button type="button" onClick={() => setVisible(true)}>
New Variable
</Button>
</>

View file

@ -4,7 +4,6 @@ import { useState } from 'react';
import Checkbox from '@/components/elements/inputs/Checkbox';
import { Dropdown } from '@/components/elements/dropdown';
import { Dialog } from '@/components/elements/dialog';
import { Button } from '@/components/elements/button';
import { User } from '@definitions/admin';
interface Props {
@ -18,14 +17,17 @@ const UserTableRow = ({ user, selected, onRowChange }: Props) => {
return (
<>
<Dialog title={'Delete account'} visible={visible} onDismissed={() => setVisible(false)}>
<Dialog.Icon type={'danger'} />
<Dialog.Confirm
title={'Delete account'}
open={visible}
onClose={() => setVisible(false)}
onConfirmed={() => {
console.log('yeet');
}}
>
This account will be permanently deleted.
<Dialog.Buttons>
<Button.Text onClick={() => setVisible(false)}>Cancel</Button.Text>
<Button.Danger>Delete</Button.Danger>
</Dialog.Buttons>
</Dialog>
</Dialog.Confirm>
<tr>
<td className={'whitespace-nowrap'}>
<div className={'flex justify-end items-center w-8'}>

View file

@ -12,6 +12,7 @@ import TFootPaginated from '@/components/elements/table/TFootPaginated';
import type { User } from '@definitions/admin';
import extractSearchFilters from '@/helpers/extractSearchFilters';
import useDebouncedState from '@/plugins/useDebouncedState';
import { Shape } from '@/components/elements/button/types';
const filters = ['id', 'uuid', 'external_id', 'username', 'email'] as const;
@ -77,13 +78,13 @@ const UsersContainer = () => {
onChange={onSelectAll}
/>
</div>
<Button.Text square>
<Button.Text shape={Shape.IconSquare}>
<SupportIcon className={'w-4 h-4'} />
</Button.Text>
<Button.Text square>
<Button.Text shape={Shape.IconSquare}>
<LockOpenIcon className={'w-4 h-4'} />
</Button.Text>
<Button.Text square>
<Button.Text shape={Shape.IconSquare}>
<TrashIcon className={'w-4 h-4'} />
</Button.Text>
</div>