Compare commits

..

No commits in common. "ee127f431c5386065b3fb6de07a463ad6dd23961" and "30706118a84772767af762816863f8bf8f4e3d27" have entirely different histories.

12 changed files with 57 additions and 327 deletions

View File

@ -203,7 +203,7 @@ export class FilesController {
return await this.filesService.removeFileType(typeId); return await this.filesService.removeFileType(typeId);
} }
@HttpCode(HttpStatus.OK) @HttpCode(HttpStatus.FOUND)
@Get(":fileId") @Get(":fileId")
async getFile(@Param("fileId") fileId: string) { async getFile(@Param("fileId") fileId: string) {
return await this.filesService.get(fileId); return await this.filesService.get(fileId);

View File

@ -19,8 +19,7 @@ import {
TypeDto, TypeDto,
} from "apps/backend/src/app/machines/machines.dto"; } from "apps/backend/src/app/machines/machines.dto";
import { MachinesService } from "apps/backend/src/app/machines/machines.service"; import { MachinesService } from "apps/backend/src/app/machines/machines.service";
import { ApiResponse, ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { IMachinesTable } from 'apps/backend/src/app/db/schema';
@ApiTags('Machines') @ApiTags('Machines')
@Controller("machines") @Controller("machines")

View File

@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
// NOTE: This file should not be edited // NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. // see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@ -15,7 +15,7 @@ export default function RootLayout({
}) { }) {
return ( return (
<html lang="en"> <html lang="en">
<body className={"h-screen w-screen bg-card flex flex-col justify-between items-center police-ubuntu"}> <body className={"h-screen w-screen bg-card flex flex-col justify-between items-center police-ubuntu dark"}>
<Header/> <Header/>
{children} {children}
<Footer/> <Footer/>

View File

@ -1,11 +1,21 @@
"use client" "use client"
import { Dispatch, SetStateAction, useState } from 'react'; import { Dispatch, SetStateAction, useState } from 'react';
import { Button } from '../components/ui/button';
import { Home, NotepadTextDashed } from 'lucide-react';
import { NewFileModal } from 'apps/frontend/src/components/new-file-modal';
import { import {
ResizableHandle, ResizableHandle,
ResizablePanel, ResizablePanel,
ResizablePanelGroup ResizablePanelGroup
} from 'apps/frontend/src/components/ui/resizable'; } from 'apps/frontend/src/components/ui/resizable';
import { ESubPage, SubPage, SubPageSelector } from '../components/sub-pages'; import {
SubHomePage
} from 'apps/frontend/src/components/sub-pages/sub-home-page';
export enum ESubPage {
Home,
Documentation,
}
export default function HomePage() { export default function HomePage() {
const [currentSubPage, setCurrentSubPage] = useState<ESubPage>(0) const [currentSubPage, setCurrentSubPage] = useState<ESubPage>(0)
@ -33,4 +43,43 @@ export default function HomePage() {
); );
} }
interface SubPageSelectorProps {
currentSubPage: ESubPage
setCurrentSubPage: Dispatch<SetStateAction<ESubPage>>
}
function SubPageSelector(props: SubPageSelectorProps) {
return (
<div className={"w-full flex flex-col justify-center items-stretch pt-4 p-4 gap-2"}>
<Button
onClick={()=>props.setCurrentSubPage(ESubPage.Home)}
disabled={props.currentSubPage === ESubPage.Home}
className={"gap-1 font-bold"}>
<Home/>
Accueil
</Button>
<NewFileModal/>
<Button
onClick={()=>props.setCurrentSubPage(ESubPage.Documentation)}
disabled={props.currentSubPage === ESubPage.Documentation}>
<NotepadTextDashed />
Documentation
</Button>
</div>
)
}
export interface ISubPageProps {
currentSubPage: ESubPage
}
function SubPage(props: ISubPageProps) {
switch (props.currentSubPage) {
case ESubPage.Home:
return (<SubHomePage/>)
case ESubPage.Documentation:
return (<>Doc</>)
default:
return (<>Default</>)
}
}

View File

@ -23,7 +23,7 @@ export function NewFileModal(props: NewFileModalProps) {
</DialogTrigger> </DialogTrigger>
<DialogContent> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle>Ajout d'un fichier</DialogTitle> <DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription> <DialogDescription>
This action cannot be undone. This will permanently delete your account This action cannot be undone. This will permanently delete your account
and remove your data from our servers. and remove your data from our servers.

View File

@ -1,56 +0,0 @@
import { NewFileModal } from "../new-file-modal";
import { Button } from "../ui/button"
import { Home, NotepadTextDashed } from 'lucide-react';
import {
SubHomePage
} from './sub-home-page';
import { Dispatch, SetStateAction } from 'react';
import {
SubDocPage
} from 'apps/frontend/src/components/sub-pages/sub-doc-page';
export interface SubPageSelectorProps {
currentSubPage: ESubPage
setCurrentSubPage: Dispatch<SetStateAction<ESubPage>>
}
export enum ESubPage {
Home,
Documentation,
}
export function SubPageSelector(props: SubPageSelectorProps) {
return (
<div className={"w-full flex flex-col justify-center items-stretch pt-4 p-4 gap-2"}>
<Button
onClick={()=>props.setCurrentSubPage(ESubPage.Home)}
disabled={props.currentSubPage === ESubPage.Home}
className={"gap-1 font-bold"}>
<Home/>
Accueil
</Button>
<NewFileModal/>
<Button
onClick={()=>props.setCurrentSubPage(ESubPage.Documentation)}
disabled={props.currentSubPage === ESubPage.Documentation}>
<NotepadTextDashed />
Documentation
</Button>
</div>
)
}
export interface ISubPageProps {
currentSubPage: ESubPage
}
export function SubPage(props: ISubPageProps) {
switch (props.currentSubPage) {
case ESubPage.Home:
return (<SubHomePage/>)
case ESubPage.Documentation:
return (<SubDocPage/>)
default:
return (<>Default</>)
}
}

View File

@ -1,14 +0,0 @@
import { useState } from 'react';
export interface SubHomePageProps {
}
export function SubDocPage(props: SubHomePageProps) {
const [isLoaded, setIsLoaded] = useState<boolean>(false);
return (<section className={"w-full h-full rounded bg-card flex flex-col"}>
<h1 className={"text-2xl m-2 font-bold"}>Documentations</h1>
</section>)
}

View File

@ -1,8 +1,4 @@
import { useState } from 'react'; import { useState } from 'react';
import { HomeIcon } from 'lucide-react';
import {
FilesDataTable, filesTableColumns
} from 'apps/frontend/src/components/tables/files-table';
export interface SubHomePageProps { export interface SubHomePageProps {
@ -12,27 +8,7 @@ export interface SubHomePageProps {
export function SubHomePage(props: SubHomePageProps) { export function SubHomePage(props: SubHomePageProps) {
const [isLoaded, setIsLoaded] = useState<boolean>(false); const [isLoaded, setIsLoaded] = useState<boolean>(false);
return (<section className={"w-full h-full rounded bg-card flex flex-col"}> return (<section className={"w-full h-full rounded bg-card"}>
<div className={"flex flex-row justify-start items-center gap-2 m-2"}>
<HomeIcon
className={"w-8 h-8 text-secondary"}
/>
<h1 className={"text-2xl font-bold"}>Page principal</h1>
</div>
<div className={"m-1 flex flex-col justify-start items-center w-5/6 self-center h-full"}>
<FilesDataTable columns={filesTableColumns} data={[{
"uuid": "bbc17f8c-244d-4a44-8faf-c5e1ec0786bf",
"fileName": "test",
"checksum": "60d6473dc75edd2e885cc32c098f0379a5dd2d8175de0df1ef7526636b2a03f5",
"extension": "jpeg",
"groupId": null,
"fileSize": 483636,
"fileType": "2c1fb8eb-59b1-4bef-b50d-6bc854f46105",
"isRestricted": false,
"isDocumentation": false,
"uploadedAt": "2024-10-21T11:40:36.350Z",
"uploadedBy": "Avnyr"
}]}/>
</div>
</section>) </section>)
} }

View File

@ -1,201 +0,0 @@
"use client"
import {
ColumnDef,
flexRender,
getCoreRowModel, getPaginationRowModel, getSortedRowModel, SortingState,
useReactTable
} from '@tanstack/react-table';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "../ui/table"
import { Button } from '../ui/button';
import { Badge } from '../ui/badge'
import { ArrowUpDown, Clock, Download, Trash } from 'lucide-react';
import { useState } from 'react';
import Link from 'next/link';
// This type is used to define the shape of our data.
// You can use a Zod schema here if you want.
export type IFile = {
uuid: string;
fileName: string;
checksum: string;
extension: string;
groupId: string | null;
fileSize: number;
fileType: string;
isRestricted: boolean;
isDocumentation: boolean;
uploadedAt: string;
uploadedBy: string;
}
function ContextButtonForFile() {
return (<div className={"scale-75"}>
<Button variant={"destructive"}><Trash/></Button>
</div>)
}
export const filesTableColumns: ColumnDef<IFile>[] = [
{
accessorKey: "fileName",
header: ({ column }) => {
return (<div className={"flex justify-center items-center"}>
Nom du fichier
</div>)
},
},
{
accessorKey: "uploadedBy",
header: ({ column }) => {
return (<div className={"flex justify-center items-center"}>
Autheur(s)
</div>)
},
},
{
accessorKey: "uploadedAt",
header: ({ column }) => {
return (
<Button
variant="ghost"
className={"flex w-full"}
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Ajouté le
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
)
},
cell: ({ row }) => {
const date = new Date(row.getValue("uploadedAt"))
const formatted = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()} à ${date.getHours()}:${date.getMinutes()}`
return (<div className={"flex justify-center items-center"}>
<Badge
variant="outline"
className={"gap-1 flex w-fit items-center"}>
<Clock className={"w-4 h-4"} />
<p className={"font-light"}>
{formatted}
</p>
</Badge>
</div>)
},
},
{
accessorKey: "extension",
header: ({ column }) => {
return (<div className={"flex justify-center items-center"}>
Extension du fichier
</div>)
},
cell: ({ row }) => {
const extension = row.getValue("extension") as string;
return (<div className={"flex justify-center items-center"}>
<code className={"bg-gray-300 p-1 px-2 rounded-full"}>{extension}</code>
</div>)
},
},
{
id: "actions",
header: ({ column }) => {
return (<div className={"flex justify-center items-center"}>
Actions
</div>)
},
cell: ({ row }) => {
const file = row.original
return (<div className={"flex gap"}>
<Button variant={"ghost"} asChild>
<Link
href={`http://localhost:3333/api/files/${file.uuid}`}
>
<Download />
Télécharger
</Link>
</Button>
<ContextButtonForFile/>
</div>)
},
},
]
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[]
data: TData[]
}
export function FilesDataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = useState<SortingState>([])
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
state: {
sorting,
},
})
return (
<div className="rounded-md border w-full">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
Auccun résultat
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
)
}

View File

@ -45,7 +45,6 @@
"@radix-ui/react-toggle": "^1.1.0", "@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0", "@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.3", "@radix-ui/react-tooltip": "^1.1.3",
"@tanstack/react-table": "^8.20.5",
"argon2": "^0.41.1", "argon2": "^0.41.1",
"axios": "^1.7.7", "axios": "^1.7.7",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",

22
pnpm-lock.yaml generated
View File

@ -110,9 +110,6 @@ importers:
'@radix-ui/react-tooltip': '@radix-ui/react-tooltip':
specifier: ^1.1.3 specifier: ^1.1.3
version: 1.1.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 1.1.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@tanstack/react-table':
specifier: ^8.20.5
version: 8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
argon2: argon2:
specifier: ^0.41.1 specifier: ^0.41.1
version: 0.41.1 version: 0.41.1
@ -3196,17 +3193,6 @@ packages:
resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
engines: {node: '>=10'} engines: {node: '>=10'}
'@tanstack/react-table@8.20.5':
resolution: {integrity: sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==}
engines: {node: '>=12'}
peerDependencies:
react: '>=16.8'
react-dom: '>=16.8'
'@tanstack/table-core@8.20.5':
resolution: {integrity: sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==}
engines: {node: '>=12'}
'@tokenizer/token@0.3.0': '@tokenizer/token@0.3.0':
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
@ -12655,14 +12641,6 @@ snapshots:
dependencies: dependencies:
defer-to-connect: 2.0.1 defer-to-connect: 2.0.1
'@tanstack/react-table@8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@tanstack/table-core': 8.20.5
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
'@tanstack/table-core@8.20.5': {}
'@tokenizer/token@0.3.0': {} '@tokenizer/token@0.3.0': {}
'@tootallnate/once@2.0.0': {} '@tootallnate/once@2.0.0': {}