mirror of
https://github.com/ae-utbm/sith.git
synced 2026-09-09 14:04:36 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35a55ff95a
|
||
|
|
00cae33a33
|
||
|
|
4bfcb6a267
|
@@ -15,9 +15,6 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% extends "core/base.jinja" %}
|
{% extends "core/base.jinja" %}
|
||||||
{% block additional_css %}
|
|
||||||
<link rel="stylesheet" href="{{ static("club/list.scss") }}">
|
|
||||||
{% endblock %}
|
|
||||||
{% block description -%}
|
{% block description -%}
|
||||||
{% trans %}The list of all clubs existing at UTBM.{% endtrans %}
|
{% trans %}The list of all clubs existing at UTBM.{% endtrans %}
|
||||||
{%- endblock %}
|
{%- endblock %}
|
||||||
@@ -26,6 +23,12 @@
|
|||||||
{%- endblock %}
|
{%- endblock %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% block additional_css %}
|
||||||
|
{% if not is_fragment %}
|
||||||
|
<link rel="stylesheet" href="{{ static("club/list.scss") }}">
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% from "core/macros.jinja" import paginate_htmx %}
|
{% from "core/macros.jinja" import paginate_htmx %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -33,15 +36,17 @@
|
|||||||
<h3>{% trans %}Filters{% endtrans %}</h3>
|
<h3>{% trans %}Filters{% endtrans %}</h3>
|
||||||
<form
|
<form
|
||||||
id="club-list-filters"
|
id="club-list-filters"
|
||||||
hx-get="{{ url("club:club_list") }}"
|
method="GET"
|
||||||
|
hx-action="{{ url("club:club_list") }}"
|
||||||
hx-target="#content"
|
hx-target="#content"
|
||||||
hx-swap="outerHtml"
|
hx-swap="innerHTML"
|
||||||
hx-push-url="true"
|
hx-push-url="true"
|
||||||
|
hx-disable="find input, find button"
|
||||||
>
|
>
|
||||||
<div class="row gap-4x">
|
<div class="row gap-4x">
|
||||||
{{ form }}
|
{{ form }}
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-blue margin-bottom">
|
<button class="btn btn-blue margin-bottom">
|
||||||
<i class="fa fa-magnifying-glass"></i>{% trans %}Search{% endtrans %}
|
<i class="fa fa-magnifying-glass"></i>{% trans %}Search{% endtrans %}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ document.body.addEventListener(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
htmx.config.transitions = true;
|
||||||
Object.assign(window, { htmx });
|
Object.assign(window, { htmx });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
{% if is_fragment %}
|
{% if is_fragment %}
|
||||||
hx-post="{{ action }}"
|
hx-post="{{ action }}"
|
||||||
hx-target="#content"
|
hx-target="#content"
|
||||||
hx-swap="outerHtml"
|
hx-swap="innerHTML"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
>{% trans %}Confirm{% endtrans %}</button>
|
>{% trans %}Confirm{% endtrans %}</button>
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
{% if is_fragment %}
|
{% if is_fragment %}
|
||||||
hx-get="{{ previous }}"
|
hx-get="{{ previous }}"
|
||||||
hx-target="#content"
|
hx-target="#content"
|
||||||
hx-swap="outerHtml"
|
hx-swap="innerHTML"
|
||||||
{% else %}
|
{% else %}
|
||||||
action="window.history.back()"
|
action="window.history.back()"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -39,13 +39,13 @@
|
|||||||
<p><button
|
<p><button
|
||||||
hx-get="{{ url('core:file_moderate', file_id=f.id) }}"
|
hx-get="{{ url('core:file_moderate', file_id=f.id) }}"
|
||||||
hx-target="#content"
|
hx-target="#content"
|
||||||
hx-swap="outerHtml"
|
hx-swap="innerHTML"
|
||||||
>{% trans %}Moderate{% endtrans %}</button> -
|
>{% trans %}Moderate{% endtrans %}</button> -
|
||||||
{% set current_page = url('core:file_moderation') + "?page=" + page_obj.number | string %}
|
{% set current_page = url('core:file_moderation') + "?page=" + page_obj.number | string %}
|
||||||
<button
|
<button
|
||||||
hx-get="{{ url('core:file_delete', file_id=f.id) }}?next={{ current_page | urlencode }}&previous={{ current_page | urlencode }}"
|
hx-get="{{ url('core:file_delete', file_id=f.id) }}?next={{ current_page | urlencode }}&previous={{ current_page | urlencode }}"
|
||||||
hx-target="#file-{{ loop.index }}"
|
hx-target="#file-{{ loop.index }}"
|
||||||
hx-swap="outerHtml"
|
hx-swap="innerHTML"
|
||||||
>{% trans %}Delete{% endtrans %}</button></p>
|
>{% trans %}Delete{% endtrans %}</button></p>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
+49
-35
@@ -1,5 +1,9 @@
|
|||||||
import { getCurrentUrlParams, updateQueryString } from "#core:utils/history";
|
import {
|
||||||
import { type SimpleUeSchema, ueFetchUeList } from "#openapi";
|
getCurrentUrlParams,
|
||||||
|
History,
|
||||||
|
updateQueryString,
|
||||||
|
} from "#core:utils/history.ts";
|
||||||
|
import { ueFetchUeList } from "#openapi";
|
||||||
|
|
||||||
const pageDefault = 1;
|
const pageDefault = 1;
|
||||||
const pageSizeDefault = 100;
|
const pageSizeDefault = 100;
|
||||||
@@ -8,42 +12,38 @@ document.addEventListener("alpine:init", () => {
|
|||||||
Alpine.data("ue_search", () => ({
|
Alpine.data("ue_search", () => ({
|
||||||
ues: {
|
ues: {
|
||||||
count: 0,
|
count: 0,
|
||||||
next: null as string | null,
|
next: null,
|
||||||
previous: null as string | null,
|
previous: null,
|
||||||
results: [] as SimpleUeSchema[],
|
results: [],
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
page: pageDefault,
|
page: pageDefault,
|
||||||
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
||||||
page_size: pageSizeDefault,
|
page_size: pageSizeDefault,
|
||||||
search: "",
|
search: "",
|
||||||
department: [] as string[],
|
department: [],
|
||||||
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
||||||
credit_type: [] as string[],
|
credit_type: [],
|
||||||
semester: [] as string[],
|
semester: [],
|
||||||
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
||||||
to_change: [] as { param: string; value: string }[],
|
to_change: [],
|
||||||
|
pushstate: History.Push,
|
||||||
|
|
||||||
// dummy implementation to make TS happy.
|
update: undefined,
|
||||||
// The real function is initialized in init
|
|
||||||
update: () => {
|
|
||||||
console.warn("Update not yet initialized");
|
|
||||||
},
|
|
||||||
|
|
||||||
initializeArgs() {
|
initializeArgs() {
|
||||||
const url = getCurrentUrlParams();
|
const url = getCurrentUrlParams();
|
||||||
this.page = Number.parseInt(url.get("page") || pageDefault.toString(), 10);
|
this.pushstate = History.Replace;
|
||||||
this.page_size = Number.parseInt(
|
|
||||||
url.get("page_size") || pageSizeDefault.toString(),
|
this.page = Number.parseInt(url.get("page"), 10) || pageDefault;
|
||||||
10,
|
this.page_size = Number.parseInt(url.get("page_size"), 10) || pageSizeDefault;
|
||||||
);
|
|
||||||
this.search = url.get("search") || "";
|
this.search = url.get("search") || "";
|
||||||
this.department = url.getAll("department");
|
this.department = url.getAll("department");
|
||||||
this.credit_type = url.getAll("credit_type");
|
this.credit_type = url.getAll("credit_type");
|
||||||
/* The semester is easier to use on the backend as an enum (spring/autumn/both/none)
|
/* The semester is easier to use on the backend as an enum (spring/autumn/both/none)
|
||||||
and easier to use on the frontend as an array ([spring, autumn]).
|
and easier to use on the frontend as an array ([spring, autumn]).
|
||||||
Thus there is some conversion involved when both communicate together */
|
Thus there is some conversion involved when both communicate together */
|
||||||
this.semester = url.get("semester")?.split("_AND_") || [];
|
this.semester = url.has("semester") ? url.get("semester").split("_AND_") : [];
|
||||||
|
|
||||||
this.update();
|
this.update();
|
||||||
},
|
},
|
||||||
@@ -51,11 +51,15 @@ document.addEventListener("alpine:init", () => {
|
|||||||
async init() {
|
async init() {
|
||||||
this.update = Alpine.debounce(async () => {
|
this.update = Alpine.debounce(async () => {
|
||||||
/* Create the whole url before changing everything all at once */
|
/* Create the whole url before changing everything all at once */
|
||||||
for (const val of this.to_change) {
|
const first = this.to_change.shift();
|
||||||
updateQueryString(val.param, val.value);
|
let url = updateQueryString(first.param, first.value, History.None);
|
||||||
|
for (const value of this.to_change) {
|
||||||
|
url = updateQueryString(value.param, value.value, History.None, url);
|
||||||
}
|
}
|
||||||
|
updateQueryString(first.param, first.value, this.pushstate, url);
|
||||||
await this.fetchData(); /* reload data on form change */
|
await this.fetchData(); /* reload data on form change */
|
||||||
this.to_change = [];
|
this.to_change = [];
|
||||||
|
this.pushstate = History.Push;
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
const searchParams = ["search", "department", "credit_type", "semester"];
|
const searchParams = ["search", "department", "credit_type", "semester"];
|
||||||
@@ -63,37 +67,47 @@ document.addEventListener("alpine:init", () => {
|
|||||||
|
|
||||||
for (const param of searchParams) {
|
for (const param of searchParams) {
|
||||||
this.$watch(param, () => {
|
this.$watch(param, () => {
|
||||||
|
if (this.pushstate !== History.Push) {
|
||||||
|
/* This means that we are doing a mass param edit */
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* Reset pagination on search */
|
/* Reset pagination on search */
|
||||||
this.page = pageDefault;
|
this.page = pageDefault;
|
||||||
this.page_size = pageSizeDefault;
|
this.page_size = pageSizeDefault;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (const param of searchParams.concat(paginationParams)) {
|
for (const param of searchParams.concat(paginationParams)) {
|
||||||
this.$watch(param, (value: string) => {
|
this.$watch(param, (value) => {
|
||||||
this.to_change.push({ param: param, value: value });
|
this.to_change.push({ param: param, value: value });
|
||||||
this.update();
|
this.update();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
window.addEventListener("popstate", () => {
|
||||||
|
this.initializeArgs();
|
||||||
|
});
|
||||||
this.initializeArgs();
|
this.initializeArgs();
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetchData() {
|
async fetchData() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
const args = {
|
||||||
const res = await ueFetchUeList({
|
|
||||||
query: {
|
|
||||||
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
||||||
page_size: this.page_size,
|
page_size: this.page_size,
|
||||||
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
};
|
||||||
credit_type: this.credit_type.length > 0 ? this.credit_type : undefined,
|
for (const [param, value] of new URL(
|
||||||
semester: this.semester.length > 0 ? this.semester : undefined,
|
window.location.href,
|
||||||
department: this.department.length > 0 ? this.department : undefined,
|
).searchParams.entries()) {
|
||||||
search: this.search || undefined,
|
// Deal with array type params
|
||||||
},
|
if (["credit_type", "department", "semester"].includes(param)) {
|
||||||
});
|
if (args[param] === undefined) {
|
||||||
if (res.data !== undefined) {
|
args[param] = [];
|
||||||
this.ues = res.data;
|
|
||||||
}
|
}
|
||||||
|
args[param].push(value);
|
||||||
|
} else {
|
||||||
|
args[param] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.ues = (await ueFetchUeList({ query: args })).data;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
Reference in New Issue
Block a user