This commit is contained in:
roydfalk 2025-08-21 21:45:39 +00:00
parent a0c0e9eb22
commit 9f0468ac0d
20 changed files with 643 additions and 173 deletions

View file

@ -9,13 +9,16 @@
"common.timezone_shift": "Zeitzonen-Verschiebung", "common.timezone_shift": "Zeitzonen-Verschiebung",
"common.date": "Datum", "common.date": "Datum",
"common.time": "Uhzeit", "common.time": "Uhzeit",
"domain.group.name.label": "Name",
"domain.member.member": "Mitglied", "domain.member.member": "Mitglied",
"domain.member.membership_number.label": "Mitgliedsnummer", "domain.member.membership_number.label": "Mitgliedsnummer",
"domain.member.name.label": "Name",
"domain.member.name_real_value.label": "Echter Name", "domain.member.name_real_value.label": "Echter Name",
"domain.member.name_real_index.label": "Namens-Index", "domain.member.name_real_index.label": "Namens-Index",
"domain.member.groups.label": "Gruppen", "domain.member.groups.label": "Gruppen",
"domain.member.registered.label": "registriert", "domain.member.registered.label": "registriert",
"domain.member.enabled.label": "aktiviert", "domain.member.enabled.label": "aktiviert",
"domain.member.email_address.label": "E-Mail-Adresse",
"domain.member.email_address_private.label": "private E-Mail-Adresse", "domain.member.email_address_private.label": "private E-Mail-Adresse",
"domain.member.email_address_veiled.label": "pseudonymisierte E-Mail-Adresse", "domain.member.email_address_veiled.label": "pseudonymisierte E-Mail-Adresse",
"domain.member.email_address_nominal.label": "namentliche E-Mail-Adresse", "domain.member.email_address_nominal.label": "namentliche E-Mail-Adresse",
@ -31,6 +34,9 @@
"page.login.password": "Passwort", "page.login.password": "Passwort",
"page.login.submit": "Anmelden", "page.login.submit": "Anmelden",
"page.logout.title": "Abmelden", "page.logout.title": "Abmelden",
"page.group_list.title": "Gruppen",
"page.group_create.title": "Gruppe anlegen",
"page.group_create.form.submit": "Abschicken",
"page.member_create.title": "Mitglied anlegen", "page.member_create.title": "Mitglied anlegen",
"page.member_list.title": "Mitglieder", "page.member_list.title": "Mitglieder",
"page.member_view.title": "Mitglied", "page.member_view.title": "Mitglied",

View file

@ -9,13 +9,16 @@
"common.timezone_shift": "timezone shift", "common.timezone_shift": "timezone shift",
"common.date": "date", "common.date": "date",
"common.time": "time", "common.time": "time",
"domain.group.name.label": "name",
"domain.member.member": "member", "domain.member.member": "member",
"domain.member.membership_number.label": "membership number", "domain.member.membership_number.label": "membership number",
"domain.member.name.label": "name",
"domain.member.name_real_value.label": "real name", "domain.member.name_real_value.label": "real name",
"domain.member.name_real_index.label": "name index", "domain.member.name_real_index.label": "name index",
"domain.member.groups.label": "groups", "domain.member.groups.label": "groups",
"domain.member.registered.label": "registered", "domain.member.registered.label": "registered",
"domain.member.enabled.label": "enabled", "domain.member.enabled.label": "enabled",
"domain.member.email_address.label": "e-mail address",
"domain.member.email_address_private.label": "private e-mail address", "domain.member.email_address_private.label": "private e-mail address",
"domain.member.email_address_veiled.label": "veiled e-mail address", "domain.member.email_address_veiled.label": "veiled e-mail address",
"domain.member.email_address_nominal.label": "nominal e-mail address", "domain.member.email_address_nominal.label": "nominal e-mail address",
@ -31,6 +34,9 @@
"page.login.password": "password", "page.login.password": "password",
"page.login.submit": "login", "page.login.submit": "login",
"page.logout.title": "logout", "page.logout.title": "logout",
"page.group_list.title": "groups",
"page.group_create.title": "Create group",
"page.group_create.form.submit": "submit",
"page.member_create.title": "Create member", "page.member_create.title": "Create member",
"page.member_list.title": "Members", "page.member_list.title": "Members",
"page.member_view.title": "Member", "page.member_view.title": "Member",

View file

@ -230,6 +230,91 @@ namespace _espe.backend
} }
/**
*/
export async function group_list(
) : Promise<
Array<
{
id : int;
name : string;
}
>
>
{
return (
abstract_call(
"GET",
"/group/list"
)
);
}
/**
*/
export async function group_get(
group_id : int
) : Promise<
{
name : string;
}
>
{
return (
abstract_call(
"GET",
("/group/read/" + group_id.toFixed(0))
)
);
}
/**
*/
export async function group_add(
group_object : {
name : string;
}
) : Promise<
int
>
{
return (
abstract_call(
"POST",
"/group/add",
{
"data": group_object,
}
)
);
}
/**
*/
export async function group_modify(
group_id : int,
group_object : {
name : string;
}
) : Promise<
void
>
{
return (
abstract_call(
"PATCH",
("/group/modify/" + group_id.toFixed(0)),
{
"data": group_object,
}
)
);
}
/** /**
*/ */
export async function member_list( export async function member_list(
@ -239,9 +324,7 @@ namespace _espe.backend
{ {
id : int; id : int;
preview : { preview : {
membership_number : string; name : string;
name_real_value : string;
name_real_index : int;
}; };
} }
> >
@ -262,21 +345,11 @@ namespace _espe.backend
id : int id : int
) : Promise< ) : Promise<
{ {
membership_number : string; name : string;
name_real_value : string; email_address : (null | string);
name_real_index : int; groups : Array<int>;
email_address_private : (null | string);
groups : Array<string>;
registered : boolean;
enabled : boolean; enabled : boolean;
email_use_veiled_address : boolean;
email_use_nominal_address : boolean;
email_redirect_to_private_address : boolean;
email_allow_sending : boolean;
password_set : boolean; password_set : boolean;
email_address_veiled : string;
email_address_nominal : string;
name_login : string;
} }
> >
{ {
@ -393,9 +466,8 @@ namespace _espe.backend
export async function member_modify( export async function member_modify(
id : int, id : int,
data : { data : {
email_address_private : (null | string); email_address : (null | string);
groups : Array<string>; groups : Array<int>;
registered : boolean;
enabled : boolean; enabled : boolean;
} }
) : Promise<void> ) : Promise<void>
@ -503,7 +575,7 @@ namespace _espe.backend
return abstract_call( return abstract_call(
"GET", "GET",
lib_plankton.string.coin( lib_plankton.string.coin(
"/invite/list", "/invitation/list",
{ {
} }
) )
@ -533,7 +605,7 @@ namespace _espe.backend
return abstract_call( return abstract_call(
"GET", "GET",
lib_plankton.string.coin( lib_plankton.string.coin(
"/invite/read?id={{id}}", "/invitation/read?id={{id}}",
{ {
"id": id.toFixed(0), "id": id.toFixed(0),
} }
@ -567,7 +639,7 @@ namespace _espe.backend
{ {
return abstract_call( return abstract_call(
"POST", "POST",
"/invite/create", "/invitation/create",
{ {
"data": { "data": {
"data": data, "data": data,
@ -599,7 +671,7 @@ namespace _espe.backend
return abstract_call( return abstract_call(
"GET", "GET",
lib_plankton.string.coin( lib_plankton.string.coin(
"/invite/examine?key={{key}}", "/invitation/examine?key={{key}}",
{ {
"key": key "key": key
} }
@ -630,7 +702,7 @@ namespace _espe.backend
{ {
return abstract_call( return abstract_call(
"POST", "POST",
"/invite/accept", "/invitation/accept",
{ {
"data": { "data": {
"key": key, "key": key,

132
source/logic/input_set.ts Normal file
View file

@ -0,0 +1,132 @@
/*
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*/
namespace _espe
{
/**
* @todo outsource to plankton
*/
export class class_input_set implements lib_plankton.zoo_input.interface_input<Set<string>>
{
/**
*/
private options : Array<string>;
/**
*/
private show_element : ((element : string) => string);
/**
*/
private read_only : boolean;
/**
*/
private checkboxes : Map<string, HTMLInputElement>;
/**
*/
public constructor(
options : Array<string>,
show_element : ((element : string) => string),
{
"read_only": read_only = false,
} : {
read_only ?: boolean;
} = {
}
)
{
this.show_element = show_element;
this.options = options;
this.read_only = read_only;
this.checkboxes = new Map<string, HTMLInputElement>();
}
/**
* [implementation]
*/
public setup(
parent : HTMLElement
) : Promise<void>
{
for (const option of this.options)
{
// label
const element_container : HTMLElement = document.createElement("label");
element_container.classList.add("plankton_input_set_option");
element_container.setAttribute("rel", option);
// checkbox
{
const element_checkbox : HTMLInputElement = document.createElement("input");
element_checkbox.setAttribute("type", "checkbox");
element_container.appendChild(element_checkbox);
this.checkboxes.set(option, element_checkbox);
}
// text
{
const element_text : HTMLElement = document.createElement("span");
element_text.textContent = this.show_element(option);
element_container.appendChild(element_text);
}
parent.appendChild(element_container);
}
return Promise.resolve<void>(undefined);
}
/**
* [implementation]
*/
public read(
) : Promise<Set<string>>
{
const result : Set<string> = new Set<string>();
for (const option of this.options)
{
const element_checkbox : HTMLInputElement = this.checkboxes.get(option);
if (element_checkbox.checked) {
result.add(option);
}
}
return Promise.resolve<Set<string>>(result);
}
/**
* [implementation]
*/
public write(
value : Set<string>
) : Promise<void>
{
for (const option of this.options)
{
const element_checkbox : HTMLInputElement = this.checkboxes.get(option);
element_checkbox.checked = value.has(option);
}
return Promise.resolve<void>(undefined);
}
}
}

View file

@ -59,6 +59,11 @@ function setup_nav(
"label": lib_plankton.translate.get("page.login.title"), "label": lib_plankton.translate.get("page.login.title"),
"classes": ["logged_out"], "classes": ["logged_out"],
}, },
{
"location": {"name": "group_list", "parameters": {}},
"label": lib_plankton.translate.get("page.group_list.title"),
"classes": ["logged_in"],
},
{ {
"location": {"name": "member_list", "parameters": {}}, "location": {"name": "member_list", "parameters": {}},
"label": lib_plankton.translate.get("page.member_list.title"), "label": lib_plankton.translate.get("page.member_list.title"),

View file

@ -0,0 +1,51 @@
/*
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*/
lib_plankton.zoo_page.register(
"group_create",
(parameters, target_element) => {
target_element.appendChild(template_request("group_create"));
target_element.querySelector(".group_create-title").textContent = lib_plankton.translate.get("page.group_create.title");
const form = new lib_plankton.zoo_form.class_form<
{name : string},
{name : string}
>(
value => value,
representation => representation,
new lib_plankton.zoo_input.class_input_group(
[
{
"name": "name",
"input": new lib_plankton.zoo_input.class_input_text(),
"label": lib_plankton.translate.get("domain.group.name.label"),
},
]
),
[
{
"label": lib_plankton.translate.get("page.group_create.form.submit"),
"procedure": async (get_value, get_representation) => {
const value = await get_value();
const id : int = await _espe.backend.group_add(value);
lib_plankton.zoo_page.set({"name": "group_view", "parameters": {"id": id}});
},
}
]
);
form.setup(target_element.querySelector(".group_create-form") as HTMLElement);
}
);

View file

@ -0,0 +1,19 @@
<!--
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
-->
<template id="group_create">
<h2 class="group_create-title"></h2>
<div class="group_create-form"></div>
</template>

View file

@ -0,0 +1,15 @@
/*
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*/

View file

@ -0,0 +1,90 @@
/*
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*/
lib_plankton.zoo_page.register(
"group_list",
(parameters, target_element) => {
type type_item = {
id : int;
name : string;
};
const term : (null | string) = (parameters["term"] ?? "");
target_element.appendChild(template_request("group_list"));
target_element.querySelector(".group_list-title").textContent = lib_plankton.translate.get("page.group_list.title");
// create link
{
const element : HTMLElement = target_element.querySelector(".group_list-create");
element.setAttribute(
"href",
lib_plankton.zoo_page.encode(
{
"name": "group_create",
"parameters": {
}
}
)
);
element.textContent = lib_plankton.translate.get("page.group_create.title");
}
const search : lib_plankton.zoo_search.type_search<type_item> = lib_plankton.zoo_search.make<type_item>(
(term) => _espe.backend.group_list(),
{
"encode_item": (item) => lib_plankton.string.coin(
"{{name}}",
{
"name": item.name,
}
),
"hooks_begin": [
(term) => {
lib_plankton.zoo_page.set(
{
"name": "group_list",
"parameters": {
"term": term,
}
}
);
}
],
"hooks_select": [
(item) => {
lib_plankton.zoo_page.set(
{
"name": "group_view",
"parameters": {
"id": item.id.toFixed(0),
}
}
);
}
]
}
);
lib_plankton.zoo_search.render(
search,
target_element.querySelector(".group_list-search"),
{
"state": {
"term": term,
}
}
);
}
);

View file

@ -0,0 +1,22 @@
<!--
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
-->
<template id="group_list">
<h2 class="group_list-title"></h2>
<div class="group_list-links">
<a class="group_list-create"></a>
</div>
<div class="group_list-search"></div>
</template>

View file

@ -0,0 +1,19 @@
/*
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*/
.group_list-links
{
margin-bottom: 16px;
}

View file

@ -0,0 +1,58 @@
/*
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*/
lib_plankton.zoo_page.register(
"group_view",
async (parameters, target_element) => {
const id : int = parseInt(parameters["id"]);
let dom_fragment : DocumentFragment = template_request("group_view");
dom_fragment.querySelector(".group_view-title").textContent = lib_plankton.translate.get("page.group_view.title");
const group_object = await _espe.backend.group_get(id);
const form = new lib_plankton.zoo_form.class_form<
{name : string},
{name : string}
>(
value => value,
representation => representation,
new lib_plankton.zoo_input.class_input_group(
[
{
"name": "name",
"input": new lib_plankton.zoo_input.class_input_text(),
"label": lib_plankton.translate.get("domain.group.name.label"),
},
]
),
[
{
"label": lib_plankton.translate.get("page.group_create.form.submit"),
"procedure": async (get_value, get_representation) => {
const value = await get_value();
await _espe.backend.group_modify(id, value);
lib_plankton.zoo_page.set({"name": "group_list", "parameters": {}});
},
}
]
);
await form.setup(dom_fragment.querySelector(".group_view-form") as HTMLElement);
await form.input_write(group_object);
target_element.appendChild(dom_fragment);
},
);

View file

@ -0,0 +1,22 @@
<!--
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
-->
<template id="group_view">
<section class="group_view">
<h2 class="group_view-title"></h2>
<div class="group_view-form">
</div>
</section>
</template>

View file

@ -0,0 +1,21 @@
/*
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*/
.group_view-title
{
display: none;
}

View file

@ -112,7 +112,7 @@ lib_plankton.zoo_page.register(
new lib_plankton.zoo_input.class_input_group( new lib_plankton.zoo_input.class_input_group(
[ [
{ {
"name": "membership_number", "name": "name",
"input": new lib_plankton.zoo_input.class_input_group( "input": new lib_plankton.zoo_input.class_input_group(
[ [
{ {
@ -127,7 +127,7 @@ lib_plankton.zoo_page.register(
}, },
] ]
), ),
"label": lib_plankton.translate.get("domain.member.membership_number.label"), "label": lib_plankton.translate.get("domain.member.name.label"),
}, },
{ {
"name": "groups", "name": "groups",
@ -149,24 +149,6 @@ lib_plankton.zoo_page.register(
), ),
"label": lib_plankton.translate.get("domain.member.groups.label"), "label": lib_plankton.translate.get("domain.member.groups.label"),
}, },
{
"name": "name",
"input": new lib_plankton.zoo_input.class_input_group(
[
{
"name": "value",
"input": new lib_plankton.zoo_input.class_input_text(),
"label": indent(lib_plankton.translate.get("common.initial_value")),
},
{
"name": "changeable",
"input": new lib_plankton.zoo_input.class_input_checkbox(),
"label": indent(lib_plankton.translate.get("common.changeable")),
},
]
),
"label": lib_plankton.translate.get("domain.member.name_real_value.label"),
},
{ {
"name": "email_address", "name": "email_address",
"input": new lib_plankton.zoo_input.class_input_group( "input": new lib_plankton.zoo_input.class_input_group(
@ -183,7 +165,7 @@ lib_plankton.zoo_page.register(
}, },
] ]
), ),
"label": lib_plankton.translate.get("domain.member.email_address_private.label"), "label": lib_plankton.translate.get("domain.member.email_address.label"),
}, },
{ {
"name": "expiry", "name": "expiry",

View file

@ -127,7 +127,7 @@ lib_plankton.zoo_page.register(
[ [
{ {
"name": "url", "name": "url",
"input": new lib_plankton.zoo_input.class_input_text({"read_only": false}), "input": new lib_plankton.zoo_input.class_input_text({"read_only": true}),
"label": lib_plankton.translate.get("domain.invite.url.label"), "label": lib_plankton.translate.get("domain.invite.url.label"),
}, },
{ {
@ -136,7 +136,7 @@ lib_plankton.zoo_page.register(
"label": lib_plankton.translate.get("domain.invite.key.label"), "label": lib_plankton.translate.get("domain.invite.key.label"),
}, },
{ {
"name": "membership_number", "name": "name",
"input": new lib_plankton.zoo_input.class_input_group( "input": new lib_plankton.zoo_input.class_input_group(
[ [
{ {
@ -151,7 +151,7 @@ lib_plankton.zoo_page.register(
}, },
] ]
), ),
"label": lib_plankton.translate.get("domain.member.membership_number.label"), "label": lib_plankton.translate.get("domain.member.name.label"),
}, },
{ {
"name": "groups", "name": "groups",
@ -174,24 +174,6 @@ lib_plankton.zoo_page.register(
), ),
"label": lib_plankton.translate.get("domain.member.groups.label"), "label": lib_plankton.translate.get("domain.member.groups.label"),
}, },
{
"name": "name",
"input": new lib_plankton.zoo_input.class_input_group(
[
{
"name": "value",
"input": new lib_plankton.zoo_input.class_input_text({"read_only": true}),
"label": indent(lib_plankton.translate.get("common.initial_value")),
},
{
"name": "changeable",
"input": new lib_plankton.zoo_input.class_input_checkbox({"read_only": true}),
"label": indent(lib_plankton.translate.get("common.changeable")),
},
]
),
"label": lib_plankton.translate.get("domain.member.name_real_value.label"),
},
{ {
"name": "email_address", "name": "email_address",
"input": new lib_plankton.zoo_input.class_input_group( "input": new lib_plankton.zoo_input.class_input_group(
@ -208,7 +190,7 @@ lib_plankton.zoo_page.register(
}, },
] ]
), ),
"label": lib_plankton.translate.get("domain.member.email_address_private.label"), "label": lib_plankton.translate.get("domain.member.email_address.label"),
}, },
{ {
"name": "expiry", "name": "expiry",

View file

@ -19,9 +19,7 @@ lib_plankton.zoo_page.register(
type type_item = { type type_item = {
id : int; id : int;
preview : { preview : {
membership_number : string; name : string;
name_real_value : string;
name_real_index : int;
}; };
}; };
const term : (null | string) = (parameters["term"] ?? ""); const term : (null | string) = (parameters["term"] ?? "");
@ -50,19 +48,9 @@ lib_plankton.zoo_page.register(
(term) => _espe.backend.member_list(term), (term) => _espe.backend.member_list(term),
{ {
"encode_item": (item) => lib_plankton.string.coin( "encode_item": (item) => lib_plankton.string.coin(
"{{membership_number}} | {{name}}{{addition}}", "{{name}}",
{ {
"membership_number": item.preview.membership_number, "name": item.preview.name,
"name": item.preview.name_real_value,
"addition": (
(
(item.preview.name_real_index === null)
||
(item.preview.name_real_index <= 1)
)
? ""
: (" (" + item.preview.name_real_index.toFixed(0) + ")")
),
} }
), ),
"hooks_begin": [ "hooks_begin": [

View file

@ -22,63 +22,74 @@ lib_plankton.zoo_page.register(
dom_fragment.querySelector(".member_view-title").textContent = lib_plankton.translate.get("page.member_view.title"); dom_fragment.querySelector(".member_view-title").textContent = lib_plankton.translate.get("page.member_view.title");
/**
* @todo cache
*/
const groups_as_array : Array<{id : int; name : string;}> = await _espe.backend.group_list();
const groups_as_map : Map<int, {name : string;}> = new Map<int, {name : string;}>();
for (const group_thingy of groups_as_array)
{
groups_as_map.set(group_thingy.id, {"name": group_thingy.name});
}
const member_data = await _espe.backend.member_get(id); const member_data = await _espe.backend.member_get(id);
const form = new lib_plankton.zoo_form.class_form< const form = new lib_plankton.zoo_form.class_form<
{ {
membership_number : string; name : string;
name_real_value : string; groups : Array<int>;
name_real_index : int;
groups : Array<string>;
registered : boolean;
enabled : boolean; enabled : boolean;
email_address_private : (null | string); email_address : (null | string);
email_address_veiled : (null | string);
email_address_nominal : (null | string);
email_redirect_to_private_address : boolean;
email_allow_sending : boolean;
name_login : string;
password_set : boolean; password_set : boolean;
}, },
{ {
membership_number : string; name : string;
name_real_value : string; groups : Set<string>;
name_real_index : int;
groups : Array<string>;
registered : boolean;
enabled : boolean; enabled : boolean;
email_address_private : (null | string); email_address : (null | string);
email_address_veiled : (null | string);
email_address_nominal : (null | string);
email_redirect_to_private_address : boolean;
email_allow_sending : boolean;
name_login : string;
password_set : boolean; password_set : boolean;
} }
>( >(
value => value, value => ({
representation => representation, "name": value.name,
"groups": new Set<string>(value.groups.map(group_id => group_id.toFixed(0))),
"enabled": value.enabled,
"email_address": value.email_address,
"password_set": value.password_set,
}),
representation => ({
"name": representation.name,
"groups": (() => {
const array : Array<int> = [];
for (const group_id_encoded of representation.groups)
{
array.push(parseInt(group_id_encoded));
}
return array;
}) (),
"enabled": representation.enabled,
"email_address": representation.email_address,
"password_set": representation.password_set,
}),
new lib_plankton.zoo_input.class_input_group( new lib_plankton.zoo_input.class_input_group(
[ [
{ {
"name": "name_real_value", "name": "name",
"input": new lib_plankton.zoo_input.class_input_text({"read_only": true}), "input": new lib_plankton.zoo_input.class_input_text({"read_only": true}),
"label": lib_plankton.translate.get("domain.member.name_real_value.label"), "label": lib_plankton.translate.get("domain.member.name.label"),
},
{
"name": "name_real_index",
"input": new lib_plankton.zoo_input.class_input_number({"read_only": true}),
"label": lib_plankton.translate.get("domain.member.name_real_index.label"),
},
{
"name": "membership_number",
"input": new lib_plankton.zoo_input.class_input_text({"read_only": true}),
"label": lib_plankton.translate.get("domain.member.membership_number.label"),
}, },
{ {
"name": "groups", "name": "groups",
/*
"input": new lib_plankton.zoo_input.class_input_list( "input": new lib_plankton.zoo_input.class_input_list(
() => new lib_plankton.zoo_input.class_input_text() () => new lib_plankton.zoo_input.class_input_number()
),
*/
"input": new _espe.class_input_set(
groups_as_array.map(
group_thingy => group_thingy.id.toFixed(0)
),
group_id_encoded => groups_as_map.get(parseInt(group_id_encoded)).name
), ),
"label": lib_plankton.translate.get("domain.member.groups.label"), "label": lib_plankton.translate.get("domain.member.groups.label"),
}, },
@ -87,45 +98,15 @@ lib_plankton.zoo_page.register(
"input": new lib_plankton.zoo_input.class_input_checkbox(), "input": new lib_plankton.zoo_input.class_input_checkbox(),
"label": lib_plankton.translate.get("domain.member.enabled.label"), "label": lib_plankton.translate.get("domain.member.enabled.label"),
}, },
{
"name": "registered",
"input": new lib_plankton.zoo_input.class_input_checkbox({"read_only": true}),
"label": lib_plankton.translate.get("domain.member.registered.label"),
},
{
"name": "name_login",
"input": new lib_plankton.zoo_input.class_input_text({"read_only": true}),
"label": lib_plankton.translate.get("domain.member.name_login.label"),
},
{ {
"name": "password_set", "name": "password_set",
"input": new lib_plankton.zoo_input.class_input_checkbox({"read_only": true}), "input": new lib_plankton.zoo_input.class_input_checkbox({"read_only": true}),
"label": lib_plankton.translate.get("domain.member.password_set.label"), "label": lib_plankton.translate.get("domain.member.password_set.label"),
}, },
{ {
"name": "email_address_private", "name": "email_address",
"input": new lib_plankton.zoo_input.class_input_text(), "input": new lib_plankton.zoo_input.class_input_text(),
"label": lib_plankton.translate.get("domain.member.email_address_private.label"), "label": lib_plankton.translate.get("domain.member.email_address.label"),
},
{
"name": "email_address_veiled",
"input": new lib_plankton.zoo_input.class_input_text({"read_only": true}),
"label": lib_plankton.translate.get("domain.member.email_address_veiled.label"),
},
{
"name": "email_address_nominal",
"input": new lib_plankton.zoo_input.class_input_text({"read_only": true}),
"label": lib_plankton.translate.get("domain.member.email_address_nominal.label"),
},
{
"name": "email_redirect_to_private_address",
"input": new lib_plankton.zoo_input.class_input_checkbox({"read_only": true}),
"label": lib_plankton.translate.get("domain.member.email_redirect_to_private_address.label"),
},
{
"name": "email_allow_sending",
"input": new lib_plankton.zoo_input.class_input_checkbox(),
"label": lib_plankton.translate.get("domain.member.email_allow_sending.label"),
}, },
] ]
), ),
@ -138,15 +119,15 @@ lib_plankton.zoo_page.register(
await _espe.backend.member_modify( await _espe.backend.member_modify(
id, id,
{ {
"email_address_private": value.email_address_private, "email_address": value.email_address,
"groups": value.groups, "groups": value.groups,
"enabled": value.enabled, "enabled": value.enabled,
"registered": value.registered,
} }
); );
}, },
}, },
] ]
/*
.concat( .concat(
member_data.registered member_data.registered
? [] ? []
@ -176,31 +157,16 @@ lib_plankton.zoo_page.register(
}, },
] ]
) )
*/
) )
); );
await form.setup(dom_fragment.querySelector(".member_view-form") as HTMLElement); await form.setup(dom_fragment.querySelector(".member_view-form") as HTMLElement);
await form.input_write( await form.input_write(
{ {
"membership_number": member_data.membership_number, "name": member_data.name,
"name_real_value": member_data.name_real_value,
"name_real_index": member_data.name_real_index,
"groups": member_data.groups, "groups": member_data.groups,
"registered": member_data.registered,
"enabled": member_data.enabled, "enabled": member_data.enabled,
"email_address_private": member_data.email_address_private, "email_address": member_data.email_address,
"email_address_veiled": (
member_data.email_use_veiled_address
? member_data.email_address_veiled
: ("(" + lib_plankton.translate.get("common.not_used") + ")")
),
"email_address_nominal": (
member_data.email_use_nominal_address
? member_data.email_address_nominal
: ("(" + lib_plankton.translate.get("common.not_used") + ")")
),
"email_redirect_to_private_address": member_data.email_redirect_to_private_address,
"email_allow_sending": member_data.email_allow_sending,
"name_login": member_data.name_login,
"password_set": member_data.password_set, "password_set": member_data.password_set,
} }
); );

View file

@ -251,3 +251,8 @@ nav > ul > li:hover::after
{ {
display: none!important; display: none!important;
} }
.plankton_input_set_option
{
display: block;
}

View file

@ -36,11 +36,15 @@ _default: ${dir_build}/logic.js ${dir_build}/style.css ${dir_build}/index.html d
${dir_temp}/logic-unlinked.js: \ ${dir_temp}/logic-unlinked.js: \
${dir_lib}/plankton/plankton.d.ts \ ${dir_lib}/plankton/plankton.d.ts \
${dir_source}/logic/helpers.ts \ ${dir_source}/logic/helpers.ts \
${dir_source}/logic/input_set.ts \
${dir_source}/logic/backend.ts \ ${dir_source}/logic/backend.ts \
${dir_source}/logic/conf.ts \ ${dir_source}/logic/conf.ts \
${dir_source}/pages/index/logic.ts \ ${dir_source}/pages/index/logic.ts \
${dir_source}/pages/login/logic.ts \ ${dir_source}/pages/login/logic.ts \
${dir_source}/pages/logout/logic.ts \ ${dir_source}/pages/logout/logic.ts \
${dir_source}/pages/group_list/logic.ts \
${dir_source}/pages/group_view/logic.ts \
${dir_source}/pages/group_create/logic.ts \
${dir_source}/pages/member_create/logic.ts \ ${dir_source}/pages/member_create/logic.ts \
${dir_source}/pages/member_list/logic.ts \ ${dir_source}/pages/member_list/logic.ts \
${dir_source}/pages/member_view/logic.ts \ ${dir_source}/pages/member_view/logic.ts \
@ -54,19 +58,21 @@ ${dir_temp}/logic-unlinked.js: \
${dir_source}/logic/main.ts ${dir_source}/logic/main.ts
@ ${cmd_log} "logic | compile …" @ ${cmd_log} "logic | compile …"
@ ${cmd_mkdir} $(dir $@) @ ${cmd_mkdir} $(dir $@)
@ ${cmd_tsc} --lib es2020,dom $^ --outFile $@ @ ${cmd_tsc} --lib es2020,dom --target es2015 $^ --outFile $@
${dir_build}/logic.js: ${dir_lib}/plankton/plankton.js ${dir_temp}/logic-unlinked.js ${dir_build}/logic.js: ${dir_lib}/plankton/plankton.js ${dir_temp}/logic-unlinked.js
@ ${cmd_log} "logic | link …" @ ${cmd_log} "logic | link …"
@ ${cmd_mkdir} $(dir $@) @ ${cmd_mkdir} $(dir $@)
@ ${cmd_cat} $^ > $@ @ ${cmd_cat} $^ > $@
@ ${cmd_chmod} +x $@
${dir_build}/style.css: \ ${dir_build}/style.css: \
${dir_source}/style/style.css \ ${dir_source}/style/style.css \
${dir_source}/pages/index/style.css \ ${dir_source}/pages/index/style.css \
${dir_source}/pages/login/style.css \ ${dir_source}/pages/login/style.css \
${dir_source}/pages/logout/style.css \ ${dir_source}/pages/logout/style.css \
${dir_source}/pages/group_list/style.css \
${dir_source}/pages/group_view/style.css \
${dir_source}/pages/group_create/style.css \
${dir_source}/pages/member_create/style.css \ ${dir_source}/pages/member_create/style.css \
${dir_source}/pages/member_list/style.css \ ${dir_source}/pages/member_list/style.css \
${dir_source}/pages/member_view/style.css \ ${dir_source}/pages/member_view/style.css \
@ -86,6 +92,9 @@ ${dir_build}/index.html: \
${dir_source}/pages/index/structure.html \ ${dir_source}/pages/index/structure.html \
${dir_source}/pages/login/structure.html \ ${dir_source}/pages/login/structure.html \
${dir_source}/pages/logout/structure.html \ ${dir_source}/pages/logout/structure.html \
${dir_source}/pages/group_list/structure.html \
${dir_source}/pages/group_view/structure.html \
${dir_source}/pages/group_create/structure.html \
${dir_source}/pages/member_create/structure.html \ ${dir_source}/pages/member_create/structure.html \
${dir_source}/pages/member_list/structure.html \ ${dir_source}/pages/member_list/structure.html \
${dir_source}/pages/member_view/structure.html \ ${dir_source}/pages/member_view/structure.html \