WIP state
This commit is contained in:
parent
4aff334677
commit
3640e22239
|
@ -32,7 +32,7 @@ fontawesomeSubset(
|
|||
const ignoreFontsPlugin: esbuild.Plugin = {
|
||||
name: "file",
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /\.woff2|ttf$/ }, (args) => ({
|
||||
build.onResolve({ filter: /\.woff2|ttf$/ }, () => ({
|
||||
external: true,
|
||||
}));
|
||||
},
|
||||
|
|
|
@ -18,7 +18,7 @@ sub new_invite {
|
|||
if ($c->is_user_authenticated) {
|
||||
my $mail_attr = $c->config('invitations')->{'mail_attr'} // 'mail';
|
||||
my $max_expire_at = $c->config('invitations')->{'max_invitation_expiration_delay'} // 30;
|
||||
my $send_with_user_email = defined $c->config('invitations')->{'send_invitation_with_ldap_user_mail'};
|
||||
my $send_with_user_email = defined $c->config('invitations')->{'send_invitation_with_ldap_user_mail'} && $c->config('invitations')->{'send_invitation_with_ldap_user_mail'} eq 1;
|
||||
$c->render(
|
||||
template => 'invitations/invite',
|
||||
max_expire_at => $max_expire_at,
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,7 @@ const addItem = (item) => {
|
|||
const files = JSON.parse(localStorage.getItem(`${prefix}files`)) || [];
|
||||
|
||||
files.push(item);
|
||||
|
||||
localStorage.setItem(`${prefix}files`, JSON.stringify(files));
|
||||
};
|
||||
|
||||
|
@ -195,8 +196,6 @@ const populateFilesTable = () => {
|
|||
|
||||
itemsTableDOM.append(itemDOM);
|
||||
|
||||
console.debug(file.short, file.token);
|
||||
|
||||
fetch(counterURL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
|
@ -7,6 +7,22 @@ const entityMap = {
|
|||
"/": "/",
|
||||
};
|
||||
|
||||
export const addToast = (message, type) => {
|
||||
const notification = document
|
||||
.querySelector("template#notification")
|
||||
.content.cloneNode(true).children[0];
|
||||
|
||||
notification.classList.add(`is-${type}`);
|
||||
|
||||
notification.querySelector(".message").innerText = message;
|
||||
|
||||
document.getElementById("notifications-container").append(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.remove();
|
||||
}, 3500);
|
||||
};
|
||||
|
||||
export const copyToClipboard = async (text) => {
|
||||
try {
|
||||
if (navigator.clipboard) {
|
||||
|
@ -50,21 +66,11 @@ export const formatDate = (unixTimestamp) =>
|
|||
minute: "2-digit",
|
||||
});
|
||||
|
||||
// export const notify = (message, type) => {
|
||||
// const notification = document
|
||||
// .querySelector("template#notification")
|
||||
// .content.cloneNode(true).children[0];
|
||||
|
||||
// notification.classList.add(`is-${type}`);
|
||||
|
||||
// notification.querySelector(".message").innerText = message;
|
||||
|
||||
// document.getElementById("notifications-container").append(notification);
|
||||
|
||||
// setTimeout(() => {
|
||||
// notification.remove();
|
||||
// }, 3500);
|
||||
// };
|
||||
export const hideNode = (node) => {
|
||||
if (node) {
|
||||
node.classList.add("is-hidden");
|
||||
}
|
||||
};
|
||||
|
||||
export const notify = (title, body) => {
|
||||
if (isSecureContext) {
|
||||
|
@ -86,6 +92,12 @@ export const notify = (title, body) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const showNode = (node) => {
|
||||
if (node) {
|
||||
node.classList.remove("is-hidden");
|
||||
}
|
||||
};
|
||||
|
||||
export const uuidv4 = () =>
|
||||
"10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) =>
|
||||
(
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
import { filesize } from "~/lib/filesize.esm.min.js";
|
||||
import { addToast, hideNode, showNode } from "~/lib/utils.js";
|
||||
|
||||
const updateButtonsStatus = () => {
|
||||
const targetSelectionDOM = document.querySelectorAll(".target-selection");
|
||||
|
||||
if (
|
||||
document.querySelectorAll(".column.selection .checkbox input:checked")
|
||||
.length > 0
|
||||
document.querySelectorAll(".selection .checkbox input:checked").length > 0
|
||||
) {
|
||||
targetSelectionDOM.forEach((node) => (node.disabled = false));
|
||||
targetSelectionDOM.forEach((node) => {
|
||||
node.disabled = false;
|
||||
});
|
||||
} else {
|
||||
targetSelectionDOM.forEach((node) => (node.disabled = true));
|
||||
}
|
||||
};
|
||||
|
||||
const invertSelection = () => {
|
||||
document.querySelectorAll(".item .column.selection input").forEach((node) => {
|
||||
node.click();
|
||||
const updateSelection = (event) => {
|
||||
document.querySelectorAll(".item .checkbox input").forEach((node) => {
|
||||
node.checked = event.target.checked;
|
||||
});
|
||||
|
||||
updateButtonsStatus();
|
||||
|
@ -28,12 +30,12 @@ const toggleHidden = () => {
|
|||
".item[data-visibility='0']"
|
||||
);
|
||||
|
||||
if (invitationsListDOM.getAttribute("data-visibility") === "hidden") {
|
||||
if (invitationsListDOM.dataset.visibility === "hidden") {
|
||||
toggleButtonDOM.innerText = i18n.hideText;
|
||||
|
||||
itemsHiddenDOM.forEach((item) => showNode(item));
|
||||
|
||||
invitationsListDOM.setAttribute("data-visibility", "shown");
|
||||
invitationsListDOM.dataset.visibility = "shown";
|
||||
} else {
|
||||
toggleButtonDOM.innerText = i18n.showText;
|
||||
|
||||
|
@ -47,7 +49,7 @@ const toggleHidden = () => {
|
|||
}
|
||||
});
|
||||
|
||||
invitationsListDOM.setAttribute("data-visibility", "hidden");
|
||||
invitationsListDOM.dataset.visibility = "hidden";
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -70,7 +72,7 @@ const deleteInvitation = () => {
|
|||
})
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
data.tokens.forEach((t) => {
|
||||
data.success.forEach((t) => {
|
||||
addToast(t.msg, "success");
|
||||
document.getElementById(`row-${t.token}`).remove();
|
||||
});
|
||||
|
@ -114,13 +116,12 @@ const resendInvitation = () => {
|
|||
})
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
data.tokens.forEach((t) => {
|
||||
data.success.forEach((t) => {
|
||||
const itemDOM = document.getElementById(`row-${t.token}`);
|
||||
|
||||
itemDOM.querySelector(".column.expiration-date").innerText =
|
||||
t.expires;
|
||||
itemDOM.querySelector(".expiration-date").innerText = t.expires;
|
||||
|
||||
itemDOM.querySelector(".column.selection input").click();
|
||||
itemDOM.querySelector(".selection input").click();
|
||||
addToast(t.msg, "success");
|
||||
});
|
||||
|
||||
|
@ -158,22 +159,19 @@ const toggleVisibility = () => {
|
|||
if (t.show) {
|
||||
itemDOM.setAttribute("data-visibility", 1);
|
||||
showNode(itemDOM);
|
||||
itemDOM
|
||||
.querySelector(".column.selection .icon.hide-source")
|
||||
.remove();
|
||||
itemDOM.querySelector(".selection .icon.hide-source").remove();
|
||||
} else {
|
||||
itemDOM.setAttribute("data-visibility", 0);
|
||||
|
||||
if (
|
||||
document
|
||||
.querySelector(".invitations-list")
|
||||
.getAttribute("data-visibility") === "hidden"
|
||||
document.querySelector(".invitations-list").dataset.visibility ===
|
||||
"hidden"
|
||||
) {
|
||||
hideNode(itemDOM);
|
||||
}
|
||||
|
||||
itemDOM
|
||||
.querySelector(".column.selection")
|
||||
.querySelector(".selection")
|
||||
.appendChild(
|
||||
document
|
||||
.querySelector("template#icon-hide-source")
|
||||
|
@ -181,7 +179,7 @@ const toggleVisibility = () => {
|
|||
);
|
||||
}
|
||||
|
||||
itemDOM.querySelector(".column.selection input").click();
|
||||
itemDOM.querySelector(".selection input").click();
|
||||
});
|
||||
|
||||
updateButtonsStatus();
|
||||
|
@ -196,10 +194,8 @@ const getTokensBody = () => {
|
|||
const tokens = new URLSearchParams();
|
||||
|
||||
document
|
||||
.querySelectorAll(".column.selection input:checked")
|
||||
.forEach((item) =>
|
||||
tokens.append("tokens[]", item.getAttribute("data-token"))
|
||||
);
|
||||
.querySelectorAll(".selection input:checked")
|
||||
.forEach((item) => tokens.append("tokens[]", item.dataset.token));
|
||||
|
||||
return tokens;
|
||||
};
|
||||
|
@ -212,10 +208,10 @@ const fillModal = (event) => {
|
|||
modalDOM.querySelector(".files-list").replaceChildren();
|
||||
|
||||
modalDOM.querySelector("h1").innerText = i18n.listFiles
|
||||
.replace("XX1", buttonDOM.getAttribute("data-token"))
|
||||
.replace("XX2", buttonDOM.getAttribute("data-guest"));
|
||||
.replace("XX1", buttonDOM.dataset.token)
|
||||
.replace("XX2", buttonDOM.dataset.guest);
|
||||
|
||||
const files = JSON.parse(buttonDOM.getAttribute("data-files")) || [];
|
||||
const files = JSON.parse(buttonDOM.dataset.files) || [];
|
||||
const itemList = new DocumentFragment();
|
||||
|
||||
files.forEach((file) => {
|
||||
|
@ -254,10 +250,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
};
|
||||
|
||||
document
|
||||
.querySelectorAll(".column.selection input")
|
||||
.querySelectorAll(".selection input")
|
||||
.forEach((node) => (node.onclick = updateButtonsStatus));
|
||||
|
||||
document.querySelector(".action-invert-selection").onclick = invertSelection;
|
||||
document.getElementById("action-select-all").onclick = updateSelection;
|
||||
|
||||
document.querySelector(".action-toggle-hidden").onclick = toggleHidden;
|
||||
|
||||
|
|
|
@ -252,6 +252,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
|
||||
// Add the file to localStorage
|
||||
if (!isGuest) {
|
||||
console.debug(job.lufiFile.keys.server);
|
||||
addItem(
|
||||
job.lufiFile.name,
|
||||
job.lufiFile.downloadUrl(),
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th class="has-text-centered">
|
||||
<span><%= l('Selection') %></span>
|
||||
<div><%= l('Selection') %></div>
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="action-select-all">
|
||||
</div>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<p>
|
||||
<%= l('You can invite someone to send you files through this Lufi instance even if they don’t have an account on it.') %>
|
||||
</p>
|
||||
% if (stash('send_invitation_with_ldap_user_email')) {
|
||||
% if (stash('send_with_user_email')) {
|
||||
<p>
|
||||
<%= l('The invitation mail will be send from your email address (%1).', stash('user_mail')) %>
|
||||
</p>
|
||||
|
|
|
@ -1,29 +1,40 @@
|
|||
% use Number::Bytes::Human qw(format_bytes);
|
||||
% my $lang = $self->get_date_lang();
|
||||
|
||||
<section class="my-invitations-section">
|
||||
<h1><%= l('My invitations') %></h1>
|
||||
<div class="box">
|
||||
<h1 class="title is-1"><%= l('My invitations') %></h1>
|
||||
|
||||
<div class="message is-info">
|
||||
<div class="message-body">
|
||||
<p>
|
||||
<%= l('Rows in purple mean that the invitations have expired.') %>
|
||||
</p>
|
||||
<div class="actions-buttons">
|
||||
<button href="#" class="button action-invert-selection"><%= l('Invert selection') %></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
<button href="#" class="button action-toggle-hidden"><%= l('Show hidden invitations') %></button>
|
||||
<button href="#" class="button target-selection action-delete-invitation" disabled="disabled"=><%= l('Delete') %></button>
|
||||
<button href="#" class="button target-selection action-resend-invitation" disabled="disabled"><%= l('Resend invitation mail') %></button>
|
||||
<button href="#" class="button target-selection action-toggle-visibility" disabled="disabled"><%= l('Toggle visibility') %></button>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<div class="table-container">
|
||||
<table class="table is-stripped is-hoverable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= l('Selection') %></th>
|
||||
<th><%= l('Guest mail') %></th>
|
||||
<th><%= l('URL') %></th>
|
||||
<th><%= l('Created at') %></th>
|
||||
<th><%= l('Expire at') %></th>
|
||||
<th><%= l('Files sent at') %></th>
|
||||
<th><%= l('Files') %></th>
|
||||
<th class="has-text-centered">
|
||||
<div><%= l('Selection') %></div>
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="action-select-all">
|
||||
</div>
|
||||
</th>
|
||||
<th class="has-text-centered"><%= l('Guest mail') %></th>
|
||||
<th class="has-text-centered"><%= l('URL') %></th>
|
||||
<th class="has-text-centered"><%= l('Created at') %></th>
|
||||
<th class="has-text-centered"><%= l('Expire at') %></th>
|
||||
<th class="has-text-centered"><%= l('Files sent at') %></th>
|
||||
<th class="has-text-centered"><%= l('Files') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="invitations-list" data-visibility="hidden">
|
||||
|
@ -33,23 +44,23 @@
|
|||
% return if $e->deleted;
|
||||
% my $class = '';
|
||||
% $class = 'deleted' unless $e->is_valid;
|
||||
% $class .= ' hidden' unless $e->show_in_list;
|
||||
% $class .= ' is-hidden' unless $e->show_in_list;
|
||||
<tr id="row-<%= $e->token %>" class="item <%= $class %>" aria-hidden="<%= ($e->show_in_list) ? 'true' : 'false' %>" data-visibility="<%= ($e->show_in_list) ? 1 : 0 %>">
|
||||
<td class="column selection">
|
||||
<div class="checkbox input-selection">
|
||||
<input type="checkbox" data-token="<%= $e->token %>" aria-label="Select">
|
||||
<td class="selection is-vcentered has-text-centered">
|
||||
<div class="checkbox input-delete-on-first-view">
|
||||
<input type="checkbox" data-token="<%= $e->token %>" autocomplete="off" aria-label="Select">
|
||||
|
||||
% unless ($e->show_in_list) {
|
||||
<span class="icon hide-source" title="<%= l('This invitation is normally hidden') %>"></span>
|
||||
<span class="icon fas fa-eye-slash" title="<%= l('This invitation is normally hidden') %>"></span>
|
||||
% }
|
||||
</div>
|
||||
</td>
|
||||
<td class="column mail"><%= $e->guest_mail %></td>
|
||||
<td class="column url"><%= url_for('guest', token => $e->token)->to_abs %></td>
|
||||
<td class="column creation-date"><%= $lang->time2str(l('%A %d %B %Y at %T'), $e->created_at) %></td>
|
||||
<td class="column expiration-date"><%= $lang->time2str(l('%A %d %B %Y at %T'), $e->expire_at) %></td>
|
||||
<td class="column files-sent-data"><%= $lang->time2str(l('%A %d %B %Y at %T'), $e->files_sent_at) if $e->files_sent_at %></td>
|
||||
<td class="column actions">
|
||||
<td class="mail is-vcentered"><%= $e->guest_mail %></td>
|
||||
<td class="url is-vcentered"><%= url_for('guest', token => $e->token)->to_abs %></td>
|
||||
<td class="creation-date is-vcentered"><%= $lang->time2str(l('%A %d %B %Y at %T'), $e->created_at) %></td>
|
||||
<td class="expiration-date is-vcentered"><%= $lang->time2str(l('%A %d %B %Y at %T'), $e->expire_at) %></td>
|
||||
<td class="files-sent-data is-vcentered"><%= $lang->time2str(l('%A %d %B %Y at %T'), $e->files_sent_at) if $e->files_sent_at %></td>
|
||||
<td class="actions is-vcentered">
|
||||
% if ($e->files) {
|
||||
<a
|
||||
class="button modal-button action-files-info"
|
||||
|
@ -66,6 +77,7 @@
|
|||
% });
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<dialog class="modal files-info">
|
||||
<section>
|
||||
|
@ -82,10 +94,30 @@
|
|||
</footer>
|
||||
</section>
|
||||
</dialog>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="modal-language-selector" class="modal files-info">
|
||||
<div class="modal-background"></div>
|
||||
<div class="modal-card">
|
||||
<header class="modal-card-head is-shadowless">
|
||||
<p class="modal-card-title">
|
||||
<%= l('Files sent in invitation XX1 by XX2') %>
|
||||
<button class="delete is-pulled-right" aria-label="close"></button>
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<section class="modal-card-body">
|
||||
<ul class="files-list">
|
||||
|
||||
</li>
|
||||
</section>
|
||||
<footer class="modal-card-foot"></footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template id="icon-hide-source">
|
||||
<span class="icon hide-source" title="<%= l('This invitation is normally hidden') %>"></span>
|
||||
<span class="icon fas fa-eye-slash" title="<%= l('This invitation is normally hidden') %>"></span>
|
||||
</template>
|
||||
|
||||
<template id="item">
|
||||
|
@ -109,4 +141,4 @@ const deleteURL = '<%= url_for('invite_list_delete') %>';
|
|||
const resendURL = '<%= url_for('invite_list_resend') %>';
|
||||
const toggleURL = '<%= url_for('invite_list_visibility') %>';
|
||||
</script>
|
||||
%= javascript '/js/min.lufi-list-invitations.js', type => 'module', defer => "true"
|
||||
%= javascript '/js/minified/list-invitations.min.js', type => 'module', defer => "true"
|
||||
|
|
Loading…
Reference in New Issue