Compare commits
3 Commits
30706118a8
...
ee127f431c
Author | SHA1 | Date | |
---|---|---|---|
ee127f431c | |||
13c77bfc32 | |||
2d6815efb6 |
@ -203,7 +203,7 @@ export class FilesController {
|
||||
return await this.filesService.removeFileType(typeId);
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.FOUND)
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Get(":fileId")
|
||||
async getFile(@Param("fileId") fileId: string) {
|
||||
return await this.filesService.get(fileId);
|
||||
|
@ -19,7 +19,8 @@ import {
|
||||
TypeDto,
|
||||
} from "apps/backend/src/app/machines/machines.dto";
|
||||
import { MachinesService } from "apps/backend/src/app/machines/machines.service";
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||
import { IMachinesTable } from 'apps/backend/src/app/db/schema';
|
||||
|
||||
@ApiTags('Machines')
|
||||
@Controller("machines")
|
||||
|
2
apps/frontend/next-env.d.ts
vendored
2
apps/frontend/next-env.d.ts
vendored
@ -2,4 +2,4 @@
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
|
||||
|
@ -15,7 +15,7 @@ export default function RootLayout({
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={"h-screen w-screen bg-card flex flex-col justify-between items-center police-ubuntu dark"}>
|
||||
<body className={"h-screen w-screen bg-card flex flex-col justify-between items-center police-ubuntu"}>
|
||||
<Header/>
|
||||
{children}
|
||||
<Footer/>
|
||||
|
@ -1,21 +1,11 @@
|
||||
"use client"
|
||||
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 {
|
||||
ResizableHandle,
|
||||
ResizablePanel,
|
||||
ResizablePanelGroup
|
||||
} from 'apps/frontend/src/components/ui/resizable';
|
||||
import {
|
||||
SubHomePage
|
||||
} from 'apps/frontend/src/components/sub-pages/sub-home-page';
|
||||
|
||||
export enum ESubPage {
|
||||
Home,
|
||||
Documentation,
|
||||
}
|
||||
import { ESubPage, SubPage, SubPageSelector } from '../components/sub-pages';
|
||||
|
||||
export default function HomePage() {
|
||||
const [currentSubPage, setCurrentSubPage] = useState<ESubPage>(0)
|
||||
@ -43,43 +33,4 @@ 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</>)
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ export function NewFileModal(props: NewFileModalProps) {
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Are you absolutely sure?</DialogTitle>
|
||||
<DialogTitle>Ajout d'un fichier</DialogTitle>
|
||||
<DialogDescription>
|
||||
This action cannot be undone. This will permanently delete your account
|
||||
and remove your data from our servers.
|
||||
|
56
apps/frontend/src/components/sub-pages/index.tsx
Normal file
56
apps/frontend/src/components/sub-pages/index.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
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</>)
|
||||
}
|
||||
}
|
14
apps/frontend/src/components/sub-pages/sub-doc-page.tsx
Normal file
14
apps/frontend/src/components/sub-pages/sub-doc-page.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
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>)
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
import { useState } from 'react';
|
||||
import { HomeIcon } from 'lucide-react';
|
||||
import {
|
||||
FilesDataTable, filesTableColumns
|
||||
} from 'apps/frontend/src/components/tables/files-table';
|
||||
|
||||
|
||||
export interface SubHomePageProps {
|
||||
@ -8,7 +12,27 @@ export interface SubHomePageProps {
|
||||
export function SubHomePage(props: SubHomePageProps) {
|
||||
const [isLoaded, setIsLoaded] = useState<boolean>(false);
|
||||
|
||||
return (<section className={"w-full h-full rounded bg-card"}>
|
||||
|
||||
return (<section className={"w-full h-full rounded bg-card flex flex-col"}>
|
||||
<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>)
|
||||
}
|
201
apps/frontend/src/components/tables/files-table.tsx
Normal file
201
apps/frontend/src/components/tables/files-table.tsx
Normal file
@ -0,0 +1,201 @@
|
||||
"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>
|
||||
)
|
||||
}
|
@ -45,6 +45,7 @@
|
||||
"@radix-ui/react-toggle": "^1.1.0",
|
||||
"@radix-ui/react-toggle-group": "^1.1.0",
|
||||
"@radix-ui/react-tooltip": "^1.1.3",
|
||||
"@tanstack/react-table": "^8.20.5",
|
||||
"argon2": "^0.41.1",
|
||||
"axios": "^1.7.7",
|
||||
"class-transformer": "^0.5.1",
|
||||
|
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
@ -110,6 +110,9 @@ importers:
|
||||
'@radix-ui/react-tooltip':
|
||||
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)
|
||||
'@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:
|
||||
specifier: ^0.41.1
|
||||
version: 0.41.1
|
||||
@ -3193,6 +3196,17 @@ packages:
|
||||
resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
|
||||
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':
|
||||
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
|
||||
|
||||
@ -12641,6 +12655,14 @@ snapshots:
|
||||
dependencies:
|
||||
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': {}
|
||||
|
||||
'@tootallnate/once@2.0.0': {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user