Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
Commit eecced51 authored by Christophe Chaudier's avatar Christophe Chaudier :rocket:
Browse files

Merge branch 'compagnons-devops.fr-tools' into 'main'

Add tools pages

Closes #28

See merge request !28
parents 31441914 19d73fcb
No related branches found
No related tags found
1 merge request!28Add tools pages
Pipeline #32584 passed
---
sidebar_position: 1
---
# Tutorial Intro
Let's discover **Docusaurus in less than 5 minutes**.
## Getting Started
Get started by **creating a new site**.
Or **try Docusaurus immediately** with **[docusaurus.new](https://docusaurus.new)**.
### What you'll need
- [Node.js](https://nodejs.org/en/download/) version 16.14 or above:
- When installing Node.js, you are recommended to check all checkboxes related to dependencies.
## Generate a new site
Generate a new Docusaurus site using the **classic template**.
The classic template will automatically be added to your project after you run the command:
```bash
npm init docusaurus@latest my-website classic
```
You can type this command into Command Prompt, Powershell, Terminal, or any other integrated terminal of your code editor.
The command also installs all necessary dependencies you need to run Docusaurus.
## Start your site
Run the development server:
```bash
cd my-website
npm run start
```
The `cd` command changes the directory you're working with. In order to work with your newly created Docusaurus site, you'll need to navigate the terminal there.
The `npm run start` command builds your website locally and serves it through a development server, ready for you to view at http://localhost:3000/.
Open `docs/intro.md` (this page) and edit some lines: the site **reloads automatically** and displays your changes.
---
title: "Outils"
description: "La liste des outils évoqués dans l'Actu DevOps"
full_width: 'true'
---
import Outils from "../src/components/outils";
# Les outils des Compagnons du DevOps
La liste des outils évoqués dans [le podcast Actus DevOps](http://radio.compagnons-devops.fr).
<Outils/>
......@@ -85,6 +85,11 @@ const config = {
label: '🎓 Formations',
position: 'left'
},
{
to: '/docs/outils',
label: '🧰 Outils',
position: 'left'
},
{
label: 'Soutenir',
position: 'left',
......
This diff is collapsed.
import React from "react";
import dataFile from '@site/static/outils.json';
import Link from "@docusaurus/Link";
import {
createColumnHelper,
Column,
Table,
useReactTable,
ColumnFiltersState,
getCoreRowModel,
getFilteredRowModel,
getFacetedRowModel,
getFacetedUniqueValues,
getFacetedMinMaxValues,
getPaginationRowModel,
sortingFns,
getSortedRowModel,
FilterFn,
SortingFn,
ColumnDef,
flexRender,
FilterFns,
} from "@tanstack/react-table";
import {
RankingInfo,
rankItem,
compareItems,
} from "@tanstack/match-sorter-utils";
declare module "@tanstack/table-core" {
interface FilterFns {
fuzzy: FilterFn<unknown>;
}
interface FilterMeta {
itemRank: RankingInfo;
}
}
const fuzzyFilter: FilterFn<any> = (row, columnId, value, addMeta) => {
// Rank the item
const itemRank = rankItem(row.getValue(columnId), value);
// Store the itemRank info
addMeta({
itemRank,
});
// Return if the item should be filtered in/out
return itemRank.passed;
};
interface RefData {
Name: string;
Description: string;
Links: string[];
Type: string;
Date: Date;
Reporter: string;
TimecodeURL: string;
}
const fuzzySort: SortingFn<any> = (rowA, rowB, columnId) => {
let dir = 0;
// Only sort by rank if the column has ranking information
if (rowA.columnFiltersMeta[columnId]) {
dir = compareItems(
rowA.columnFiltersMeta[columnId]?.itemRank!,
rowB.columnFiltersMeta[columnId]?.itemRank!,
);
}
// Provide an alphanumeric fallback for when the item ranks are equal
return dir === 0 ? sortingFns.alphanumeric(rowA, rowB, columnId) : dir;
};
function displayDate(date: Date) {
const months = [
"Janvier",
"Février",
"Mars",
"Avril",
"Mai",
"Juin",
"Juillet",
"Août",
"Septembre",
"Octobre",
"Novembre",
"Decembre",
];
return `${months[date.getMonth()].startsWith('O') || months[date.getMonth()].startsWith('A') ? 'd\'' : 'de ' }${months[date.getMonth()]} ${date.getFullYear()}`;
}
export default function App() {
const columnHelper = createColumnHelper<RefData>();
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[],
);
const [globalFilter, setGlobalFilter] = React.useState("");
const columns = React.useMemo<ColumnDef<RefData, any>[]>(() => [
{
header: "Tools",
footer: (props) => props.column.id,
columns: [
columnHelper.accessor("Name", {
cell: props => <>{props.row.original.Links[0] ? <Link to={props.row.original.Links[0]} > {props.getValue()} </Link> : <span>{props.getValue()}</span>}</>,
header: () => <span>Name</span>
}),
columnHelper.accessor("Type", {
cell: props => <><span>{props.getValue()}</span></>,
header: () => <span>Type</span>
}),
columnHelper.accessor("Description", {
cell: props => <p>{props.row.original.Description}</p>,
header: () => <span>Description</span>
}),
columnHelper.accessor("Date", {
cell: props => <>
Présenté {props.row.original.Reporter && <> par {props.row.original.Reporter} </>} dans {props.row.original.TimecodeURL!== '' ? <Link to={props.row.original.TimecodeURL}> Actus DevOps {displayDate(props.row.original.Date)} </Link> : <span> Actus DevOps {displayDate(props.row.original.Date)}</span>}
<ul className="linkslist">
{props.row.original.Links.map((link, idx) => {
return (
<li key={idx}> <Link to={link}>{link.replace('https://', '')}</Link> </li>
)
})}
</ul>
</>,
header: () => <span>Liens</span>
}),
],
}
], []);
// Fileter data and set Date as a Date type.
const defaultData = dataFile.map((item) => {
return {
Name: item.Name,
Description: item.Description,
Links: item.Links,
Reporter: item.Reporter,
Date: new Date(item.Date),
Type: item.Type,
TimecodeURL: item.TimecodeURL,
};
});
const [data, setData] = React.useState<RefData[]>(() => defaultData);
const table = useReactTable({
data,
columns,
filterFns: {
fuzzy: fuzzyFilter,
},
state: {
columnFilters,
globalFilter,
},
onColumnFiltersChange: setColumnFilters,
onGlobalFilterChange: setGlobalFilter,
globalFilterFn: fuzzyFilter,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(),
getFacetedMinMaxValues: getFacetedMinMaxValues(),
debugTable: false,
debugHeaders: false,
debugColumns: false,
initialState: {
pagination: {
pageSize: 50,
},
},
});
React.useEffect(() => {
if (table.getState().columnFilters[0]?.id === "Name") {
if (table.getState().sorting[0]?.id !== "Name") {
table.setSorting([{ id: "Name", desc: false }]);
}
}
}, [table.getState().columnFilters[0]?.id]);
return (
<div>
<select
value={table.getState().pagination.pageSize}
onChange={(e) => {
table.setPageSize(Number(e.target.value));
}}
>
{[50, 100, 200].map((pageSize) => (
<option key={pageSize} value={pageSize}>
Afficher {pageSize}
</option>
))}
</select>
<table>
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<th key={header.id} colSpan={header.colSpan} style={{position: 'relative'
}}>
{header.isPlaceholder ? null : (
<>
<div
{...{
onClick: header.column.getToggleSortingHandler(),
}}
>
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
{{
asc: " 🔼",
desc: " 🔽",
}[header.column.getIsSorted() as string] ?? null}
</div>
{header.column.getCanFilter() ? (
<div>
<Filter column={header.column} table={table}/>
</div>
) : null}
</>
)}
</th>
);
})}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => {
return (
<tr key={row.id}>
{row.getVisibleCells().map((cell) => {
return (
<td key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
<div>
<button
onClick={() => table.setPageIndex(0)}
disabled={!table.getCanPreviousPage()}
>
{"<<"}
</button>
<button
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
{"<"}
</button>
<button
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
{">"}
</button>
<button
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
disabled={!table.getCanNextPage()}
>
{">>"}
</button>
<span>
<strong>
{table.getState().pagination.pageIndex + 1} of{" "}
{table.getPageCount()}
</strong>
</span>
<span>
| page:
<input
type="number"
defaultValue={table.getState().pagination.pageIndex + 1}
onChange={(e) => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
table.setPageIndex(page);
}}
/>
</span>
<select
value={table.getState().pagination.pageSize}
onChange={(e) => {
table.setPageSize(Number(e.target.value));
}}
>
{[50, 100, 200].map((pageSize) => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
<div>{table.getPrePaginationRowModel().rows.length} entrées</div>
</div>
);
}
function Filter({
column,
table,
}: {
column: Column<any, unknown>;
table: Table<any>;
}) {
const firstValue = table
.getPreFilteredRowModel()
.flatRows[0]?.getValue(column.id);
const columnFilterValue = column.getFilterValue();
const sortedUniqueValues = React.useMemo(
() =>
typeof firstValue === "number"
? []
: Array.from(column.getFacetedUniqueValues().keys()).sort(),
[column.getFacetedUniqueValues()],
);
return typeof firstValue === "number" ? (
<div>
<div className="flex space-x-2">
<DebouncedInput
type="number"
min={Number(column.getFacetedMinMaxValues()?.[0] ?? "")}
max={Number(column.getFacetedMinMaxValues()?.[1] ?? "")}
value={(columnFilterValue as [number, number])?.[0] ?? ""}
onChange={(value) =>
column.setFilterValue((old: [number, number]) => [value, old?.[1]])
}
placeholder={`Min ${
column.getFacetedMinMaxValues()?.[0]
? `(${column.getFacetedMinMaxValues()?.[0]})`
: ""
}`}
/>
<DebouncedInput
type="number"
min={Number(column.getFacetedMinMaxValues()?.[0] ?? "")}
max={Number(column.getFacetedMinMaxValues()?.[1] ?? "")}
value={(columnFilterValue as [number, number])?.[1] ?? ""}
onChange={(value) =>
column.setFilterValue((old: [number, number]) => [old?.[0], value])
}
placeholder={`Max ${
column.getFacetedMinMaxValues()?.[1]
? `(${column.getFacetedMinMaxValues()?.[1]})`
: ""
}`}
/>
</div>
</div>
) : (
<>
<datalist id={column.id + "list"}>
{sortedUniqueValues.slice(0, 5000).map((value: any, index) => (
<option value={value} key={value+index} />
))}
</datalist>
<DebouncedInput
type="text"
value={(columnFilterValue ?? "") as string}
onChange={(value) => column.setFilterValue(value)}
placeholder={`Recherche... (${column.getFacetedUniqueValues().size})`}
list={column.id + "list"}
style={{width:'100%'}}
/>
<div className="h-1" />
</>
);
}
// A debounced input react component
function DebouncedInput({
value: initialValue,
onChange,
debounce = 500,
...props
}: {
value: string | number;
onChange: (value: string | number) => void;
debounce?: number;
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, "onChange">) {
const [value, setValue] = React.useState(initialValue);
React.useEffect(() => {
setValue(initialValue);
}, [initialValue]);
React.useEffect(() => {
const timeout = setTimeout(() => {
onChange(value);
}, debounce);
return () => clearTimeout(timeout);
}, [value]);
return (
<input
{...props}
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}
......@@ -108,6 +108,21 @@ a, .table-of-contents__link--active {
text-decoration: none;
}
.linkslist {
list-style: none;
margin-left: 0;
padding-left: 0;
}
.linkslist li:before {
content: "🔗";
padding-right: 5px;
}
main > .container {
max-width: initial !important;
}
@media (max-width: 560px) {
.video-responsive {
width: 100%;
......
......@@ -19,6 +19,8 @@
--ifm-button-primary-color: #380d5b;
--ifm-button-primary-hover: #582780;
--ifm-navbar-link-hover-color: #e8ac00;
--ifm-menu-color-active: var(--ifm-button-primary-color);
--ifm-breadcrumb-color-active: #27093f;
/* Fonts */
--ifm-font-family-base: 'roboto', sans;
......@@ -42,6 +44,6 @@
--ifm-button-primary-color: #ffbd00;
--ifm-button-primary-hover: #ffd666;
--ifm-link-hover-color: var(--ifm-button-primary-hover);
--text-contrast: #000;
--ifm-breadcrumb-color-active: #fff;
}
ihtml {
font-family: sans-serif;
font-size: 14px;
}
table {
border: 1px solid lightgray;
}
tbody {
border-bottom: 1px solid lightgray;
}
th {
border-bottom: 1px solid lightgray;
border-right: 1px solid lightgray;
padding: 2px 4px;
}
tfoot {
color: gray;
}
tfoot th {
font-weight: normal;
}
import React from 'react';
import Layout from '@theme-original/DocItem/Layout';
import {useDoc} from '@docusaurus/theme-common/internal';
export default function LayoutWrapper(props) {
const doc = useDoc();
return (
<div className={doc.frontMatter.full_width ? "" : "container"}>
<Layout {...props} />
</div>
);
}
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment