Skip to content

Commit

Permalink
feat(ai.notebooks): dashboard tab part 2
Browse files Browse the repository at this point in the history
Signed-off-by: Arthur Bullet <[email protected]>
  • Loading branch information
abullet33 committed Nov 15, 2024
1 parent e581329 commit 1f882b4
Show file tree
Hide file tree
Showing 14 changed files with 322 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"networkSecureTitle": "Privé",
"networkPublicTitle": "Public",
"tableHeaderDuration": "Durée",
"durationHelper": "Durée de fonctionnement du notebook",
"tableHeaderStatus": "Statut",
"tableActionManage": "Gérer",
"tableActionStart": "Démarrer",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@
"memoryField": "RAM: {{ memory }}",
"publicNetworkField": "Réseau public: {{ network }}/s",
"temporaryLocalStorageField": "Stockage local éphémère: {{ storage }} SSD",
"temporaryLocalStorageHelper": "Not that much for now",
"temporaryLocalStorageHelper": "Stockage local performant, mais non sauvegardé",
"workspaceStorage": "Espace de travail {{ storage }} SSD inclus",
"workspaceStorageHelper": "Nothing for now",
"workspaceStorageHelper": "Stockage distant sauvegardé. Au-delà de 30 jours consécutifs de stockage ou/et du dépassement de ce quota de 10 Gio, les tarifs appliqués seront ceux de Public Cloud Object Storage.",
"sliderInfo": "{{ usedStorage }} / {{ totalStorage }}",
"notebookIdLabel": "Id du notebook",
"notebookIdCopyToast": "L'identifiant du notebook a été copié",
"billingLink": "Gérer la facturation",
"supportLink": "Contacter le support",
"deleteNotebookButton": "Supprimer"
"deleteNotebookButton": "Supprimer",
"addLabelTitle": "Ajouter un label",
"keyFieldLabel": "Clé",
"valueFieldLabel": "Valeur",
"addLabelButtonCancel": "Annuler",
"addLabelNameSubmit": "Ajouter",
"notebookToastErrorTitle": "Erreur",
"notebookToastSuccessTitle": "Succés",
"deleteNotebookSuccess": "Le label a été correctement ajouté à votre notebook"
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const buttonVariants = cva(
table: "h-4 w-4 my-auto",
menu: 'size-8 p-0',
input: "h-10 w-full rounded-md px-3 py-2 text-sm",
roundedIcon: "h-8 w-8 rounded-full",
roundedIcon: "h-6 w-6 rounded-full",
},
},
defaultVariants: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function useGetNotebooks(
projectId: string,
options: Omit<QueryObserverOptions, 'queryKey'> = {},
) {
const queryKey = [projectId, 'ai', 'notebook'];
const queryKey = [projectId, 'ai/notebook'];
return useQueryImmediateRefetch({
queryKey,
queryFn: () => getNotebooks({ projectId }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ export function useStartNotebook({
},
onError,
onSuccess: () => {
onStartSuccess();
// Invalidate service list query to get the latest data
queryClient.invalidateQueries({
queryKey: [projectId, 'ai/notebook'],
});
onStartSuccess();
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export function useStopNotebook({ onError, onStopSuccess }: UseStopNotebook) {
},
onError,
onSuccess: () => {
onStopSuccess();
// Invalidate service list query to get the latest data
queryClient.invalidateQueries({
queryKey: [projectId, 'ai/notebook'],
});
onStopSuccess();
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@ import { Skeleton } from '@/components/ui/skeleton';
import * as ai from '@/types/cloud/project/ai';
import NotebookStatusBadge from '../../_components/NotebookStatusBadge.component';
import { Button } from '@/components/ui/button';
import StartNotebook from './StartNotebook.component';
import { useModale } from '@/hooks/useModale';
import StopNotebook from './StopNotebook.component';
import { isDeletingNotebook, isRunningNotebook } from '@/lib/notebookHelper';

export const NotebookHeader = ({
notebook,
}: {
notebook: ai.notebook.Notebook;
}) => {
const { t } = useTranslation('regions');
const startModale = useModale('start');
const stopModale = useModale('stop');
return (
<div
data-testid="notebook-header-container"
Expand All @@ -28,14 +34,31 @@ export const NotebookHeader = ({
<NotebookText width={40} height={40} />
</div>
<div className="w-full">
<div className="flex flex-row items-center gap-8">
<div className="flex flex-row items-center gap-5">
<h2>{notebook.spec.name ?? 'Dashboard'}</h2>
<div className="flex flex-row gap-2">
<Button type="button" size="roundedIcon">
<PlayIcon className="size-4 ml-1 fill-white" />
<Button
type="button"
size="roundedIcon"
onClick={() => startModale.open()}
disabled={
isRunningNotebook(notebook.status.state) ||
isDeletingNotebook(notebook.status.state)
}
>
<PlayIcon className="size-3 fill-white" />
</Button>
<Button type="button" size="roundedIcon" className="bg-red-400">
<Square className="size-4 fill-white" />
<Button
type="button"
size="roundedIcon"
className="bg-red-400 hover:bg-red-600"
onClick={() => stopModale.open()}
disabled={
!isRunningNotebook(notebook.status.state) ||
isDeletingNotebook(notebook.status.state)
}
>
<Square className="size-3 fill-white" />
</Button>
</div>
</div>
Expand All @@ -55,6 +78,20 @@ export const NotebookHeader = ({
</Badge>
</div>
</div>
<StartNotebook
controller={startModale.controller}
notebook={notebook}
onSuccess={() => {
startModale.close();
}}
/>
<StopNotebook
controller={stopModale.controller}
notebook={notebook}
onSuccess={() => {
stopModale.close();
}}
/>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { useStartNotebook } from '@/hooks/api/ai/notebook/useStartNotebook.hook'
interface StartNotebookModalProps {
notebook: ai.notebook.Notebook;
controller: ModalController;
onSuccess?: (notebook: ai.notebook.Notebook) => void;
onSuccess?: () => void;
onError?: (service: Error) => void;
}

Expand Down Expand Up @@ -52,7 +52,7 @@ const StartNotebook = ({
}),
});
if (onSuccess) {
onSuccess(notebook);
onSuccess();
}
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { useStopNotebook } from '@/hooks/api/ai/notebook/useStopNotebook.hook';
interface StopNotebookModalProps {
notebook: ai.notebook.Notebook;
controller: ModalController;
onSuccess?: (notebook: ai.notebook.Notebook) => void;
onSuccess?: () => void;
onError?: (service: Error) => void;
}

Expand Down Expand Up @@ -52,7 +52,7 @@ const StopNotebook = ({
}),
});
if (onSuccess) {
onSuccess(notebook);
onSuccess();
}
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const Dashboard = () => {
<Card>
<CardHeader>
<h4>
<Atom className="size-4 inline mr-2 text-sky-600" />
<Atom className="size-4 inline mr-2" />
<span>{t('resourcesTitle')}</span>
</h4>
</CardHeader>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import { useParams } from 'react-router-dom';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { useTranslation } from 'react-i18next';
import { useForm } from 'react-hook-form';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { ModalController } from '@/hooks/useModale';
import { useToast } from '@/components/ui/use-toast';
import * as ai from '@/types/cloud/project/ai';
import { useEditLabel } from '@/hooks/api/ai/notebook/label/useEditLabel.hook';
import { getAIApiErrorMessage } from '@/lib/apiHelper';

interface AddLabelProps {
notebook: ai.notebook.Notebook;
controller: ModalController;
onSuccess?: () => void;
onError?: (error: Error) => void;
}

const AddLabel = ({
notebook,
controller,
onError,
onSuccess,
}: AddLabelProps) => {
// import translations
const { projectId } = useParams();
const { t } = useTranslation('pci-ai-notebooks/notebooks/notebook/dashboard');
const toast = useToast();

const { editLabel, isPending } = useEditLabel({
onError: (err) => {
toast.toast({
title: t('notebookToastErrorTitle'),
variant: 'destructive',
description: getAIApiErrorMessage(err),
});
if (onError) {
onError(err);
}
},
onSuccess: () => {
toast.toast({
title: t('notebookToastSuccessTitle'),
description: t('deleteNotebookSuccess'),
});
if (onSuccess) {
onSuccess();
}
},
});
// define the schema for the form
const labelSchema = z.object({
name: z
.string()
.min(1)
.max(15)
.refine(
(newKey) => notebook.spec.labels && !(newKey in notebook.spec.labels),
{
message: t('existingKeyError'),
},
),
value: z
.string()
.min(1)
.max(15),
});
// generate a form controller
const form = useForm<z.infer<typeof labelSchema>>({
resolver: zodResolver(labelSchema),
defaultValues: {
name: '',
value: '',
},
});

const onSubmit = form.handleSubmit((formValues) => {
editLabel({
projectId: projectId,

Check failure on line 98 in packages/manager/apps/pci-ai-notebooks/src/pages/notebooks/[notebookId]/dashboard/_components/AddLabel.component.tsx

View workflow job for this annotation

GitHub Actions / Lint Code Base

Expected property shorthand
notebookId: notebook.id,
label: {
name: formValues.name,
value: formValues.value,
},
});
});

return (
<Dialog {...controller}>
<DialogContent>
<DialogHeader>
<DialogTitle data-testid="rename-service-modal">
{t('addLabelTitle')}
</DialogTitle>
</DialogHeader>

<Form {...form}>
<form onSubmit={onSubmit} className="grid gap-2">
<FormField
control={form.control}
name="name"
defaultValue=""
render={({ field }) => (
<FormItem>
<FormLabel data-testid="name-field-label">
{t('keyFieldLabel')}
</FormLabel>
<FormControl>
<Input data-testid="key-input-field" {...field}/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="value"
defaultValue=""
render={({ field }) => (
<FormItem data-testid="value-field-label">
<FormLabel>{t('valueFieldLabel')}</FormLabel>
<FormControl>
<Input data-testid="value-input-field" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<DialogFooter className="flex justify-end">
<DialogClose asChild>
<Button
data-testid="add-label-cancel-button"
type="button"
variant="outline"
>
{t('addLabelButtonCancel')}
</Button>
</DialogClose>
<Button
data-testid="add-label-submit-button"
type="submit"
disabled={isPending}
>
{t('addLabelNameSubmit')}
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
</Dialog>
);
};

export default AddLabel;
Loading

0 comments on commit 1f882b4

Please sign in to comment.