Skip to content

Commit

Permalink
feat(admin): init apps tables
Browse files Browse the repository at this point in the history
  • Loading branch information
Mati365 committed Oct 12, 2024
1 parent 4398cb6 commit 2be7bf0
Show file tree
Hide file tree
Showing 26 changed files with 663 additions and 0 deletions.
1 change: 1 addition & 0 deletions apps/admin/src/components/controls/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './input';
export * from './numeric-input';
export * from './search-select';
export * from './select';
export * from './textarea';
12 changes: 12 additions & 0 deletions apps/admin/src/components/controls/textarea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import clsx from 'clsx';

export type TextAreaProps = JSX.IntrinsicElements['textarea'];

export function TextArea({ className, ...props }: TextAreaProps) {
return (
<textarea
{...props}
className={clsx('uk-textarea', className)}
/>
);
}
32 changes: 32 additions & 0 deletions apps/admin/src/i18n/packs/i18n-lang-en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export const I18N_PACK_EN = {
users: 'Users',
s3: 'S3',
projects: 'Projects',
apps: 'Apps',
},
loggedIn: {
logout: 'Logout',
Expand Down Expand Up @@ -210,6 +211,30 @@ export const I18N_PACK_EN = {
},
},
},
apps: {
prefix: {
app: 'App',
},
form: {
title: {
create: 'Create app',
edit: 'Edit app',
},
fields: {
name: {
label: 'Name',
placeholder: 'Enter app name',
},
organization: {
label: 'Organization',
},
chatContext: {
label: 'Chat context',
placeholder: 'Enter chat context',
},
},
},
},
users: {
roles: I18N_USER_ROLES_EN,
form: {
Expand Down Expand Up @@ -315,6 +340,13 @@ export const I18N_PACK_EN = {
},
title: 'Manage projects',
},
apps: {
meta: {
title: 'Apps',
description: 'Manage apps',
},
title: 'Manage apps',
},
users: {
meta: {
title: 'Users',
Expand Down
32 changes: 32 additions & 0 deletions apps/admin/src/i18n/packs/i18n-lang-pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export const I18N_PACK_PL: I18nLangPack = {
users: 'Użytkownicy',
s3: 'S3',
projects: 'Projekty',
apps: 'Aplikacje',
},
loggedIn: {
logout: 'Wyloguj się',
Expand Down Expand Up @@ -184,6 +185,30 @@ export const I18N_PACK_PL: I18nLangPack = {
},
},
},
apps: {
prefix: {
app: 'Aplikacja',
},
form: {
title: {
create: 'Utwórz aplikację',
edit: 'Edytuj aplikację',
},
fields: {
name: {
label: 'Nazwa',
placeholder: 'Wpisz nazwę aplikacji',
},
organization: {
label: 'Organizacja',
},
chatContext: {
label: 'Kontekst czatu',
placeholder: 'Wpisz kontekst czatu',
},
},
},
},
users: {
roles: I18N_USER_ROLES_PL,
form: {
Expand Down Expand Up @@ -289,6 +314,13 @@ export const I18N_PACK_PL: I18nLangPack = {
},
title: 'Zarządzaj projektami',
},
apps: {
meta: {
title: 'Aplikacje',
description: 'Zarządzaj aplikacjami',
},
title: 'Zarządzaj aplikacjami',
},
users: {
meta: {
title: 'Użytkownicy',
Expand Down
4 changes: 4 additions & 0 deletions apps/admin/src/layouts/navigation/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export function Navigation() {
{t.links.users}
</NavigationItem>

<NavigationItem path={sitemap.apps.index.raw} icon="bot">
{t.links.apps}
</NavigationItem>

<NavigationItem path={sitemap.projects.index.raw} icon="folder">
{t.links.projects}
</NavigationItem>
Expand Down
75 changes: 75 additions & 0 deletions apps/admin/src/modules/apps/form/create/app-create-form-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import type { SdkCreateAppInputT } from '@llm/sdk';

import {
CancelButton,
CreateButton,
FormErrorAlert,
FormField,
Modal,
type ModalProps,
ModalTitle,
} from '~/components';
import { useI18n } from '~/i18n';
import { OrganizationsSearchSelect } from '~/modules/organizations/controls/organizations-search-select';

import { AppSharedFormFields } from '../shared';
import { useAppCreateForm } from './use-app-create-form';

export type AppCreateFormModalProps =
& Omit<ModalProps, 'children' | 'header' | 'formProps'>
& {
defaultValue: SdkCreateAppInputT;
onAfterSubmit?: VoidFunction;
};

export function AppCreateFormModal(
{
defaultValue,
onAfterSubmit,
onClose,
...props
}: AppCreateFormModalProps,
) {
const t = useI18n().pack.modules.apps.form;
const { handleSubmitEvent, validator, submitState, bind } = useAppCreateForm({
defaultValue,
onAfterSubmit,
});

return (
<Modal
{...props}
isOverflowVisible
onClose={onClose}
formProps={{
onSubmit: handleSubmitEvent,
}}
header={(
<ModalTitle>
{t.title.create}
</ModalTitle>
)}
footer={(
<>
<CancelButton disabled={submitState.loading} onClick={onClose} />
<CreateButton loading={submitState.loading} type="submit" />
</>
)}
>
<FormField
className="uk-margin"
label={t.fields.organization.label}
{...validator.errors.extract('organization')}
>
<OrganizationsSearchSelect {...bind.path('organization')} required />
</FormField>

<AppSharedFormFields
errors={validator.errors.all as any}
{...bind.merged()}
/>

<FormErrorAlert result={submitState.result} />
</Modal>
);
}
3 changes: 3 additions & 0 deletions apps/admin/src/modules/apps/form/create/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './app-create-form-modal';
export * from './use-app-create-form';
export * from './use-app-create-modal';
46 changes: 46 additions & 0 deletions apps/admin/src/modules/apps/form/create/use-app-create-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { type FormHookAttrs, useForm } from '@under-control/forms';
import { flow } from 'fp-ts/lib/function';

import { runTask, tapTaskEither } from '@llm/commons';
import { type SdkCreateAppInputT, useSdkForLoggedIn } from '@llm/sdk';
import { useSaveTaskEitherNotification } from '~/components';
import { usePredefinedFormValidators } from '~/hooks';

type CreateAppFormHookAttrs =
& Omit<
FormHookAttrs<SdkCreateAppInputT>,
'validation' | 'onSubmit'
>
& {
onAfterSubmit?: VoidFunction;
};

export function useAppCreateForm(
{
onAfterSubmit,
...props
}: CreateAppFormHookAttrs,
) {
const { sdks } = useSdkForLoggedIn();
const { required, requiredListItem } = usePredefinedFormValidators<SdkCreateAppInputT>();
const saveNotifications = useSaveTaskEitherNotification();

return useForm({
resetAfterSubmit: false,
onSubmit: flow(
sdks.dashboard.apps.create,
saveNotifications,
tapTaskEither(() => onAfterSubmit?.()),
runTask,
),
validation: {
mode: ['blur', 'submit'],
validators: () => [
required('name'),
required('chatContext'),
requiredListItem('organization'),
],
},
...props,
});
}
32 changes: 32 additions & 0 deletions apps/admin/src/modules/apps/form/create/use-app-create-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { SdkCreateAppInputT } from '@llm/sdk';

import { useAnimatedModal } from '@llm/commons-front';

import {
AppCreateFormModal,
type AppCreateFormModalProps,
} from './app-create-form-modal';

type AppShowModalProps =
& Pick<AppCreateFormModalProps, 'onAfterSubmit'>
& {
defaultValue: SdkCreateAppInputT;
};

export function useAppCreateModal() {
return useAnimatedModal<boolean, AppShowModalProps>({
renderModalContent: ({ showProps, hiding, onAnimatedClose }) => (
<AppCreateFormModal
{...showProps}
isLeaving={hiding}
onAfterSubmit={() => {
void onAnimatedClose(true);
showProps?.onAfterSubmit?.();
}}
onClose={() => {
void onAnimatedClose();
}}
/>
),
});
}
2 changes: 2 additions & 0 deletions apps/admin/src/modules/apps/form/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './create';
export * from './update';
46 changes: 46 additions & 0 deletions apps/admin/src/modules/apps/form/shared/app-shared-form-fields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { controlled, useFormValidatorMessages, type ValidationErrorsListProps } from '@under-control/forms';

import type { SdkAppT } from '@llm/sdk';

import { FormField, Input, TextArea } from '~/components';
import { useI18n } from '~/i18n';

type Value = Pick<SdkAppT, 'name' | 'chatContext'>;

type Props = ValidationErrorsListProps<Value>;

export const AppSharedFormFields = controlled<Value, Props>(({ errors, control: { bind } }) => {
const t = useI18n().pack.modules.apps.form;
const validation = useFormValidatorMessages({ errors });

return (
<>
<FormField
className="uk-margin"
label={t.fields.name.label}
{...validation.extract('name')}
>
<Input
name="name"
placeholder={t.fields.name.placeholder}
required
{...bind.path('name')}
/>
</FormField>

<FormField
className="uk-margin"
label={t.fields.chatContext.label}
{...validation.extract('name')}
>
<TextArea
name="chat-context"
placeholder={t.fields.chatContext.placeholder}
rows={3}
required
{...bind.path('chatContext')}
/>
</FormField>
</>
);
});
1 change: 1 addition & 0 deletions apps/admin/src/modules/apps/form/shared/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './app-shared-form-fields';
Loading

0 comments on commit 2be7bf0

Please sign in to comment.