mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-21 21:53:30 +00:00
Use typescript api for user pictures and allow imports across js files
* Add imports paths for js files in node * Add a ts version of fetchPaginated * Update documentation
This commit is contained in:
parent
9247696c1c
commit
9199f91151
@ -1,5 +1,7 @@
|
|||||||
|
import { paginated } from "#core:utils/api";
|
||||||
import { HttpReader, ZipWriter } from "@zip.js/zip.js";
|
import { HttpReader, ZipWriter } from "@zip.js/zip.js";
|
||||||
import { showSaveFilePicker } from "native-file-system-adapter";
|
import { showSaveFilePicker } from "native-file-system-adapter";
|
||||||
|
import { picturesFetchPictures } from "#openapi";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef UserProfile
|
* @typedef UserProfile
|
||||||
@ -28,14 +30,14 @@ import { showSaveFilePicker } from "native-file-system-adapter";
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef PicturePageConfig
|
* @typedef PicturePageConfig
|
||||||
* @param {string} apiUrl Url of the api endpoint to fetch pictures from the user
|
* @param {number} userId Id of the user to get the pictures from
|
||||||
**/
|
**/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load user picture page with a nice download bar
|
* Load user picture page with a nice download bar
|
||||||
* @param {PicturePageConfig} Configuration
|
* @param {PicturePageConfig} Configuration
|
||||||
**/
|
**/
|
||||||
window.loadPicturePage = (config) => {
|
window.window.loadPicturePage = (config) => {
|
||||||
document.addEventListener("alpine:init", () => {
|
document.addEventListener("alpine:init", () => {
|
||||||
Alpine.data("user_pictures", () => ({
|
Alpine.data("user_pictures", () => ({
|
||||||
isDownloading: false,
|
isDownloading: false,
|
||||||
@ -44,8 +46,10 @@ window.loadPicturePage = (config) => {
|
|||||||
albums: {},
|
albums: {},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
// biome-ignore lint/correctness/noUndeclaredVariables: imported from script.json
|
this.pictures = await paginated(picturesFetchPictures, {
|
||||||
this.pictures = await fetchPaginated(config.apiUrl);
|
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
||||||
|
query: { users_identified: [config.userId] },
|
||||||
|
});
|
||||||
this.albums = this.pictures.reduce((acc, picture) => {
|
this.albums = this.pictures.reduce((acc, picture) => {
|
||||||
if (!acc[picture.album]) {
|
if (!acc[picture.album]) {
|
||||||
acc[picture.album] = [];
|
acc[picture.album] = [];
|
||||||
|
46
core/static/webpack/utils/api.ts
Normal file
46
core/static/webpack/utils/api.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import type { Options, RequestResult } from "@hey-api/client-fetch";
|
||||||
|
|
||||||
|
interface PaginatedResponse<T> {
|
||||||
|
count: number;
|
||||||
|
next: string | null;
|
||||||
|
previous: string | null;
|
||||||
|
results: T[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PaginatedRequest {
|
||||||
|
query?: {
|
||||||
|
page?: number;
|
||||||
|
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
||||||
|
page_size?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaginatedEndpoint<T> = <ThrowOnError extends boolean = false>(
|
||||||
|
options?: Options<PaginatedRequest, ThrowOnError>,
|
||||||
|
) => RequestResult<PaginatedResponse<T>, unknown, ThrowOnError>;
|
||||||
|
|
||||||
|
export const paginated = async <T>(
|
||||||
|
endpoint: PaginatedEndpoint<T>,
|
||||||
|
options?: PaginatedRequest,
|
||||||
|
) => {
|
||||||
|
const maxPerPage = 199;
|
||||||
|
options.query.page_size = maxPerPage;
|
||||||
|
options.query.page = 1;
|
||||||
|
|
||||||
|
const firstPage = (await endpoint(options)).data;
|
||||||
|
const results = firstPage.results;
|
||||||
|
|
||||||
|
const nbElements = firstPage.count;
|
||||||
|
const nbPages = Math.ceil(nbElements / maxPerPage);
|
||||||
|
|
||||||
|
if (nbPages > 1) {
|
||||||
|
const promises: Promise<T[]>[] = [];
|
||||||
|
for (let i = 2; i <= nbPages; i++) {
|
||||||
|
const nextPage = structuredClone(options);
|
||||||
|
nextPage.query.page = i;
|
||||||
|
promises.push(endpoint(nextPage).then((res) => res.data.results));
|
||||||
|
}
|
||||||
|
results.push(...(await Promise.all(promises)).flat());
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
@ -62,9 +62,7 @@
|
|||||||
{{ super() }}
|
{{ super() }}
|
||||||
<script>
|
<script>
|
||||||
window.addEventListener("DOMContentLoaded", () => {
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
loadPicturePage({
|
loadPicturePage({ userId: {{ object.id }} });
|
||||||
apiUrl: "{{ url("api:pictures") }}?users_identified={{ object.id }}"
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock script %}
|
{% endblock script %}
|
||||||
|
39
docs/howto/js-import-paths.md
Normal file
39
docs/howto/js-import-paths.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
Vous avez ajouté une application et vous voulez y mettre du javascript ?
|
||||||
|
|
||||||
|
Vous voulez importer depuis cette nouvelle application dans votre script géré par webpack ?
|
||||||
|
|
||||||
|
Eh bien il faut manuellement enregistrer dans node où les trouver et c'est très simple.
|
||||||
|
|
||||||
|
D'abord, il faut ajouter dans node via `package.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
"imports": {
|
||||||
|
// ...
|
||||||
|
"#mon_app:*": "./mon_app/static/webpack/*"
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Ensuite, pour faire fonctionne l'auto-complétion, il faut configurer `tsconfig.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
// ...
|
||||||
|
"paths": {
|
||||||
|
// ...
|
||||||
|
"#mon_app:*": ["./mon_app/static/webpack/*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Et c'est tout !
|
||||||
|
|
||||||
|
!!!note
|
||||||
|
|
||||||
|
Il se peut qu'il soit nécessaire de redémarrer `./manage.py runserver` pour
|
||||||
|
que les changements prennent effet.
|
@ -35,8 +35,9 @@ les fichiers sont à mettre dans un dossier `static/webpack` de l'application à
|
|||||||
Pour accéder au fichier, il faut utiliser `static` comme pour le reste mais en ajouter `webpack/` comme prefix.
|
Pour accéder au fichier, il faut utiliser `static` comme pour le reste mais en ajouter `webpack/` comme prefix.
|
||||||
|
|
||||||
```jinja
|
```jinja
|
||||||
{# Exemple pour ajouter sith/core/webpack/alpine-index.js #}
|
{# Example pour ajouter sith/core/webpack/alpine-index.js #}
|
||||||
<script src="{{ static('webpack/alpine-index.js') }}" defer></script>
|
<script src="{{ static('webpack/alpine-index.js') }}" defer></script>
|
||||||
|
<script src="{{ static('webpack/other-index.ts') }}" defer></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
!!!note
|
!!!note
|
||||||
@ -45,6 +46,16 @@ Pour accéder au fichier, il faut utiliser `static` comme pour le reste mais en
|
|||||||
Les autres fichiers sont disponibles à l'import dans le JavaScript comme
|
Les autres fichiers sont disponibles à l'import dans le JavaScript comme
|
||||||
si ils étaient tous au même niveau.
|
si ils étaient tous au même niveau.
|
||||||
|
|
||||||
|
### Les imports au sein des fichiers de webpack
|
||||||
|
|
||||||
|
Pour importer au sein de webpack, faut préfixer ses imports de `#app:`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { paginated } from "#core:utils/api";
|
||||||
|
```
|
||||||
|
|
||||||
## Comment ça fonctionne le post processing ?
|
## Comment ça fonctionne le post processing ?
|
||||||
|
|
||||||
Le post processing est géré par le module `staticfiles`. Les fichiers sont
|
Le post processing est géré par le module `staticfiles`. Les fichiers sont
|
||||||
|
@ -72,6 +72,7 @@ nav:
|
|||||||
- Gérer les migrations: howto/migrations.md
|
- Gérer les migrations: howto/migrations.md
|
||||||
- Gérer les traductions: howto/translation.md
|
- Gérer les traductions: howto/translation.md
|
||||||
- Gérer les statics: howto/statics.md
|
- Gérer les statics: howto/statics.md
|
||||||
|
- Ajouter un chemin d'import javascript: howto/js-import-paths.md
|
||||||
- Configurer pour la production: howto/prod.md
|
- Configurer pour la production: howto/prod.md
|
||||||
- Ajouter un logo de promo: howto/logo.md
|
- Ajouter un logo de promo: howto/logo.md
|
||||||
- Ajouter une cotisation: howto/subscriptions.md
|
- Ajouter une cotisation: howto/subscriptions.md
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"sideEffects": [".css"],
|
"sideEffects": [".css"],
|
||||||
"imports": {
|
"imports": {
|
||||||
"#openapi": "./staticfiles/generated/openapi/index.ts"
|
"#openapi": "./staticfiles/generated/openapi/index.ts",
|
||||||
|
"#core:*": "./core/static/webpack/*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.25.2",
|
"@babel/core": "^7.25.2",
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"paths": {
|
"paths": {
|
||||||
"#openapi": ["./staticfiles/generated/openapi/index.ts"]
|
"#openapi": ["./staticfiles/generated/openapi/index.ts"],
|
||||||
|
"#core:*": ["./core/static/webpack/*"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user