Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/pci ai notebooks header notebook #14128

Draft
wants to merge 2 commits into
base: feat/pci-ai-notebooks-epic
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"tableHeaderPrivacy": "Confidentialité ",
"networkSecureTitle": "Privé",
"networkPublicTitle": "Public",
"tableHeaderDuration": "Durée de fonctionnement",
"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 @@ -53,6 +53,6 @@
"cliCode": "Equivalent CLI",
"errorGetCommandCli": "Une erreur est survenue lors de la génération de code équivalent pour la CLI",
"cliEquivalentModalTitle": "Création d’un notebook équivalent",
"cliEquivalentModalDescription": "Créer le même notebook via la CLI",
"cliEquivalentModalDescription": "Commande CLI",
"cliEquivalentModalToastMessage": "Le code a été copié"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"dashboardTab": "Dashboard",
"dataTab": "Données attachées",
"backupTab": "Backup",
"logsTab": "Logs",
"deleteNotebookTitle": "Supprimer le notebook",
"deleteNotebookDescription": "Etes-vous sur de vouloir supprimer le notebook {{name}} ?",
"notebookButtonCancel": "Annuler",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"dashboardTitle": "Dashboard",
"resourcesTitle": "Ressources",
"powerTitleSection": "Power",
"computeTitleSection": "Compute",
"storageTitleSection": "Stockage",
"gpuMemoryField": "{{ gpu }} x {{ memory }} RAM",
"gcuComputeField": "CPU: {{ cpu }} vCores ",
"memoryField": "RAM: {{ memory }}",
"publicNetworkField": "Réseau public: {{ network }}/s",
"temporaryLocalStorageField": "Stockage local éphémère: {{ storage }} SSD",
"temporaryLocalStorageHelper": "Stockage local performant, mais non sauvegardé",
"workspaceStorage": "Espace de travail {{ storage }} SSD inclus",
"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",
"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
@@ -0,0 +1,6 @@
import * as ai from '@/types/cloud/project/ai';

export const mockedLabel: ai.Label = {
name: 'labelName',
value: 'labelValue',
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ interface CliCodeBlockProps {
title: string;
code: string;
toastMessage?: string;
size?: string;
}

const CliCodeBlock = ({ title, code, toastMessage }: CliCodeBlockProps) => {
const CliCodeBlock = ({
title,
code,
toastMessage,
size,
}: CliCodeBlockProps) => {
const { t } = useTranslation('common');
const toast = useToast();
const handleCopyPass = (valueToCopy: string) => {
Expand All @@ -22,7 +28,7 @@ const CliCodeBlock = ({ title, code, toastMessage }: CliCodeBlockProps) => {

return (
<div className="flex flex-col">
<div className="flex flex-row items-center justify-between p-2 px-8">
<div className="flex flex-row items-center justify-between p-2 px-6">
<p>{title}</p>
<Button
data-testid="code-block-copy-button"
Expand All @@ -34,7 +40,7 @@ const CliCodeBlock = ({ title, code, toastMessage }: CliCodeBlockProps) => {
<span className="sr-only">copy</span>
</Button>
</div>
<ScrollArea className="max-h-[80vh] px-6">
<ScrollArea className={size}>
<pre
style={{ wordBreak: 'break-word' }}
className="p-4 whitespace-pre-wrap rounded-md bg-[#122844] text-white"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ const buttonVariants = cva(
link: "text-base",
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"
input: "h-10 w-full rounded-md px-3 py-2 text-sm",
roundedIcon: "h-6 w-6 rounded-full",
},
},
defaultVariants: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ const Slider = React.forwardRef<
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-gray-100">
<SliderPrimitive.Range className="absolute h-full bg-primary" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
</SliderPrimitive.Root>
))
Slider.displayName = SliderPrimitive.Root.displayName

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { apiClient } from '@ovh-ux/manager-core-api';
import { NotebookData } from '@/data/api';
import * as ai from '@/types/cloud/project/ai';

export interface EditLabelProps extends NotebookData {
label: ai.Label;
}

export const editLabel = async ({
projectId,
notebookId,
label,
}: EditLabelProps) =>
apiClient.v6
.put(`/cloud/project/${projectId}/ai/notebook/${notebookId}/label`, label)
.then((res) => res.data);
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { apiClient } from '@ovh-ux/manager-core-api';
import { describe, expect, vi } from 'vitest';
import { editLabel } from './label.api';
import { mockedLabel } from '@/__tests__/helpers/mocks/label';

vi.mock('@ovh-ux/manager-core-api', () => {
const put = vi.fn(() => {
return Promise.resolve({ data: null });
});
return {
apiClient: {
v6: {
put,
},
},
};
});

describe('label functions', () => {
afterEach(() => {
vi.clearAllMocks();
});

it('should call editLabel with labelInput', async () => {
expect(apiClient.v6.put).not.toHaveBeenCalled();
await editLabel({
projectId: 'projectId',
notebookId: 'notebookId',
label: mockedLabel,
});
expect(apiClient.v6.put).toHaveBeenCalledWith(
'/cloud/project/projectId/ai/notebook/notebookId/label',
mockedLabel,
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useMutation } from '@tanstack/react-query';
import { AIError } from '@/data/api';
import {
EditLabelProps,
editLabel,
} from '@/data/api/ai/notebook/label/label.api';

export interface MutateLabelProps {
onError: (cause: AIError) => void;
onSuccess: () => void;
}

export function useEditLabel({ onError, onSuccess }: MutateLabelProps) {
const mutation = useMutation({
mutationFn: (labelInfo: EditLabelProps) => {
return editLabel(labelInfo);
},
onError,
onSuccess,
});

return {
editLabel: (labelInfo: EditLabelProps) => {
return mutation.mutate(labelInfo);
},
...mutation,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { renderHook, waitFor } from '@testing-library/react';
import { vi } from 'vitest';
import { QueryClientWrapper } from '@/__tests__/helpers/wrappers/QueryClientWrapper';
import * as labelApi from '@/data/api/ai/notebook/label/label.api';
import { useEditLabel } from './useEditLabel.hook';
import { mockedLabel } from '@/__tests__/helpers/mocks/label';

vi.mock('@/data/api/ai/notebook/label/label.api', () => ({
editLabel: vi.fn(),
}));

describe('useEditLabel', () => {
it('should call useEditLabel on mutation with data', async () => {
const projectId = 'projectId';
const notebookId = 'notebookId';
const onSuccess = vi.fn();
const onError = vi.fn();

vi.mocked(labelApi.editLabel).mockResolvedValue(mockedLabel);
const { result } = renderHook(() => useEditLabel({ onError, onSuccess }), {
wrapper: QueryClientWrapper,
});

const editLabelProps = {
projectId,
notebookId,
label: mockedLabel,
};
result.current.editLabel(editLabelProps);

await waitFor(() => {
expect(labelApi.editLabel).toHaveBeenCalledWith(editLabelProps);
expect(onSuccess).toHaveBeenCalledWith(
mockedLabel,
editLabelProps,
undefined,
);
});
});
});
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 @@ -13,3 +13,12 @@ export function isDeletingNotebook(
) {
return currentState === ai.notebook.NotebookStateEnum.DELETING;
}

export const OVH_TAGS_CONFIG = {
id: 'ovh/id',
type: 'ovh/type',
};

export function isOvhTags(key: string) {
return key === OVH_TAGS_CONFIG.id || key === OVH_TAGS_CONFIG.type;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { useUserActivityContext } from '@/contexts/UserActivityContext';
import { getNotebook } from '@/data/api/ai/notebook/notebook.api';
import { useGetNotebook } from '@/hooks/api/ai/notebook/useGetNotebook.hook';
import { NotebookLayoutContext } from './Notebook.context';
import { NotebookHeader } from './_components/NotebookHeader.component';
import NotebookTabs from './_components/NotebookTabs.component';

interface NotebookLayoutProps {
params: {
Expand Down Expand Up @@ -55,6 +57,7 @@ export default function NotebookLayout() {
if (!notebook) {
return (
<>
<NotebookHeader.Skeleton />
<TabsMenu.Skeleton />
Loading your notebook data
</>
Expand All @@ -67,7 +70,8 @@ export default function NotebookLayout() {

return (
<>
<div>{notebook.spec.name}</div>
<NotebookHeader notebook={notebook} />
<NotebookTabs notebook={notebook} />
<div className="space-y-2">
<Outlet context={notebookLayoutContext} />
</div>
Expand Down
Loading
Loading