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

Add the openapi specs for the documentation + restructure some parts of the code #5

Merged
merged 10 commits into from
Feb 15, 2025
Merged
29 changes: 14 additions & 15 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,10 @@ export function MyTemplate(props: Props) {

```ts
import Elysia, { t } from "elysia"
import { generateTablePage, type Context } from "../generateTablePage"
import {
generateTablePage,
type Context,
} from "../page-generators/generateTablePage"
import type { Translator } from "../Translator"
```

Expand Down Expand Up @@ -198,20 +201,16 @@ import { NewNamespace } from "./namespaces/Namespace"
new Elysia()
// [...]
.get("/", ({ t }) => Home({ t }))
.group(
"",
{
query: t.Object({ page: t.Number({ default: 1 }) }),
},
(app) =>
app
.use(NewNamespace) // <-- Add it here
.use(GeographicalReferences)
.use(Phytosanitary)
.use(Viticulture)
.use(Weather)
.use(Credits)
)
.get("/documentation*", ({ t, output }) => generateDocumentation(t, output))
.guard({
query: t.Object({ page: t.Number({ default: 1 }) }),
})
.use(NewNamespace) // <-- Add the namespace after the guard
.use(GeographicalReferences)
.use(Phytosanitary)
.use(Viticulture)
.use(Weather)
.use(Credits)
```

### How to add a list page
Expand Down
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions public/icons/book.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 44 additions & 3 deletions public/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ p {

a:link {
text-decoration: none;
color: rgb(65, 96, 253) !important;
color: rgb(65, 96, 253);
}

a:visited {
text-decoration: none;
color: rgb(65, 96, 253) !important;
color: rgb(65, 96, 253);
}

nav {
Expand Down Expand Up @@ -61,6 +61,25 @@ header {
position: relative;
}

nav a {
text-decoration: none;
text-transform: uppercase;
font-weight: bold;
color: #2c2c2c !important;
border-radius: 10px;
padding: 10px;
transition-duration: 0.25s;
}

nav a:hover {
color: #272727;
background-color: #ebebeb;
}

nav a.active {
color: #3dc798 !important;
}

.col {
text-decoration-line: none;
background-color: transparent;
Expand Down Expand Up @@ -206,6 +225,28 @@ tr:hover {
box-shadow: rgba(61, 199, 152, 0.35) 0px 5px 15px;
}

.section-link {
display: flex;
color: black !important;
border-radius: 15px;
padding: 5px;
width: 100%;
align-items: center;
box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
transition-duration: 0.25s;
}

.section-link:hover {
background-color: rgb(39, 174, 96);
color: white !important;
box-shadow: rgba(39, 174, 96, 0.608) 0px 3px 8px;
}

.section-link:hover img {
filter: invert(100%) sepia(45%) saturate(97%) hue-rotate(186deg)
brightness(113%) contrast(100%);
}

form {
width: 100%;
overflow: none;
Expand Down Expand Up @@ -257,7 +298,7 @@ input[type="number"] {
font-size: medium;
}

span {
.span {
font-weight: bold;
text-align: center;
margin-left: auto;
Expand Down
75 changes: 75 additions & 0 deletions src/applyRequestConfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { match } from "shulk"
import { useTranslator } from "./Translator"
import { Pool } from "pg"
import type { OutputFormat } from "./utils"

const DB_HOST = import.meta.env.DB_HOST
const DB_PORT = parseInt(import.meta.env.DB_PORT as string)
const DB_USER = import.meta.env.DB_USER
const DB_PASSWORD = import.meta.env.DB_PASSWORD
const DB_NAME = import.meta.env.DB_NAME

const pool = new Pool({
host: DB_HOST,
port: DB_PORT,
user: DB_USER,
password: DB_PASSWORD,
database: DB_NAME,
})

const AVAILABLE_LANGUAGES = ["fr", "en"]
const DEFAULT_LANGUAGE = "fr"

type BaseRequest = {
headers: Record<string, string | undefined>
path: string
}

export function applyRequestConfiguration(req: BaseRequest) {
const { headers, path } = req

const clientDesiredLanguage =
headers["accept-language"]?.split(",")[0]?.split("-")[0] || ""

const serverLanguage = AVAILABLE_LANGUAGES.includes(clientDesiredLanguage)
? clientDesiredLanguage
: DEFAULT_LANGUAGE

const locale = match(serverLanguage).with({
fr: "fr-FR",
en: "en-US",
_otherwise: "en-US",
})

const extension: string | undefined = path.split(".")[1]

const output: OutputFormat = match(extension).with({
json: "json",
csv: "csv",
_otherwise: "html",
})

const dateTimeFormatter = {
DateTime: (date: Date | number) =>
Intl.DateTimeFormat(locale, {
dateStyle: "short",
timeStyle: "short",
}).format(date),
Date: (date: Date | number) =>
Intl.DateTimeFormat(locale, {
dateStyle: "short",
}).format(date),
Time: (date: Date | number) =>
Intl.DateTimeFormat(locale, {
timeStyle: "short",
}).format(date),
}

return {
output,
language: serverLanguage,
t: useTranslator(serverLanguage),
db: pool,
dateTimeFormatter,
}
}
7 changes: 6 additions & 1 deletion src/assets/translations.csv
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ navigation_next_page,Page suivante,Next page

home_title,Accueil,Home
home_warning,Ceci est une version en cours de développement. Des dysfonctionnements peuvent subsister et des traductions peuvent manquer.,This is a development version. Some bugs may persist and some translations could still be missing.
home_explore,Explorer,Explore
home_explore,Explorer les jeux de données,Explore datasets
home_how_to_use,Utiliser Lexicon en 3 étapes,How to use
home_how_to_step1,Explorez et trouvez le jeu de données qui répond à vos besoins,Explore and find the dataset you need
home_how_to_step2,Filtrez les données à l'aide des formulaires si nécessaire,Filter the data with the forms if you need to
home_how_to_step3,Trouvez le format de sortie (JSON / CSV) qui vous convient et copiez l'URL ou téléchargez le document,Find the most adapted output format (JSON / CSV) for your usecase and copy the page URL or download the document
home_full_documentation,Voir la documentation complète,See the complete documentation

geographical_references_title,Références géographiques,Geographical references

Expand Down Expand Up @@ -124,4 +125,8 @@ credits_datasource,Source des données,Data sources
credits_provider,Fournisseur,Providers
credits_license,Licence,License

documentation_title,Documentation,Documentation
documentation_description,La documentation de l'API Lexicon,Documentation of Lexicon API
documentation_weather_hourly_reports,Relevés horaires d'une station donnée,Hourly weather reports for a given weather station.

country_FR,France,France
120 changes: 16 additions & 104 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,125 +1,37 @@
import { Elysia, t } from "elysia"
import { swagger } from "@elysiajs/swagger"
import { html, Html } from "@elysiajs/html"
import { Home } from "./templates/Home"
import packageJson from "../package.json"
import { Credits, CreditTable } from "./namespaces/Credits"
import { useTranslator } from "./Translator"
import { Credits } from "./namespaces/Credits"
import { staticPlugin } from "@elysiajs/static"
import { Pool } from "pg"
import type { OutputFormat } from "./utils"
import { Phytosanitary } from "./namespaces/Phytosanitary"
import { GeographicalReferences } from "./namespaces/GeographicalReferences"
import { match } from "shulk"
import cors from "@elysiajs/cors"
import { Viticulture } from "./namespaces/Viticulture"
import { Weather } from "./namespaces/Weather"
import { generateDocumentation } from "./page-generators/generateDocumentation"
import { applyRequestConfiguration } from "./applyRequestConfiguration"
import { Seed } from "./namespaces/Seed"
import { Production } from "./namespaces/Production"

const DB_HOST = import.meta.env.DB_HOST
const DB_PORT = parseInt(import.meta.env.DB_PORT as string)
const DB_USER = import.meta.env.DB_USER
const DB_PASSWORD = import.meta.env.DB_PASSWORD
const DB_NAME = import.meta.env.DB_NAME

const pool = new Pool({
host: DB_HOST,
port: DB_PORT,
user: DB_USER,
password: DB_PASSWORD,
database: DB_NAME,
})

const PORT = import.meta.env.PORT as string
const AVAILABLE_LANGUAGES = ["fr", "en"]

new Elysia()
new Elysia({ serve: { idleTimeout: 255 } })
.use(staticPlugin())
.use(cors())
.use(
swagger({
path: "/documentation",
documentation: {
info: {
title: "Lexicon REST API documentation",
version: packageJson.version,
},
},
})
)
.use(html())
.derive(({ headers, path }) => {
const clientDesiredLanguage =
headers["accept-language"]?.split(",")[0]?.split("-")[0] || ""

const serverLanguage = AVAILABLE_LANGUAGES.includes(clientDesiredLanguage)
? (clientDesiredLanguage as string)
: "fr"

let output: OutputFormat = "html"
if (path.endsWith(".json")) {
output = "json"
} else if (path.endsWith(".csv")) {
output = "csv"
}

const locale = match(serverLanguage).with({
fr: "fr-FR",
en: "en-US",
_otherwise: "en-US",
})

const dateTimeFormatter = {
DateTime: (date: Date | number) =>
Intl.DateTimeFormat(locale, {
// timeZone: timezone,
dateStyle: "short",
timeStyle: "short",
}).format(date),
Date: (date: Date | number) =>
Intl.DateTimeFormat(locale, {
// timeZone: timezone,
dateStyle: "short",
}).format(date),
Time: (date: Date | number) =>
Intl.DateTimeFormat(locale, {
// timeZone: timezone,
timeStyle: "short",
}).format(date),
}

return {
output,
language: serverLanguage,
t: useTranslator(serverLanguage),
db: pool,
dateTimeFormatter,
}
})
.derive(applyRequestConfiguration)
.get("/", ({ t }) => Home({ t }))
.group(
"",
{
query: t.Object({ page: t.Number({ default: 1 }) }),
},
(app) =>
app
.use(Production)
.use(Seed)
.use(GeographicalReferences)
.use(Phytosanitary)
.use(Viticulture)
.use(Weather)
.use(Credits)
)
.get("/datasources", async ({ db }) =>
console.log(
(await CreditTable(db).select().run()).map((credits) =>
credits.map((c) => c.datasource)
).val
)
)
.get("/documentation*", ({ t, output }) => generateDocumentation(t, output))
.guard({
query: t.Object({ page: t.Number({ default: 1 }) }),
})
.use(GeographicalReferences)
.use(Phytosanitary)
.use(Production)
.use(Seed)
.use(Viticulture)
.use(Weather)
.use(Credits)
.listen(PORT)

console.log("Lexicon REST API is open on port " + PORT)
Expand Down
6 changes: 5 additions & 1 deletion src/namespaces/Credits.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import Elysia from "elysia"
import { Table } from "../Database"
import { Hypermedia } from "../Hypermedia"
import { generateTablePage, type Context } from "../generateTablePage"
import {
generateTablePage,
type Context,
} from "../page-generators/generateTablePage"
import { AutoTable } from "../templates/AutoTable"
import { Ok } from "shulk"
import { AutoList } from "../templates/AutoList"
Expand Down Expand Up @@ -56,6 +59,7 @@ export const Credits = new Elysia({ prefix: "/credits" })
}),
],
},
t,
})
)
.get("/datasources*", async (cxt: Context) =>
Expand Down
Loading