[task-193]

This commit is contained in:
roydfalk 2025-07-02 18:33:14 +02:00
parent 76a2d7dff4
commit 1f91b8f9c8
31 changed files with 1193 additions and 343 deletions

View file

@ -4,52 +4,62 @@
}, },
"tree": { "tree": {
"common.not_used": "nicht verwendet", "common.not_used": "nicht verwendet",
"common.changeable": "änderbar",
"common.initial_value": "Vorausfüllung",
"common.timezone_shift": "Zeitzonen-Verschiebung",
"common.date": "Datum",
"common.time": "Uhzeit",
"domain.member.member": "Mitglied",
"domain.member.membership_number.label": "Mitgliedsnummer",
"domain.member.name_real_value.label": "Echter Name",
"domain.member.name_real_index.label": "Namens-Index",
"domain.member.groups.label": "Gruppen",
"domain.member.registered.label": "registriert",
"domain.member.enabled.label": "aktiviert",
"domain.member.email_address_private.label": "private 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_redirect_to_private_address.label": "eingehende E-Mails zu privater Adresse umleiten",
"domain.member.email_allow_sending.label": "Versenden von E-Mails erlauben",
"domain.member.name_login.label": "Anmeldename",
"domain.member.password_set.label": "Passwort gesetzt",
"domain.invite.key.label": "Schlüssel",
"domain.invite.expiry.label": "Ablaufzeitpunkt",
"domain.invite.url.label": "URL",
"page.login.title": "Anmelden", "page.login.title": "Anmelden",
"page.login.name": "Name", "page.login.name": "Name",
"page.login.password": "Passwort", "page.login.password": "Passwort",
"page.login.submit": "Anmelden", "page.login.submit": "Anmelden",
"page.create.title": "Mitglied anlegen", "page.logout.title": "Abmelden",
"page.list.title": "Mitglieder-Liste", "page.member_create.title": "Mitglied anlegen",
"page.view.title": "Mitglied", "page.member_list.title": "Mitglieder",
"page.view.form.field.membership_number.label": "Mitgliedsnummer", "page.member_view.title": "Mitglied",
"page.view.form.field.name_real_value.label": "Echter Name", "page.member_view.form.action.save": "Änderungen speichern",
"page.view.form.field.name_real_index.label": "Namens-Index", "page.member_view.form.action.summon": "Zur Registrierung auffordern",
"page.view.form.field.groups.label": "Gruppen", "page.member_view.misc.summoned": "Benachrichtigung verschickt",
"page.view.form.field.registered.label": "registriert", "page.member_view.misc.test_info": "Im Produktiv-Szenario würde an dieser Stelle eine E-Mail an die hinterlegte private E-Mail-Adresse des Mitglieds versendet werden mit einem Willkommens-Gruß und dem Aufruf folgenden Link zu öffnen:\n\n{{url}}",
"page.view.form.field.enabled.label": "aktiviert", "page.member_register.title": "Registrieren",
"page.view.form.field.email_address_private.label": "private E-Mail-Adresse", "page.member_register.form.field.email_address.label": "Partei-E-Mail-Adresse einrichten",
"page.view.form.field.email_address_veiled.label": "pseudonymisierte E-Mail-Adresse", "page.member_register.form.field.email_address.help": "Für Partei-Angelegenheiten möchten wir dir anbieten gesonderte E-Mail-Adressen zu verwenden.\n\nDeine namentliche E-Mail-Adresse würde lauten »{{email_address_nominal}}« und die pseudonymisierte »{{email_address_veiled}}«\n\nDie Partei-E-Mail-Adressen können zum Empfangen von E-Mails verwendet werden. Falls es nötig werden sollte, dass du auch E-Mails mit über die Partei-Adresse verschicken kannst, wende dich bitte an den/die Mitgliederbeauftragte:n!",
"page.view.form.field.email_address_nominal.label": "namentliche E-Mail-Adresse", "page.member_register.form.field.email_address.option.none": "keine",
"page.view.form.field.email_redirect_to_private_address.label": "eingehende E-Mails zu privater Adresse umleiten", "page.member_register.form.field.email_address.option.only_veiled": "nur pseudonymisiert",
"page.view.form.field.email_allow_sending.label": "Versenden von E-Mails erlauben", "page.member_register.form.field.email_address.option.both": "pseudonymisiert und namentlich",
"page.view.form.field.name_login.label": "Anmeldename", "page.member_register.form.field.email_redirect.label": "eingehende E-Mails an private Adresse leiten",
"page.view.form.field.password_set.label": "Passwort gesetzt", "page.member_register.form.field.email_redirect.help": "",
"page.view.form.action.save": "Änderungen speichern", "page.member_register.form.field.password_value.label": "Passwort für Netz-Dienste",
"page.view.form.action.summon": "Zur Registrierung auffordern", "page.member_register.form.field.password_value.help": "das Passwort für die Anmeldung bei den Netz-Diensten.\n\nDu solltest dir merken oder geeignet abspeichern, was du hier einträgst.\n\nSolltest du dieses Passwort mal vergessen oder verlieren, hast du die Möglichkeit ein neues zu setzen.",
"page.view.misc.summoned": "Benachrichtigung verschickt", "page.member_register.form.field.password_confirmation.label": "Passwort wiederholen",
"page.view.misc.test_info": "Im Produktiv-Szenario würde an dieser Stelle eine E-Mail an die hinterlegte private E-Mail-Adresse des Mitglieds versendet werden mit einem Willkommens-Gruß und dem Aufruf folgenden Link zu öffnen:\n\n{{url}}", "page.member_register.form.field.password_confirmation.help": "",
"page.register.title": "Registrieren", "page.member_register.form.submit": "Abschicken",
"page.register.form.field.email_address.label": "Partei-E-Mail-Adresse einrichten", "page.member_register.flaw.already_registered": "bereits registriert",
"page.register.form.field.email_address.help": "Für Partei-Angelegenheiten möchten wir dir anbieten gesonderte E-Mail-Adressen zu verwenden.\n\nDeine namentliche E-Mail-Adresse würde lauten »{{email_address_nominal}}« und die pseudonymisierte »{{email_address_veiled}}«\n\nDie Partei-E-Mail-Adressen können zum Empfangen von E-Mails verwendet werden. Falls es nötig werden sollte, dass du auch E-Mails mit über die Partei-Adresse verschicken kannst, wende dich bitte an den/die Mitgliederbeauftragte:n!", "page.member_register.flaw.password_mismatch": "die Passwörter stimmen nicht überein",
"page.register.form.field.email_address.option.none": "keine", "page.member_register.flaw.password_too_short": "das Passwort muss mindestens {{minimum_length}} Zeichen haben",
"page.register.form.field.email_address.option.only_veiled": "nur pseudonymisiert", "page.member_register.flaw.password_too_long": "das Passwort darf höchstens {{maximum_length}} Zeichen haben",
"page.register.form.field.email_address.option.both": "pseudonymisiert und namentlich", "page.member_register.flaw.password_lacks_letter": "das Passwort muss einen Buchstaben beinhalten",
"page.register.form.field.email_redirect.label": "eingehende E-Mails an private Adresse leiten", "page.member_register.flaw.password_lacks_number": "das Passwort muss eine Zahl beinhalten",
"page.register.form.field.email_redirect.help": "", "page.member_register.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten",
"page.register.form.field.password_value.label": "Passwort für Netz-Dienste", "page.member_register.flaw.unhandled_error": "da ist etwas schief gelaufen :/",
"page.register.form.field.password_value.help": "das Passwort für die Anmeldung bei den Netz-Diensten.\n\nDu solltest dir merken oder geeignet abspeichern, was du hier einträgst.\n\nSolltest du dieses Passwort mal vergessen oder verlieren, hast du die Möglichkeit ein neues zu setzen.", "page.member_register.success": "Danke!",
"page.register.form.field.password_confirmation.label": "Passwort wiederholen",
"page.register.form.field.password_confirmation.help": "",
"page.register.form.submit": "Abschicken",
"page.register.flaw.already_registered": "bereits registriert",
"page.register.flaw.password_mismatch": "die Passwörter stimmen nicht überein",
"page.register.flaw.password_too_short": "das Passwort muss mindestens {{minimum_length}} Zeichen haben",
"page.register.flaw.password_too_long": "das Passwort darf höchstens {{maximum_length}} Zeichen haben",
"page.register.flaw.password_lacks_letter": "das Passwort muss einen Buchstaben beinhalten",
"page.register.flaw.password_lacks_number": "das Passwort muss eine Zahl beinhalten",
"page.register.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten",
"page.register.flaw.unhandled_error": "da ist etwas schief gelaufen :/",
"page.register.success": "Danke!",
"page.password_change_init.title": "Passwort ändern", "page.password_change_init.title": "Passwort ändern",
"page.password_change_init.info": "Falls dein Mitglieds-Konto zugeordnet werden kann, wird eine E-Mail mit weiteren Anweisungen an deine private Adresse geschickt.", "page.password_change_init.info": "Falls dein Mitglieds-Konto zugeordnet werden kann, wird eine E-Mail mit weiteren Anweisungen an deine private Adresse geschickt.",
"page.password_change_init.identifier": "Anmelde-Name oder private E-Mail-Adresse", "page.password_change_init.identifier": "Anmelde-Name oder private E-Mail-Adresse",
@ -71,6 +81,13 @@
"page.password_change_exec.flaw.unhandled_error": "da ist etwas schief gelaufen :/", "page.password_change_exec.flaw.unhandled_error": "da ist etwas schief gelaufen :/",
"page.password_change_exec.status.success": "erledigt", "page.password_change_exec.status.success": "erledigt",
"page.invite_list.title": "Einladungen", "page.invite_list.title": "Einladungen",
"page.invite_handle.title": "Einladung" "page.invite_create.title": "Einladung anlegen",
"page.invite_create.form.field.send_immediatly.label": "Link sofort versenden",
"page.invite_create.form.action.submit": "anlegen",
"page.invite_view.title": "Einladung",
"page.invite_handle.title": "Einladung",
"page.invite_handle.message.invalid": "ungültig",
"page.invite_handle.message.successfull": "erfolgreich",
"page.invite_handle.form.action.submit": "annehmen"
} }
} }

View file

@ -4,52 +4,62 @@
}, },
"tree": { "tree": {
"common.not_used": "not used", "common.not_used": "not used",
"page.login.title": "Login", "common.changeable": "changeable",
"common.initial_value": "initial value",
"common.timezone_shift": "timezone shift",
"common.date": "date",
"common.time": "time",
"domain.member.member": "member",
"domain.member.membership_number.label": "membership number",
"domain.member.name_real_value.label": "real name",
"domain.member.name_real_index.label": "name index",
"domain.member.groups.label": "groups",
"domain.member.registered.label": "registered",
"domain.member.enabled.label": "enabled",
"domain.member.email_address_private.label": "private 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_redirect_to_private_address.label": "redirect incoming e-mails to private address",
"domain.member.email_allow_sending.label": "allow sending e-mails",
"domain.member.name_login.label": "login name",
"domain.member.password_set.label": "password set",
"domain.invite.key.label": "key",
"domain.invite.expiry.label": "expiration",
"domain.invite.url.url": "URL",
"page.login.title": "login",
"page.login.name": "name", "page.login.name": "name",
"page.login.password": "password", "page.login.password": "password",
"page.login.submit": "login", "page.login.submit": "login",
"page.create.title": "Create member", "page.logout.title": "logout",
"page.list.title": "Member list", "page.member_create.title": "Create member",
"page.view.title": "Member", "page.member_list.title": "Members",
"page.view.form.field.membership_number.label": "membership number", "page.member_view.title": "Member",
"page.view.form.field.name_real_value.label": "real name", "page.member_view.form.action.save": "save changes",
"page.view.form.field.name_real_index.label": "name index", "page.member_view.form.action.summon": "urge for registration",
"page.view.form.field.groups.label": "groups", "page.member_view.misc.summoned": "notification sent",
"page.view.form.field.registered.label": "registered", "page.member_view.misc.test_info": "in a productive environment the system would now send an e-mail to the member's private address with a welcome note and a call to open the following link:\n\n{{url}}",
"page.view.form.field.enabled.label": "enabled", "page.member_register.title": "Register",
"page.view.form.field.email_address_private.label": "private e-mail address", "page.member_register.form.field.email_address.label": "Set up party e-mail address",
"page.view.form.field.email_address_veiled.label": "veiled e-mail address", "page.member_register.form.field.email_address.help": "We offer you to use a special e-mail address for any party concerns.\n\nYour namely e-mail address would be »{{email_address_nominal}}« and the veiled one »{{email_address_veiled}}«\n\nThe party e-mail address may be used for the reception of e-mails. In case it becomes necessary for you to submit e-mails via a party address, please get in contact with your membership authority!",
"page.view.form.field.email_address_nominal.label": "nominal e-mail address", "page.member_register.form.field.email_address.option.none": "none",
"page.view.form.field.email_redirect_to_private_address.label": "redirect incoming e-mails to private address", "page.member_register.form.field.email_address.option.only_veiled": "only veiled",
"page.view.form.field.email_allow_sending.label": "allow sending e-mails", "page.member_register.form.field.email_address.option.both": "both, veiled and namely",
"page.view.form.field.name_login.label": "login name", "page.member_register.form.field.email_redirect.label": "redirect incoming e-mails to private address",
"page.view.form.field.password_set.label": "password set", "page.member_register.form.field.email_redirect.help": "",
"page.view.form.action.save": "save changes", "page.member_register.form.field.password_value.label": "password for online services",
"page.view.form.action.summon": "urge for registration", "page.member_register.form.field.password_value.help": "the password for logging in to the online services\n\nYou should remember, denote or save properly, what you enter here.\n\nIn case you forget or lose the password some day, you can reset it.",
"page.view.misc.summoned": "notification sent", "page.member_register.form.field.password_confirmation.label": "confirm password",
"page.view.misc.test_info": "in a productive environment the system would now send an e-mail to the member's private address with a welcome note and a call to open the following link:\n\n{{url}}", "page.member_register.form.field.password_confirmation.help": "",
"page.register.title": "Register", "page.member_register.form.submit": "submit",
"page.register.form.field.email_address.label": "Set up party e-mail address", "page.member_register.flaw.already_registered": "already registered",
"page.register.form.field.email_address.help": "We offer you to use a special e-mail address for any party concerns.\n\nYour namely e-mail address would be »{{email_address_nominal}}« and the veiled one »{{email_address_veiled}}«\n\nThe party e-mail address may be used for the reception of e-mails. In case it becomes necessary for you to submit e-mails via a party address, please get in contact with your membership authority!", "page.member_register.flaw.password_mismatch": "passwords do not match",
"page.register.form.field.email_address.option.none": "none", "page.member_register.flaw.password_too_short": "the password must have at least {{minimum_length}} characters",
"page.register.form.field.email_address.option.only_veiled": "only veiled", "page.member_register.flaw.password_too_long": "the password must not have more than {{maximum_length}} characters",
"page.register.form.field.email_address.option.both": "both, veiled and namely", "page.member_register.flaw.password_lacks_letter": "the password must contain a letter",
"page.register.form.field.email_redirect.label": "redirect incoming e-mails to private address", "page.member_register.flaw.password_lacks_number": "the password must contain a number",
"page.register.form.field.email_redirect.help": "", "page.member_register.flaw.password_lacks_special_character": "the password must contain a special character",
"page.register.form.field.password_value.label": "password for online services", "page.member_register.flaw.unhandled_error": "something went wrong :/",
"page.register.form.field.password_value.help": "the password for logging in to the online services\n\nYou should remember, denote or save properly, what you enter here.\n\nIn case you forget or lose the password some day, you can reset it.", "page.member_register.success": "Thanks!",
"page.register.form.field.password_confirmation.label": "confirm password",
"page.register.form.field.password_confirmation.help": "",
"page.register.form.submit": "submit",
"page.register.flaw.already_registered": "already registered",
"page.register.flaw.password_mismatch": "passwords do not match",
"page.register.flaw.password_too_short": "the password must have at least {{minimum_length}} characters",
"page.register.flaw.password_too_long": "the password must not have more than {{maximum_length}} characters",
"page.register.flaw.password_lacks_letter": "the password must contain a letter",
"page.register.flaw.password_lacks_number": "the password must contain a number",
"page.register.flaw.password_lacks_special_character": "the password must contain a special character",
"page.register.flaw.unhandled_error": "something went wrong :/",
"page.register.success": "Thanks!",
"page.password_change_init.title": "Change Password", "page.password_change_init.title": "Change Password",
"page.password_change_init.info": "In case your member account can be found, an e-mail with further instructions will be sent to your private e-mail address.", "page.password_change_init.info": "In case your member account can be found, an e-mail with further instructions will be sent to your private e-mail address.",
"page.password_change_init.identifier": "Login name or private e-mail address", "page.password_change_init.identifier": "Login name or private e-mail address",
@ -70,7 +80,14 @@
"page.password_change_exec.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten", "page.password_change_exec.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten",
"page.password_change_exec.flaw.unhandled_error": "da ist etwas schief gelaufen :/", "page.password_change_exec.flaw.unhandled_error": "da ist etwas schief gelaufen :/",
"page.password_change_exec.status.success": "done", "page.password_change_exec.status.success": "done",
"page.invite_list.title": "Invites", "page.invite_list.title": "invites",
"page.invite_handle.title": "Invite" "page.invite_create.title": "create invite",
"page.invite_create.form.field.send_immediatly.label": "send link immediatly",
"page.invite_create.form.action.submit": "create",
"page.invite_view.title": "invitation",
"page.invite_handle.title": "invitation",
"page.invite_handle.message.invalid": "invalid",
"page.invite_handle.message.successfull": "successful",
"page.invite_handle.form.action.submit": "accept"
} }
} }

View file

@ -511,6 +511,74 @@ namespace _espe.backend
} }
/**
*/
export async function invite_read(
id : int
) : Promise<
{
key : string;
expiry : (null | int);
membership_number_changeable : boolean;
membership_number_value : (null | string);
name_changeable : boolean;
name_value : string;
email_address_changeable : boolean;
email_address_value : (null | string);
groups_changeable : boolean;
groups_value : Array<string>;
}
>
{
return abstract_call(
"GET",
lib_plankton.string.coin(
"/invite/read?id={{id}}",
{
"id": id.toFixed(0),
}
)
);
}
/**
*/
export async function invite_create(
data : {
membership_number_changeable : boolean;
membership_number_value : (null | string);
name_changeable : boolean;
name_value : string;
email_address_changeable : boolean;
email_address_value : (null | string);
groups_changeable : boolean;
groups_value : Array<string>;
expiry : (null | int);
},
send_immediatly : boolean,
notification_target_url_template : (null | string)
) : Promise<
{
id : int;
key : string;
}
>
{
return abstract_call(
"POST",
"/invite/create",
{
"data": {
"data": data,
"notification_target_url_template": notification_target_url_template,
"send_immediatly": send_immediatly,
}
}
);
}
/** /**
*/ */
export async function invite_examine( export async function invite_examine(

View file

@ -56,27 +56,22 @@ function setup_nav(
> = [ > = [
{ {
"location": {"name": "login", "parameters": {}}, "location": {"name": "login", "parameters": {}},
"label": "Anmelden", "label": lib_plankton.translate.get("page.login.title"),
"classes": ["logged_out"], "classes": ["logged_out"],
}, },
{ {
"location": {"name": "list", "parameters": {}}, "location": {"name": "member_list", "parameters": {}},
"label": "Liste", "label": lib_plankton.translate.get("page.member_list.title"),
"classes": ["logged_in"],
},
{
"location": {"name": "create", "parameters": {}},
"label": "Anlegen",
"classes": ["logged_in"], "classes": ["logged_in"],
}, },
{ {
"location": {"name": "invite_list", "parameters": {}}, "location": {"name": "invite_list", "parameters": {}},
"label": "Einladungen", "label": lib_plankton.translate.get("page.invite_list.title"),
"classes": ["logged_in"], "classes": ["logged_in"],
}, },
{ {
"location": {"name": "logout", "parameters": {}}, "location": {"name": "logout", "parameters": {}},
"label": "Abmelden", "label": lib_plankton.translate.get("page.logout.title"),
"classes": ["logged_in"], "classes": ["logged_in"],
}, },
]; ];

View file

@ -0,0 +1,263 @@
/*
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(
"invite_create",
async (parameters, target_element) => {
target_element.appendChild(template_request("invite_create"));
target_element.querySelector(".invite_create-title").textContent = lib_plankton.translate.get("page.invite_create.title");
const indent = str => (/*"... " + */str);
/**
* @todo outsource
*/
const null_when_empty = (str) => (((str === null) || (str === "")) ? null : str);
const form = new lib_plankton.zoo_form.class_form<
{
data : {
membership_number_changeable : boolean;
membership_number_value : (null | string);
name_changeable : boolean;
name_value : string;
email_address_changeable : boolean;
email_address_value : (null | string);
groups_changeable : boolean;
groups_value : Array<string>;
expiry : (null | int);
};
send_immediatly : boolean;
},
{
membership_number : {
changeable : boolean;
value : string;
};
name : {
changeable : boolean;
value : string;
};
email_address : {
changeable : boolean;
value : string;
};
groups : {
changeable : boolean;
value : Array<string>;
};
expiry : (null | lib_plankton.pit.type_datetime);
send_immediatly : boolean;
}
>(
value => ({
"membership_number": {
"changeable": value.data.membership_number_changeable,
"value": (value.data.membership_number_value ?? ""),
},
"name": {
"changeable": value.data.name_changeable,
"value": value.data.name_value,
},
"email_address": {
"changeable": value.data.email_address_changeable,
"value": (value.data.email_address_value ?? ""),
},
"groups": {
"changeable": value.data.groups_changeable,
"value": value.data.groups_value,
},
"expiry": (
(value.data.expiry === null)
?
null
:
lib_plankton.pit.to_datetime(lib_plankton.pit.from_unix_timestamp(value.data.expiry))
),
"send_immediatly": value.send_immediatly,
}),
representation => ({
"data": {
"membership_number_changeable": representation.membership_number.changeable,
"membership_number_value": null_when_empty(representation.membership_number.value),
"name_changeable": representation.name.changeable,
"name_value": representation.name.value,
"email_address_changeable": representation.email_address.changeable,
"email_address_value": null_when_empty(representation.email_address.value),
"groups_changeable": representation.groups.changeable,
"groups_value": representation.groups.value,
"expiry": (
(representation.expiry === null)
?
null
:
lib_plankton.pit.to_unix_timestamp(lib_plankton.pit.from_datetime(representation.expiry))
),
},
"send_immediatly": representation.send_immediatly,
}),
new lib_plankton.zoo_input.class_input_group(
[
{
"name": "membership_number",
"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.membership_number.label"),
},
{
"name": "groups",
"input": new lib_plankton.zoo_input.class_input_group(
[
{
"name": "value",
"input": new lib_plankton.zoo_input.class_input_list(
() => 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.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",
"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.email_address_private.label"),
},
{
"name": "expiry",
"input": new lib_plankton.zoo_input.class_input_soft(
new lib_plankton.zoo_input.class_input_datetime_central_europe(
{
// "label_timezone_shift": indent(lib_plankton.translate.get("common.timezone_shift")),
"label_date": indent(lib_plankton.translate.get("common.date")),
"label_time": indent(lib_plankton.translate.get("common.time")),
}
)
),
"label": lib_plankton.translate.get("domain.invite.expiry.label"),
},
{
"name": "send_immediatly",
"input": new lib_plankton.zoo_input.class_input_checkbox(),
"label": indent(lib_plankton.translate.get("page.invite_create.form.field.send_immediatly.label")),
},
]
),
[
{
"label": lib_plankton.translate.get("page.invite_create.form.action.submit"),
"procedure": async (get_value, get_representation) => {
const value = await get_value();
const result : {id : int; key : string;} = await _espe.backend.invite_create(
value.data,
value.send_immediatly,
lib_plankton.zoo_page.encode(
{
"name": "invite_handle",
"parameters": {
"key": "{{key}}",
}
}
)
);
lib_plankton.zoo_page.set(
true
?
{
"name": "invite_view",
"parameters": {"id": result.id.toFixed(0)}
}
:
{
"name": "invite_list",
"parameters": {}
}
);
},
}
]
);
await form.setup(target_element.querySelector(".invite_create-form") as HTMLElement);
form.input_write(
{
"data": {
"membership_number_changeable": false,
"membership_number_value": null,
"name_changeable": false,
"name_value": "",
"email_address_changeable": true,
"email_address_value": null,
"groups_changeable": false,
"groups_value": [],
/**
* @todo conf
*/
"expiry": lib_plankton.pit.shift_week(lib_plankton.pit.now(), 2),
},
"send_immediatly": true,
}
);
}
);

View file

@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with thi
<https://www.gnu.org/licenses/>. <https://www.gnu.org/licenses/>.
--> -->
<template id="list"> <template id="invite_create">
<h2 class="list-title"></h2> <h2 class="invite_create-title"></h2>
<div class="list-search"></div> <div class="invite_create-form"></div>
</template> </template>

View file

@ -0,0 +1,31 @@
/*
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/>.
*/
.invite_create-title
{
text-transform: capitalize;
}
.plankton_input_group_field .plankton_input_group
{
padding-left: 32px;
}
.plankton_input_group_field .plankton_input_group > *
{
display: inline-block;
margin-right: 16px;
vertical-align: top;
}

View file

@ -16,139 +16,184 @@ You should have received a copy of the GNU General Public License along with thi
lib_plankton.zoo_page.register( lib_plankton.zoo_page.register(
"invite_handle", "invite_handle",
async (parameters, target_element) => { async (parameters, target_element) => {
function set_state(
state : ("load" | "fill" | "wait" | "done"),
messages : Array<string> = []
) : void
{
target_element.querySelector(".invite_handle").setAttribute("rel", state);
target_element.querySelector(".invite_handle-message").textContent = "";
let dom_list = document.createElement("ul");
messages.forEach(
message => {
let dom_message = document.createElement("li");
dom_message.textContent = message;
dom_list.appendChild(dom_message);
}
);
target_element.querySelector(".invite_handle-message").appendChild(dom_list);
}
// parameters // parameters
const key : string = parameters["key"]; const key : string = parameters["key"];
target_element.appendChild(template_request("invite_handle")); target_element.appendChild(template_request("invite_handle"));
set_state(
"load",
[
]
);
target_element.querySelector(".invite_handle-title").textContent = lib_plankton.translate.get("page.invite_handle.title"); target_element.querySelector(".invite_handle-title").textContent = lib_plankton.translate.get("page.invite_handle.title");
const data : { let data : (
membership_number_changeable : boolean; null
membership_number_value : (null | string); |
name_changeable : boolean;
name_value : string;
email_address_changeable : boolean;
email_address_value : (null | string);
groups_changeable : boolean;
groups_value : Array<string>;
} = await _espe.backend.invite_examine(key);
const form = new lib_plankton.zoo_form.class_form<
{ {
membership_number_changeable : boolean;
membership_number_value : (null | string); membership_number_value : (null | string);
name_changeable : boolean;
name_value : string; name_value : string;
email_address_changeable : boolean;
email_address_value : (null | string); email_address_value : (null | string);
groups_value : Array<string>; groups_changeable : boolean;
},
{
membership_number_value : string;
name_value : string;
email_address_value : string;
groups_value : Array<string>; groups_value : Array<string>;
} }
>( );
value => ({ try
"membership_number_value": (value.membership_number_value ?? ""), {
"name_value": value.name_value, data = await _espe.backend.invite_examine(key);
"email_address_value": (value.email_address_value ?? ""), }
"groups_value": value.groups_value, catch (error)
}), {
representation => ({ data = null;
"membership_number_value": representation.membership_number_value, }
"name_value": representation.name_value,
"email_address_value": representation.email_address_value, if (data === null)
"groups_value": representation.groups_value, {
}), set_state(
new lib_plankton.zoo_input.class_input_group( "done",
[ [
{ lib_plankton.translate.get("page.invite_handle.message.invalid"),
"name": "membership_number_value", ]
"input": new lib_plankton.zoo_input.class_input_text( );
{ }
"read_only": (! data.membership_number_changeable), else
} {
), const form = new lib_plankton.zoo_form.class_form<
/** {
* @todo translate membership_number_value : (null | string);
*/ name_value : string;
"label": "Mitgliedsnummer", email_address_value : (null | string);
}, groups_value : Array<string>;
{ },
"name": "groups_value", {
"input": new lib_plankton.zoo_input.class_input_list( membership_number_value : string;
() => new lib_plankton.zoo_input.class_input_text( name_value : string;
email_address_value : string;
groups_value : Array<string>;
}
>(
value => ({
"membership_number_value": (value.membership_number_value ?? ""),
"name_value": value.name_value,
"email_address_value": (value.email_address_value ?? ""),
"groups_value": value.groups_value,
}),
representation => ({
"membership_number_value": representation.membership_number_value,
"name_value": representation.name_value,
"email_address_value": representation.email_address_value,
"groups_value": representation.groups_value,
}),
new lib_plankton.zoo_input.class_input_group(
[
{
"name": "membership_number_value",
"input": new lib_plankton.zoo_input.class_input_text(
{
"read_only": (! data.membership_number_changeable),
}
),
"label": lib_plankton.translate.get("domain.member.membership_number.label"),
},
{
"name": "groups_value",
"input": new lib_plankton.zoo_input.class_input_list(
() => new lib_plankton.zoo_input.class_input_text(
{
"read_only": (! data.groups_changeable),
}
),
{ {
"read_only": (! data.groups_changeable), "read_only": (! data.groups_changeable),
} }
), ),
{ "label": lib_plankton.translate.get("domain.member.groups.label"),
"read_only": (! data.groups_changeable), },
} {
), "name": "name_value",
/** "input": new lib_plankton.zoo_input.class_input_text(
* @todo translate {
*/ "read_only": (! data.name_changeable),
"label": "Gruppen", }
}, ),
"label": lib_plankton.translate.get("domain.member.name_real_value.label"),
},
{
"name": "email_address_value",
"input": new lib_plankton.zoo_input.class_input_text(
{
"read_only": (! data.email_address_changeable),
}
),
"label": lib_plankton.translate.get("domain.member.email_address_private.label"),
},
]
),
[
{ {
"name": "name_value", "label": lib_plankton.translate.get("page.invite_handle.form.action.submit"),
"input": new lib_plankton.zoo_input.class_input_text( "procedure": async (get_value, get_representation) => {
{ const value = await get_value();
"read_only": (! data.name_changeable), set_state(
} "wait",
), [
/** ]
* @todo translate );
*/ await _espe.backend.invite_accept(
"label": "Name", key,
}, {
{ "membership_number_value": value.membership_number_value,
"name": "email_address_value", "name_value": value.name_value,
"input": new lib_plankton.zoo_input.class_input_text( "email_address_value": value.email_address_value,
{ "groups_value": value.groups_value,
"read_only": (! data.email_address_changeable), }
} );
), set_state(
/** "done",
* @todo translate [
*/ lib_plankton.translate.get("page.invite_handle.message.successful"),
"label": "E-Mail-Adresse", ]
}, );
},
}
] ]
), );
[ await form.setup(target_element.querySelector(".invite_handle-form") as HTMLElement);
form.input_write(
{ {
"label": "Senden", "membership_number_value": data.membership_number_value,
"procedure": async (get_value, get_representation) => { "name_value": data.name_value,
const value = await get_value(); "email_address_value": data.email_address_value,
await _espe.backend.invite_accept( "groups_value": data.groups_value,
key,
{
"membership_number_value": value.membership_number_value,
"name_value": value.name_value,
"email_address_value": value.email_address_value,
"groups_value": value.groups_value,
}
);
/**
* @todo redirect
*/
/*
lib_plankton.zoo_page.set({"name": "view", "parameters": {"id": id}});
*/
},
} }
] );
); set_state(
await form.setup(target_element.querySelector(".invite_handle-form") as HTMLElement); "fill",
await form.input_write( [
{ ]
"membership_number_value": data.membership_number_value, );
"name_value": data.name_value, }
"email_address_value": data.email_address_value,
"groups_value": data.groups_value,
}
);
} }
); );

View file

@ -14,6 +14,12 @@ You should have received a copy of the GNU General Public License along with thi
--> -->
<template id="invite_handle"> <template id="invite_handle">
<h2 class="invite_handle-title"></h2> <section class="invite_handle">
<div class="invite_handle-form"></div> <h2 class="invite_handle-title"></h2>
<div class="invite_handle-info">
</div>
<div class="invite_handle-message">
</div>
<div class="invite_handle-form"></div>
</section>
</template> </template>

View file

@ -0,0 +1,27 @@
/*
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/>.
*/
.invite_handle:not([rel]) .invite_handle-message {display: none;}
.invite_handle:not([rel]) .invite_handle-form {display: none;}
.invite_handle[rel="fill"] .invite_handle-message {}
.invite_handle[rel="fill"] .invite_handle-form {}
.invite_handle[rel="wait"] .invite_handle-message {}
.invite_handle[rel="wait"] .invite_handle-form {display: none;}
.invite_handle[rel="done"] .invite_handle-message {}
.invite_handle[rel="done"] .invite_handle-form {display: none;}

View file

@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with thi
lib_plankton.zoo_page.register( lib_plankton.zoo_page.register(
"invite_list", "invite_list",
async (parameters, target_element) => { async (parameters, target_element) => {
// types
type type_item = { type type_item = {
id : int; id : int;
key : string; key : string;
@ -23,38 +24,62 @@ lib_plankton.zoo_page.register(
name_value : string; name_value : string;
}; };
// parameters
const term : (null | string) = (parameters["term"] ?? "");
// exec
target_element.appendChild(template_request("invite_list")); target_element.appendChild(template_request("invite_list"));
target_element.querySelector(".invite_list-title").textContent = lib_plankton.translate.get("page.invite_list.title"); target_element.querySelector(".invite_list-title").textContent = lib_plankton.translate.get("page.invite_list.title");
// exec : create link
{
const element : HTMLElement = target_element.querySelector(".invite_list-create");
element.setAttribute(
"href",
lib_plankton.zoo_page.encode(
{
"name": "invite_create",
"parameters": {
}
}
)
);
element.textContent = lib_plankton.translate.get("page.invite_create.title");
}
const search : lib_plankton.zoo_search.type_search<type_item> = lib_plankton.zoo_search.make<type_item>( const search : lib_plankton.zoo_search.type_search<type_item> = lib_plankton.zoo_search.make<type_item>(
(term) => _espe.backend.invite_list(), (term) => _espe.backend.invite_list(),
{ {
"encode_item": (item) => lib_plankton.string.coin( "encode_item": (item) => lib_plankton.string.coin(
"[{{id}}] {{name}}: {{key}}", "[{{id}}] {{name}}",
{ {
"id": item.id.toFixed(0), "id": item.id.toFixed(0),
"name": item.name_value, "name": item.name_value,
"key": item.key,
} }
), ),
"hooks_begin": [ "hooks_begin": [
(term) => { (term) => {
/** lib_plankton.zoo_page.set(
* @todo {
*/ "name": "invite_list",
"parameters": {
"term": term,
}
}
);
} }
], ],
"hooks_select": [ "hooks_select": [
(item) => { (item) => {
const url : URL = new URL(window.location.toString()); lib_plankton.zoo_page.set(
url.hash = lib_plankton.string.coin(
"#invite_handle,key={{key}}",
{ {
"key": item.key, "name": "invite_view",
"parameters": {
"id": item.id.toFixed(0),
}
} }
); );
console.info(url.toString());
} }
] ]
} }

View file

@ -15,8 +15,8 @@ You should have received a copy of the GNU General Public License along with thi
<template id="invite_list"> <template id="invite_list">
<h2 class="invite_list-title"></h2> <h2 class="invite_list-title"></h2>
<!-- <div class="invite_list-links">
<pre class="invite_list-data"></pre> <a class="invite_list-create"></a>
--> </div>
<div class="invite_list-search"></div> <div class="invite_list-search"></div>
</template> </template>

View file

@ -13,3 +13,7 @@ You should have received a copy of the GNU General Public License along with thi
<https://www.gnu.org/licenses/>. <https://www.gnu.org/licenses/>.
*/ */
.invite_list-links
{
margin-bottom: 16px;
}

View file

@ -0,0 +1,249 @@
/*
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(
"invite_view",
async (parameters, target_element) => {
// functions
const get_url = (item) => {
const url : URL = new URL(window.location.toString());
url.hash = lib_plankton.string.coin(
"#invite_handle,key={{key}}",
{
"key": item.key,
}
);
return url.toString();
};
// parameters
const id : int = parseInt(parameters["id"]);
target_element.appendChild(template_request("invite_view"));
target_element.querySelector(".invite_view-title").textContent = lib_plankton.translate.get("page.invite_view.title");
const indent = str => (/*"... " + */str);
/**
* @todo outsource
*/
const null_when_empty = (str) => (((str === null) || (str === "")) ? null : str);
const form = new lib_plankton.zoo_form.class_form<
{
key : string;
expiry : (null | int);
membership_number_changeable : boolean;
membership_number_value : (null | string);
name_changeable : boolean;
name_value : string;
email_address_changeable : boolean;
email_address_value : (null | string);
groups_changeable : boolean;
groups_value : Array<string>;
},
{
key : string;
expiry : (null | lib_plankton.pit.type_datetime);
membership_number : {
changeable : boolean;
value : string;
};
name : {
changeable : boolean;
value : string;
};
email_address : {
changeable : boolean;
value : string;
};
groups : {
changeable : boolean;
value : Array<string>;
};
url : string;
}
>(
value => ({
"expiry": (
(value.expiry === null)
?
null
:
lib_plankton.pit.to_datetime(lib_plankton.pit.from_unix_timestamp(value.expiry))
),
"key": value.key,
"membership_number": {
"changeable": value.membership_number_changeable,
"value": (value.membership_number_value ?? ""),
},
"name": {
"changeable": value.name_changeable,
"value": value.name_value,
},
"email_address": {
"changeable": value.email_address_changeable,
"value": (value.email_address_value ?? ""),
},
"groups": {
"changeable": value.groups_changeable,
"value": value.groups_value,
},
"url": get_url(value),
}),
representation => ({
"expiry": (
(representation.expiry === null)
?
null
:
lib_plankton.pit.to_unix_timestamp(lib_plankton.pit.from_datetime(representation.expiry))
),
"key": representation.key,
"membership_number_changeable": representation.membership_number.changeable,
"membership_number_value": null_when_empty(representation.membership_number.value),
"name_changeable": representation.name.changeable,
"name_value": representation.name.value,
"email_address_changeable": representation.email_address.changeable,
"email_address_value": null_when_empty(representation.email_address.value),
"groups_changeable": representation.groups.changeable,
"groups_value": representation.groups.value,
"url": "",
}),
new lib_plankton.zoo_input.class_input_group(
[
{
"name": "url",
"input": new lib_plankton.zoo_input.class_input_text({"read_only": false}),
"label": lib_plankton.translate.get("domain.invite.url.label"),
},
{
"name": "key",
"input": new lib_plankton.zoo_input.class_input_text({"read_only": true}),
"label": lib_plankton.translate.get("domain.invite.key.label"),
},
{
"name": "membership_number",
"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.membership_number.label"),
},
{
"name": "groups",
"input": new lib_plankton.zoo_input.class_input_group(
[
{
"name": "value",
"input": new lib_plankton.zoo_input.class_input_list(
() => 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.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",
"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.email_address_private.label"),
},
{
"name": "expiry",
"input": new lib_plankton.zoo_input.class_input_soft(
new lib_plankton.zoo_input.class_input_datetime_central_europe(
{
// "read_only": true,
// "label_timezone_shift": indent(lib_plankton.translate.get("common.timezone_shift")),
"label_date": indent(lib_plankton.translate.get("common.date")),
"label_time": indent(lib_plankton.translate.get("common.time")),
}
)
),
"label": lib_plankton.translate.get("domain.invite.expiry.label"),
},
]
),
[
]
);
await form.setup(target_element.querySelector(".invite_view-form") as HTMLElement);
const data : {
key: string;
expiry : (null | int);
membership_number_changeable : boolean;
membership_number_value : (null | string);
name_changeable : boolean;
name_value : string;
email_address_changeable : boolean;
email_address_value : (null | string);
groups_changeable : boolean;
groups_value : Array<string>;
} = await _espe.backend.invite_read(id);
form.input_write(data);
}
);

View file

@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with thi
<https://www.gnu.org/licenses/>. <https://www.gnu.org/licenses/>.
--> -->
<template id="create"> <template id="invite_view">
<h2 class="create-title"></h2> <h2 class="invite_view-title"></h2>
<div class="create-form"></div> <div class="invite_view-form"></div>
</template> </template>

View file

@ -14,14 +14,14 @@ You should have received a copy of the GNU General Public License along with thi
*/ */
.register:not([rel]) .register-message {display: none;} .invite_view:not([rel]) .invite_view-message {display: none;}
.register:not([rel]) .register-form {display: none;} .invite_view:not([rel]) .invite_view-form {display: none;}
.register[rel="fill"] .register-message {} .invite_view[rel="fill"] .invite_view-message {}
.register[rel="fill"] .register-form {} .invite_view[rel="fill"] .invite_view-form {}
.register[rel="wait"] .register-message {} .invite_view[rel="wait"] .invite_view-message {}
.register[rel="wait"] .register-form {display: none;} .invite_view[rel="wait"] .invite_view-form {display: none;}
.register[rel="done"] .register-message {} .invite_view[rel="done"] .invite_view-message {}
.register[rel="done"] .register-form {display: none;} .invite_view[rel="done"] .invite_view-form {display: none;}

View file

@ -55,7 +55,7 @@ lib_plankton.zoo_page.register(
_espe.backend.login(value.name, value.password) _espe.backend.login(value.name, value.password)
.then( .then(
() => { () => {
lib_plankton.zoo_page.set({"name": "list", "parameters": {}}); lib_plankton.zoo_page.set({"name": "member_list", "parameters": {}});
update_nav({"mode": "logged_in"}); update_nav({"mode": "logged_in"});
} }
) )

View file

@ -14,11 +14,11 @@ You should have received a copy of the GNU General Public License along with thi
*/ */
lib_plankton.zoo_page.register( lib_plankton.zoo_page.register(
"create", "member_create",
(parameters, target_element) => { (parameters, target_element) => {
target_element.appendChild(template_request("create")); target_element.appendChild(template_request("member_create"));
target_element.querySelector(".create-title").textContent = lib_plankton.translate.get("page.create.title"); target_element.querySelector(".member_create-title").textContent = lib_plankton.translate.get("page.member_create.title");
const form = new lib_plankton.zoo_form.class_form< const form = new lib_plankton.zoo_form.class_form<
{ {
@ -51,57 +51,48 @@ lib_plankton.zoo_page.register(
{ {
"name": "name_real_value", "name": "name_real_value",
"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.name_real_value.label"),
* @todo translate
*/
"label": "Echter Name",
}, },
{ {
"name": "membership_number", "name": "membership_number",
"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.membership_number.label"),
* @todo translate
*/
"label": "Mitgliedsnummer",
}, },
{ {
"name": "email_address_private", "name": "email_address_private",
"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")
* @todo translate
*/
"label": "Private E-Mail-Adresse",
}, },
{ {
"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_text()
), ),
"label": lib_plankton.translate.get("page.view.form.field.groups.label"), "label": lib_plankton.translate.get("domain.member.groups.label"),
}, },
] ]
), ),
[ [
{ {
"label": "Senden", "label": lib_plankton.translate.get("page.member_register.form.submit"),
"procedure": async (get_value, get_representation) => { "procedure": async (get_value, get_representation) => {
const value = await get_value(); const value = await get_value();
const id : int = await _espe.backend.member_project( const id : int = await _espe.backend.member_project(
value, value,
lib_plankton.zoo_page.encode( lib_plankton.zoo_page.encode(
{ {
"name": "view", "name": "member_view",
"parameters": { "parameters": {
"id": "{{id}}", "id": "{{id}}",
} }
} }
) )
); );
lib_plankton.zoo_page.set({"name": "view", "parameters": {"id": id}}); lib_plankton.zoo_page.set({"name": "member_view", "parameters": {"id": id}});
}, },
} }
] ]
); );
form.setup(target_element.querySelector(".create-form") as HTMLElement); form.setup(target_element.querySelector(".member_create-form") as HTMLElement);
} }
); );

View file

@ -13,10 +13,7 @@ You should have received a copy of the GNU General Public License along with thi
<https://www.gnu.org/licenses/>. <https://www.gnu.org/licenses/>.
--> -->
<template id="view"> <template id="member_create">
<section class="view"> <h2 class="member_create-title"></h2>
<h2 class="view-title"></h2> <div class="member_create-form"></div>
<div class="view-form">
</div>
</section>
</template> </template>

View file

@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with thi
*/ */
lib_plankton.zoo_page.register( lib_plankton.zoo_page.register(
"list", "member_list",
(parameters, target_element) => { (parameters, target_element) => {
type type_item = { type type_item = {
id : int; id : int;
@ -26,9 +26,25 @@ lib_plankton.zoo_page.register(
}; };
const term : (null | string) = (parameters["term"] ?? ""); const term : (null | string) = (parameters["term"] ?? "");
target_element.appendChild(template_request("list")); target_element.appendChild(template_request("member_list"));
target_element.querySelector(".list-title").textContent = lib_plankton.translate.get("page.list.title"); target_element.querySelector(".member_list-title").textContent = lib_plankton.translate.get("page.member_list.title");
// create link
{
const element : HTMLElement = target_element.querySelector(".member_list-create");
element.setAttribute(
"href",
lib_plankton.zoo_page.encode(
{
"name": "member_create",
"parameters": {
}
}
)
);
element.textContent = lib_plankton.translate.get("page.member_create.title");
}
const search : lib_plankton.zoo_search.type_search<type_item> = lib_plankton.zoo_search.make<type_item>( const search : lib_plankton.zoo_search.type_search<type_item> = lib_plankton.zoo_search.make<type_item>(
(term) => _espe.backend.member_list(term), (term) => _espe.backend.member_list(term),
@ -53,7 +69,7 @@ lib_plankton.zoo_page.register(
(term) => { (term) => {
lib_plankton.zoo_page.set( lib_plankton.zoo_page.set(
{ {
"name": "list", "name": "member_list",
"parameters": { "parameters": {
"term": term, "term": term,
} }
@ -65,7 +81,7 @@ lib_plankton.zoo_page.register(
(item) => { (item) => {
lib_plankton.zoo_page.set( lib_plankton.zoo_page.set(
{ {
"name": "view", "name": "member_view",
"parameters": { "parameters": {
"id": item.id.toFixed(0), "id": item.id.toFixed(0),
} }
@ -77,7 +93,7 @@ lib_plankton.zoo_page.register(
); );
lib_plankton.zoo_search.render( lib_plankton.zoo_search.render(
search, search,
target_element.querySelector(".list-search"), target_element.querySelector(".member_list-search"),
{ {
"state": { "state": {
"term": term, "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="member_list">
<h2 class="member_list-title"></h2>
<div class="member_list-links">
<a class="member_list-create"></a>
</div>
<div class="member_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/>.
*/
.member_list-links
{
margin-bottom: 16px;
}

View file

@ -14,15 +14,15 @@ You should have received a copy of the GNU General Public License along with thi
*/ */
lib_plankton.zoo_page.register( lib_plankton.zoo_page.register(
"register", "member_register",
async (parameters, target_element) => { async (parameters, target_element) => {
function set_state( function set_state(
state : ("load" | "fill" | "wait" | "done"), state : ("load" | "fill" | "wait" | "done"),
messages : Array<string> = [] messages : Array<string> = []
) : void ) : void
{ {
target_element.querySelector(".register").setAttribute("rel", state); target_element.querySelector(".member_register").setAttribute("rel", state);
target_element.querySelector(".register-message").textContent = ""; target_element.querySelector(".member_register-message").textContent = "";
let dom_list = document.createElement("ul"); let dom_list = document.createElement("ul");
messages.forEach( messages.forEach(
message => { message => {
@ -31,15 +31,16 @@ lib_plankton.zoo_page.register(
dom_list.appendChild(dom_message); dom_list.appendChild(dom_message);
} }
); );
target_element.querySelector(".register-message").appendChild(dom_list); target_element.querySelector(".member_register-message").appendChild(dom_list);
} }
// parameters
const id : int = parseInt(parameters["id"]); const id : int = parseInt(parameters["id"]);
const verification : string = parameters["verification"]; const verification : string = parameters["verification"];
// const verification : string = (new URLSearchParams(location.search)).get("verification"); // const verification : string = (new URLSearchParams(location.search)).get("verification");
update_nav({"mode": null}); update_nav({"mode": null});
target_element.appendChild(template_request("register")); target_element.appendChild(template_request("member_register"));
set_state( set_state(
"load", "load",
[ [
@ -68,7 +69,7 @@ lib_plankton.zoo_page.register(
set_state( set_state(
"fill", "fill",
[ [
lib_plankton.translate.get("page.register.flaw.already_registered"), lib_plankton.translate.get("page.member_register.flaw.already_registered"),
] ]
); );
} }
@ -76,7 +77,7 @@ lib_plankton.zoo_page.register(
// title // title
{ {
target_element.querySelector(".register-title").textContent = lib_plankton.translate.get("page.register.title"); target_element.querySelector(".member_register-title").textContent = lib_plankton.translate.get("page.member_register.title");
} }
// info // info
{ {
@ -101,21 +102,21 @@ lib_plankton.zoo_page.register(
[ [
{ {
"value": "none", "value": "none",
"label": lib_plankton.translate.get("page.register.form.field.email_address.option.none"), "label": lib_plankton.translate.get("page.member_register.form.field.email_address.option.none"),
}, },
{ {
"value": "only_veiled", "value": "only_veiled",
"label": lib_plankton.translate.get("page.register.form.field.email_address.option.only_veiled"), "label": lib_plankton.translate.get("page.member_register.form.field.email_address.option.only_veiled"),
}, },
{ {
"value": "both", "value": "both",
"label": lib_plankton.translate.get("page.register.form.field.email_address.option.both"), "label": lib_plankton.translate.get("page.member_register.form.field.email_address.option.both"),
}, },
] ]
), ),
"label": lib_plankton.translate.get("page.register.form.field.email_address.label"), "label": lib_plankton.translate.get("page.member_register.form.field.email_address.label"),
"help": lib_plankton.translate.get( "help": lib_plankton.translate.get(
"page.register.form.field.email_address.help", "page.member_register.form.field.email_address.help",
{ {
"email_address_veiled": member_data.email_address_veiled, "email_address_veiled": member_data.email_address_veiled,
"email_address_nominal": member_data.email_address_nominal, "email_address_nominal": member_data.email_address_nominal,
@ -126,24 +127,24 @@ lib_plankton.zoo_page.register(
"name": "email_redirect", "name": "email_redirect",
"input": new lib_plankton.zoo_input.class_input_checkbox( "input": new lib_plankton.zoo_input.class_input_checkbox(
), ),
"label": lib_plankton.translate.get("page.register.form.field.email_redirect.label"), "label": lib_plankton.translate.get("page.member_register.form.field.email_redirect.label"),
}, },
{ {
"name": "password_value", "name": "password_value",
"input": new lib_plankton.zoo_input.class_input_password( "input": new lib_plankton.zoo_input.class_input_password(
), ),
"label": lib_plankton.translate.get("page.register.form.field.password_value.label"), "label": lib_plankton.translate.get("page.member_register.form.field.password_value.label"),
"help": lib_plankton.translate.get("page.register.form.field.password_value.help"), "help": lib_plankton.translate.get("page.member_register.form.field.password_value.help"),
}, },
{ {
"name": "password_confirmation", "name": "password_confirmation",
"input": new lib_plankton.zoo_input.class_input_password( "input": new lib_plankton.zoo_input.class_input_password(
), ),
"label": lib_plankton.translate.get("page.register.form.field.password_confirmation.label"), "label": lib_plankton.translate.get("page.member_register.form.field.password_confirmation.label"),
}, },
] ]
); );
await input.setup(target_element.querySelector(".register-form-input") as HTMLElement); await input.setup(target_element.querySelector(".member_register-form-input") as HTMLElement);
await input.write( await input.write(
{ {
"email_address": _espe.conf.get().settings.registration_defaults.email_address, "email_address": _espe.conf.get().settings.registration_defaults.email_address,
@ -155,8 +156,8 @@ lib_plankton.zoo_page.register(
} }
// actions // actions
{ {
target_element.querySelector(".register-form-action-send").textContent = lib_plankton.translate.get("page.register.form.submit"); target_element.querySelector(".member_register-form-action-send").textContent = lib_plankton.translate.get("page.member_register.form.submit");
target_element.querySelector(".register-form-action-send").addEventListener( target_element.querySelector(".member_register-form-action-send").addEventListener(
"click", "click",
async (event) => { async (event) => {
const value : { const value : {
@ -189,7 +190,7 @@ lib_plankton.zoo_page.register(
}, },
lib_plankton.zoo_page.encode( lib_plankton.zoo_page.encode(
{ {
"name": "view", "name": "member_view",
"parameters": { "parameters": {
"id": "{{id}}", "id": "{{id}}",
} }
@ -208,7 +209,7 @@ lib_plankton.zoo_page.register(
"fill", "fill",
flaws.map( flaws.map(
flaw => lib_plankton.string.coin( flaw => lib_plankton.string.coin(
lib_plankton.translate.get("page.register.flaw." + flaw.incident), lib_plankton.translate.get("page.member_register.flaw." + flaw.incident),
flaw.details flaw.details
) )
) )
@ -218,7 +219,7 @@ lib_plankton.zoo_page.register(
set_state( set_state(
"done", "done",
[ [
lib_plankton.translate.get("page.register.success") lib_plankton.translate.get("page.member_register.success")
] ]
); );
} }

View file

@ -13,18 +13,18 @@ You should have received a copy of the GNU General Public License along with thi
<https://www.gnu.org/licenses/>. <https://www.gnu.org/licenses/>.
--> -->
<template id="register"> <template id="member_register">
<section class="register"> <section class="member_register">
<h2 class="register-title"></h2> <h2 class="member_register-title"></h2>
<div class="register-info"> <div class="member_register-info">
</div> </div>
<div class="register-message"> <div class="member_register-message">
</div> </div>
<div class="register-form"> <div class="member_register-form">
<div class="register-form-input"> <div class="member_register-form-input">
</div> </div>
<div class="register-form-actions"> <div class="member_register-form-actions">
<button class="register-form-action-send"></button> <button class="member_register-form-action-send"></button>
</div> </div>
</div> </div>
</section> </section>

View file

@ -0,0 +1,27 @@
/*
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/>.
*/
.member_register:not([rel]) .member_register-message {display: none;}
.member_register:not([rel]) .member_register-form {display: none;}
.member_register[rel="fill"] .member_register-message {}
.member_register[rel="fill"] .member_register-form {}
.member_register[rel="wait"] .member_register-message {}
.member_register[rel="wait"] .member_register-form {display: none;}
.member_register[rel="done"] .member_register-message {}
.member_register[rel="done"] .member_register-form {display: none;}

View file

@ -14,13 +14,13 @@ You should have received a copy of the GNU General Public License along with thi
*/ */
lib_plankton.zoo_page.register( lib_plankton.zoo_page.register(
"view", "member_view",
async (parameters, target_element) => { async (parameters, target_element) => {
const id : int = parseInt(parameters["id"]); const id : int = parseInt(parameters["id"]);
let dom_fragment : DocumentFragment = template_request("view"); let dom_fragment : DocumentFragment = template_request("member_view");
dom_fragment.querySelector(".view-title").textContent = lib_plankton.translate.get("page.view.title"); dom_fragment.querySelector(".member_view-title").textContent = lib_plankton.translate.get("page.member_view.title");
const member_data = await _espe.backend.member_get(id); const member_data = await _espe.backend.member_get(id);
@ -63,76 +63,76 @@ lib_plankton.zoo_page.register(
{ {
"name": "name_real_value", "name": "name_real_value",
"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("page.view.form.field.name_real_value.label"), "label": lib_plankton.translate.get("domain.member.name_real_value.label"),
}, },
{ {
"name": "name_real_index", "name": "name_real_index",
"input": new lib_plankton.zoo_input.class_input_number({"read_only": true}), "input": new lib_plankton.zoo_input.class_input_number({"read_only": true}),
"label": lib_plankton.translate.get("page.view.form.field.name_real_index.label"), "label": lib_plankton.translate.get("domain.member.name_real_index.label"),
}, },
{ {
"name": "membership_number", "name": "membership_number",
"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("page.view.form.field.membership_number.label"), "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_text()
), ),
"label": lib_plankton.translate.get("page.view.form.field.groups.label"), "label": lib_plankton.translate.get("domain.member.groups.label"),
}, },
{ {
"name": "enabled", "name": "enabled",
"input": new lib_plankton.zoo_input.class_input_checkbox(), "input": new lib_plankton.zoo_input.class_input_checkbox(),
"label": lib_plankton.translate.get("page.view.form.field.enabled.label"), "label": lib_plankton.translate.get("domain.member.enabled.label"),
}, },
{ {
"name": "registered", "name": "registered",
"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("page.view.form.field.registered.label"), "label": lib_plankton.translate.get("domain.member.registered.label"),
}, },
{ {
"name": "name_login", "name": "name_login",
"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("page.view.form.field.name_login.label"), "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("page.view.form.field.password_set.label"), "label": lib_plankton.translate.get("domain.member.password_set.label"),
}, },
{ {
"name": "email_address_private", "name": "email_address_private",
"input": new lib_plankton.zoo_input.class_input_text(), "input": new lib_plankton.zoo_input.class_input_text(),
"label": lib_plankton.translate.get("page.view.form.field.email_address_private.label"), "label": lib_plankton.translate.get("domain.member.email_address_private.label"),
}, },
{ {
"name": "email_address_veiled", "name": "email_address_veiled",
"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("page.view.form.field.email_address_veiled.label"), "label": lib_plankton.translate.get("domain.member.email_address_veiled.label"),
}, },
{ {
"name": "email_address_nominal", "name": "email_address_nominal",
"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("page.view.form.field.email_address_nominal.label"), "label": lib_plankton.translate.get("domain.member.email_address_nominal.label"),
}, },
{ {
"name": "email_redirect_to_private_address", "name": "email_redirect_to_private_address",
"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("page.view.form.field.email_redirect_to_private_address.label"), "label": lib_plankton.translate.get("domain.member.email_redirect_to_private_address.label"),
}, },
{ {
"name": "email_allow_sending", "name": "email_allow_sending",
"input": new lib_plankton.zoo_input.class_input_checkbox(), "input": new lib_plankton.zoo_input.class_input_checkbox(),
"label": lib_plankton.translate.get("page.view.form.field.email_allow_sending.label"), "label": lib_plankton.translate.get("domain.member.email_allow_sending.label"),
}, },
] ]
), ),
( (
[ [
{ {
"label": lib_plankton.translate.get("page.view.form.action.save"), "label": lib_plankton.translate.get("page.member_view.form.action.save"),
"procedure": async (get_value, get_representation) => { "procedure": async (get_value, get_representation) => {
const value = await get_value(); const value = await get_value();
await _espe.backend.member_modify( await _espe.backend.member_modify(
@ -152,7 +152,7 @@ lib_plankton.zoo_page.register(
? [] ? []
: [ : [
{ {
"label": lib_plankton.translate.get("page.view.form.action.summon"), "label": lib_plankton.translate.get("page.member_view.form.action.summon"),
"procedure": async (get_value, get_representation) => { "procedure": async (get_value, get_representation) => {
const url : string = await _espe.backend.member_summon( const url : string = await _espe.backend.member_summon(
id, id,
@ -167,10 +167,10 @@ lib_plankton.zoo_page.register(
) )
); );
if (_espe.conf.get().settings.test_mode) { if (_espe.conf.get().settings.test_mode) {
alert(lib_plankton.translate.get("page.view.misc.test_info", {"url": url})); alert(lib_plankton.translate.get("page.member_view.misc.test_info", {"url": url}));
} }
else { else {
alert(lib_plankton.translate.get("page.view.misc.summoned")); alert(lib_plankton.translate.get("page.member_view.misc.summoned"));
} }
}, },
}, },
@ -178,7 +178,7 @@ lib_plankton.zoo_page.register(
) )
) )
); );
await form.setup(dom_fragment.querySelector(".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, "membership_number": member_data.membership_number,

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="member_view">
<section class="member_view">
<h2 class="member_view-title"></h2>
<div class="member_view-form">
</div>
</section>
</template>

View file

@ -14,25 +14,25 @@ You should have received a copy of the GNU General Public License along with thi
*/ */
.view-title .member_view-title
{ {
display: none; display: none;
} }
/* /*
.view-form > .plankton_form .member_view-form > .plankton_form
{ {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
} }
.view-form > .plankton_form > .plankton_form_input .member_view-form > .plankton_form > .plankton_form_input
{ {
flex: 1; flex: 1;
} }
.view-form > .plankton_form > .plankton_form_actions .member_view-form > .plankton_form > .plankton_form_actions
{ {
flex: 1; flex: 1;

View file

@ -247,7 +247,7 @@ nav > ul > li:hover::after
display: inline-block; display: inline-block;
} }
.plankton_input_list_element_input .plankton_input_soft_inactive
{ {
display: none!important;
} }

View file

@ -41,13 +41,15 @@ ${dir_temp}/logic-unlinked.js: \
${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/create/logic.ts \ ${dir_source}/pages/member_create/logic.ts \
${dir_source}/pages/list/logic.ts \ ${dir_source}/pages/member_list/logic.ts \
${dir_source}/pages/view/logic.ts \ ${dir_source}/pages/member_view/logic.ts \
${dir_source}/pages/register/logic.ts \ ${dir_source}/pages/member_register/logic.ts \
${dir_source}/pages/password_change_init/logic.ts \ ${dir_source}/pages/password_change_init/logic.ts \
${dir_source}/pages/password_change_exec/logic.ts \ ${dir_source}/pages/password_change_exec/logic.ts \
${dir_source}/pages/invite_list/logic.ts \ ${dir_source}/pages/invite_list/logic.ts \
${dir_source}/pages/invite_view/logic.ts \
${dir_source}/pages/invite_create/logic.ts \
${dir_source}/pages/invite_handle/logic.ts \ ${dir_source}/pages/invite_handle/logic.ts \
${dir_source}/logic/main.ts ${dir_source}/logic/main.ts
@ ${cmd_log} "logic | compile …" @ ${cmd_log} "logic | compile …"
@ -65,12 +67,16 @@ ${dir_build}/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/create/style.css \ ${dir_source}/pages/member_create/style.css \
${dir_source}/pages/list/style.css \ ${dir_source}/pages/member_list/style.css \
${dir_source}/pages/view/style.css \ ${dir_source}/pages/member_view/style.css \
${dir_source}/pages/register/style.css \ ${dir_source}/pages/member_register/style.css \
${dir_source}/pages/password_change_init/style.css \ ${dir_source}/pages/password_change_init/style.css \
${dir_source}/pages/password_change_exec/style.css ${dir_source}/pages/password_change_exec/style.css \
${dir_source}/pages/invite_list/style.css \
${dir_source}/pages/invite_view/style.css \
${dir_source}/pages/invite_create/style.css \
${dir_source}/pages/invite_handle/style.css
@ ${cmd_log} "style …" @ ${cmd_log} "style …"
@ ${cmd_mkdir} $(dir $@) @ ${cmd_mkdir} $(dir $@)
@ ${cmd_cat} $^ > $@ @ ${cmd_cat} $^ > $@
@ -80,13 +86,15 @@ ${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/create/structure.html \ ${dir_source}/pages/member_create/structure.html \
${dir_source}/pages/list/structure.html \ ${dir_source}/pages/member_list/structure.html \
${dir_source}/pages/view/structure.html \ ${dir_source}/pages/member_view/structure.html \
${dir_source}/pages/register/structure.html \ ${dir_source}/pages/member_register/structure.html \
${dir_source}/pages/password_change_init/structure.html \ ${dir_source}/pages/password_change_init/structure.html \
${dir_source}/pages/password_change_exec/structure.html \ ${dir_source}/pages/password_change_exec/structure.html \
${dir_source}/pages/invite_list/structure.html \ ${dir_source}/pages/invite_list/structure.html \
${dir_source}/pages/invite_view/structure.html \
${dir_source}/pages/invite_create/structure.html \
${dir_source}/pages/invite_handle/structure.html ${dir_source}/pages/invite_handle/structure.html
@ ${cmd_log} "structure …" @ ${cmd_log} "structure …"
@ ${cmd_mkdir} $(dir $@) @ ${cmd_mkdir} $(dir $@)