Merge branch 'staging' into soon

pull/1/head
ansuz 4 years ago
commit db5b825cc3

@ -78,7 +78,7 @@
} }
&.cp-support-list-closed { &.cp-support-list-closed {
.cp-support-list-actions { .cp-support-list-actions {
display: block !important; display: flex !important;
.cp-support-answer, .cp-support-close { .cp-support-answer, .cp-support-close {
display: none; display: none;
} }

14
package-lock.json generated

@ -1,6 +1,6 @@
{ {
"name": "cryptpad", "name": "cryptpad",
"version": "3.24.0", "version": "3.25.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -181,16 +181,16 @@
"optional": true "optional": true
}, },
"chainpad-crypto": { "chainpad-crypto": {
"version": "0.2.4", "version": "0.2.5",
"resolved": "https://registry.npmjs.org/chainpad-crypto/-/chainpad-crypto-0.2.4.tgz", "resolved": "https://registry.npmjs.org/chainpad-crypto/-/chainpad-crypto-0.2.5.tgz",
"integrity": "sha512-fWbVyeAv35vf/dkkQaefASlJcEfpEvfRI23Mtn+/TBBry7+LYNuJMXJiovVY35pfyw2+trKh1Py5Asg9vrmaVg==", "integrity": "sha512-K9vRsAspuX+uU1goXPz0CawpLIaOHq+1JP3WfDLqaz67LbCX/MLIUt9aMcSeIJcwZ9uMpqnbMGRktyVPoz6MCA==",
"requires": { "requires": {
"tweetnacl": "git://github.com/dchest/tweetnacl-js.git#v0.12.2" "tweetnacl": "git+https://github.com/dchest/tweetnacl-js.git#v0.12.2"
}, },
"dependencies": { "dependencies": {
"tweetnacl": { "tweetnacl": {
"version": "git://github.com/dchest/tweetnacl-js.git#8a21381d696acdc4e99c9f706f1ad23285795f79", "version": "git+https://github.com/dchest/tweetnacl-js.git#8a21381d696acdc4e99c9f706f1ad23285795f79",
"from": "git://github.com/dchest/tweetnacl-js.git#v0.12.2" "from": "git+https://github.com/dchest/tweetnacl-js.git#v0.12.2"
} }
} }
}, },

@ -1,11 +1,11 @@
{ {
"name": "cryptpad", "name": "cryptpad",
"description": "realtime collaborative visual editor with zero knowlege server", "description": "realtime collaborative visual editor with zero knowlege server",
"version": "3.24.0", "version": "3.25.0",
"license": "AGPL-3.0+", "license": "AGPL-3.0+",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git://github.com/xwiki-labs/cryptpad.git" "url": "git+https://github.com/xwiki-labs/cryptpad.git"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@ -13,7 +13,7 @@
}, },
"dependencies": { "dependencies": {
"@mcrowe/minibloom": "^0.2.0", "@mcrowe/minibloom": "^0.2.0",
"chainpad-crypto": "^0.2.2", "chainpad-crypto": "^0.2.5",
"chainpad-server": "^4.0.9", "chainpad-server": "^4.0.9",
"express": "~4.16.0", "express": "~4.16.0",
"fs-extra": "^7.0.0", "fs-extra": "^7.0.0",

@ -65,14 +65,62 @@
.cp-support-container { .cp-support-container {
display: flex; display: flex;
flex-flow: column; flex-wrap: wrap;
.cp-support-column {
min-width: 700px;
flex: 1 0 50%;
h1 {
display: flex;
align-items: center;
button {
margin-left: 50px !important;
}
}
.cp-support-count {
margin-left: 10px;
}
&.cp-support-column-collapsed {
.cp-support-list-ticket {
display: none;
}
}
}
} }
.cp-support-list-actions { .cp-support-list-actions {
margin: 10px 0px 10px 2px; margin: 10px 0px 10px 2px;
} }
.cp-support-list-ticket {
h2 {
font-size: 1.5rem;
display: flex;
justify-content: space-between;
align-items: top;
.cp-support-title-buttons {
flex-shrink: 0;
}
}
.cp-support-collapsed {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
color: #666;
.cp-support-ispremium {
padding: 0 5px;
color: @colortheme_cp-red;
background-color: lighten(@colortheme_cp-red, 25%);
}
}
}
.cp-support-list-ticket:not(.cp-support-list-closed) { .cp-support-list-ticket:not(.cp-support-list-closed) {
.cp-support-list-actions {
.cp-button-confirm, .cp-support-close {
order: 20;
margin-left: auto !important;
}
}
.cp-support-list-message { .cp-support-list-message {
&:last-child:not(.cp-support-fromadmin) { &:last-child:not(.cp-support-fromadmin) {
color: @colortheme_cp-red; color: @colortheme_cp-red;
@ -92,6 +140,28 @@
} }
} }
} }
.cp-support-list-ticket:not(.cp-support-open) {
span:first-child {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
& > :not(h2):not(.cp-support-collapsed) {
display: none;
}
.cp-support-collapse {
display: none;
}
cursor: pointer;
}
.cp-support-list-ticket.cp-support-open {
.cp-support-collapsed {
display: none;
}
.cp-support-expand {
display: none;
}
}
.cp-support-fromadmin { .cp-support-fromadmin {
color: @colortheme_logo-2; color: @colortheme_logo-2;

@ -552,7 +552,53 @@ define([
var $div = $(h('div.cp-support-container')).appendTo($container); var $div = $(h('div.cp-support-container')).appendTo($container);
var catContainer = h('div.cp-dropdown-container'); var catContainer = h('div.cp-dropdown-container');
$div.append(catContainer); Messages.admin_support_premium = "Premium tickets:"; // XXX
Messages.admin_support_normal = "Unanswered tickets:";
Messages.admin_support_answered = "Answered tickets:";
Messages.admin_support_closed = "Closed tickets:";
Messages.admin_support_open = "Show";
Messages.admin_support_collapse = "Collapse";
Messages.admin_support_first = "Created on: ";
Messages.admin_support_last = "Updated on: ";
var col1 = h('div.cp-support-column', h('h1', [
h('span', Messages.admin_support_premium),
h('span.cp-support-count'),
h('button.btn.cp-support-column-button', Messages.admin_support_collapse)
]));
var col2 = h('div.cp-support-column', h('h1', [
h('span', Messages.admin_support_normal),
h('span.cp-support-count'),
h('button.btn.cp-support-column-button', Messages.admin_support_collapse)
]));
var col3 = h('div.cp-support-column', h('h1', [
h('span', Messages.admin_support_answered),
h('span.cp-support-count'),
h('button.btn.cp-support-column-button', Messages.admin_support_collapse)
]));
var col4 = h('div.cp-support-column', h('h1', [
h('span', Messages.admin_support_closed),
h('span.cp-support-count'),
h('button.btn.cp-support-column-button', Messages.admin_support_collapse)
]));
var $col1 = $(col1), $col2 = $(col2), $col3 = $(col3), $col4 = $(col4);
$div.append([
//catContainer
col1,
col2,
col3,
col4
]);
$div.find('.cp-support-column-button').click(function () {
var $col = $(this).closest('.cp-support-column');
$col.toggleClass('cp-support-column-collapsed');
if ($col.hasClass('cp-support-column-collapsed')) {
$(this).text(Messages.admin_support_open);
$(this).toggleClass('btn-primary');
} else {
$(this).text(Messages.admin_support_collapse);
$(this).toggleClass('btn-primary');
}
});
var category = 'all'; var category = 'all';
var $drop = APP.support.makeCategoryDropdown(catContainer, function (key) { var $drop = APP.support.makeCategoryDropdown(catContainer, function (key) {
category = key; category = key;
@ -572,37 +618,128 @@ define([
var hashesById = {}; var hashesById = {};
var reorder = function () { var getTicketData = function (id) {
var order = Object.keys(hashesById); var t = hashesById[id];
order.sort(function (id1, id2) { if (!Array.isArray(t) || !t.length) { return; }
var t1 = hashesById[id1]; var ed = Util.find(t[0], ['content', 'msg', 'content', 'sender', 'edPublic']);
var t2 = hashesById[id2]; // If one of their ticket was sent as a premium user, mark them as premium
if (!Array.isArray(t1)) { return 1; } var premium = t.some(function (msg) {
if (!Array.isArray(t2)) { return -1; } var _ed = Util.find(msg, ['content', 'msg', 'content', 'sender', 'edPublic']);
var lastMsg1 = t1[t1.length - 1]; if (ed !== _ed) { return; }
var lastMsg2 = t2[t2.length - 1]; return Util.find(t[0], ['content', 'msg', 'content', 'sender', 'plan']);
var time1 = Util.find(lastMsg1, ['content', 'msg', 'content', 'time']); });
var time2 = Util.find(lastMsg2, ['content', 'msg', 'content', 'time']); var lastMsg = t[t.length - 1];
var authorEd1 = Util.find(lastMsg1, ['content', 'msg', 'content', 'sender', 'edPublic']); var lastMsgEd = Util.find(lastMsg, ['content', 'msg', 'content', 'sender', 'edPublic']);
var authorEd2 = Util.find(lastMsg2, ['content', 'msg', 'content', 'sender', 'edPublic']); return {
var admin1 = ApiConfig.adminKeys.indexOf(authorEd1) !== -1; lastMsg: lastMsg,
var admin2 = ApiConfig.adminKeys.indexOf(authorEd2) !== -1; time: Util.find(lastMsg, ['content', 'msg', 'content', 'time']),
// If one is answered and not the other, put the unanswered first lastMsgEd: lastMsgEd,
if (admin1 && !admin2) { return 1; } lastAdmin: lastMsgEd !== ed && ApiConfig.adminKeys.indexOf(lastMsgEd) !== -1,
if (!admin1 && admin2) { return -1; } premium: premium,
// Otherwise, sort them by time authorEd: ed,
return time2 - time1; closed: Util.find(lastMsg, ['content', 'msg', 'type']) === 'CLOSE'
};
};
var addClickHandler = function ($ticket) {
$ticket.on('click', function () {
$ticket.toggleClass('cp-support-open', true);
$ticket.off('click');
}); });
order.forEach(function (id, i) { };
$div.find('[data-id="'+id+'"]').css('order', i); var makeOpenButton = function ($ticket) {
var button = h('button.btn.btn-primary.cp-support-expand', Messages.admin_support_open);
var collapse = h('button.btn.cp-support-collapse', Messages.admin_support_collapse);
$(button).click(function () {
$ticket.toggleClass('cp-support-open', true);
}); });
addClickHandler($ticket);
$(collapse).click(function (e) {
$ticket.toggleClass('cp-support-open', false);
e.stopPropagation();
setTimeout(function () {
addClickHandler($ticket);
});
});
$ticket.find('.cp-support-title-buttons').prepend([button, collapse]);
$ticket.append(h('div.cp-support-collapsed'));
};
var updateTicketDetails = function ($ticket, isPremium) {
var $first = $ticket.find('.cp-support-message-from').first();
var user = $first.find('span').first().html();
var time = $first.find('.cp-support-message-time').text();
var last = $ticket.find('.cp-support-message-from').last().find('.cp-support-message-time').text();
var $c = $ticket.find('.cp-support-collapsed');
var txtClass = isPremium ? ".cp-support-ispremium" : "";
$c.html('').append([
UI.setHTML(h('span'+ txtClass), user),
h('span', [
h('b', Messages.admin_support_first),
h('span', time)
]),
h('span', [
h('b', Messages.admin_support_last),
h('span', last)
])
]);
}; };
var sort = function (id1, id2) {
var t1 = getTicketData(id1);
var t2 = getTicketData(id2);
if (!t1) { return 1; }
if (!t2) { return -1; }
/*
// If one is answered and not the other, put the unanswered first
if (t1.lastAdmin && !t2.lastAdmin) { return 1; }
if (!t1.lastAdmin && t2.lastAdmin) { return -1; }
*/
// Otherwise, sort them by time
return t1.time - t2.time;
};
var _reorder = function () {
var orderAnswered = Object.keys(hashesById).filter(function (id) {
var d = getTicketData(id);
return d && d.lastAdmin && !d.closed;
}).sort(sort);
var orderPremium = Object.keys(hashesById).filter(function (id) {
var d = getTicketData(id);
return d && d.premium && !d.lastAdmin && !d.closed;
}).sort(sort);
var orderNormal = Object.keys(hashesById).filter(function (id) {
var d = getTicketData(id);
return d && !d.premium && !d.lastAdmin && !d.closed;
}).sort(sort);
var orderClosed = Object.keys(hashesById).filter(function (id) {
var d = getTicketData(id);
return d && d.closed;
}).sort(sort);
var cols = [$col1, $col2, $col3, $col4];
[orderPremium, orderNormal, orderAnswered, orderClosed].forEach(function (list, j) {
list.forEach(function (id, i) {
var $t = $div.find('[data-id="'+id+'"]');
var d = getTicketData(id);
$t.css('order', i).appendTo(cols[j]);
updateTicketDetails($t, d.premium);
});
if (!list.length) {
cols[j].hide();
} else {
cols[j].show();
cols[j].find('.cp-support-count').text(list.length);
}
});
};
var reorder = Util.throttle(_reorder, 150);
var to = Util.throttle(function () { var to = Util.throttle(function () {
var $ticket = $div.find('.cp-support-list-ticket[data-id="'+linkedId+'"]'); var $ticket = $div.find('.cp-support-list-ticket[data-id="'+linkedId+'"]');
$ticket.addClass('cp-support-open');
$ticket[0].scrollIntoView(); $ticket[0].scrollIntoView();
linkedId = undefined; linkedId = undefined;
}, 100); }, 200);
// Register to the "support" mailbox // Register to the "support" mailbox
common.mailbox.subscribe(['supportadmin'], { common.mailbox.subscribe(['supportadmin'], {
@ -630,6 +767,7 @@ define([
if (!$ticket.length) { return; } if (!$ticket.length) { return; }
$ticket.addClass('cp-support-list-closed'); $ticket.addClass('cp-support-list-closed');
$ticket.append(APP.support.makeCloseMessage(content, hash)); $ticket.append(APP.support.makeCloseMessage(content, hash));
reorder();
return; return;
} }
if (msg.type !== 'TICKET') { return; } if (msg.type !== 'TICKET') { return; }
@ -650,13 +788,19 @@ define([
})); }));
}); });
}).nThen(function () { }).nThen(function () {
if (!error) { return void $ticket.remove(); } if (!error) {
$ticket.remove();
delete hashesById[id];
reorder();
return;
}
// if deletion failed then reactivate the button and warn // if deletion failed then reactivate the button and warn
hideButton.removeAttribute('disabled'); hideButton.removeAttribute('disabled');
// and show a generic error message // and show a generic error message
UI.alert(Messages.error); UI.alert(Messages.error);
}); });
}); });
makeOpenButton($ticket);
if (category !== 'all' && $ticket.attr('data-cat') !== category) { if (category !== 'all' && $ticket.attr('data-cat') !== category) {
$ticket.hide(); $ticket.hide();
} }

@ -774,7 +774,8 @@ define([
$(originalBtn).show(); $(originalBtn).show();
}; };
$button.click(function () { $button.click(function (e) {
e.stopPropagation();
done(true); done(true);
}); });
@ -792,7 +793,8 @@ define([
to = setTimeout(todo, INTERVAL); to = setTimeout(todo, INTERVAL);
}; };
$(originalBtn).addClass('cp-button-confirm-placeholder').click(function () { $(originalBtn).addClass('cp-button-confirm-placeholder').click(function (e) {
e.stopPropagation();
// If we have a validation function, continue only if it's true // If we have a validation function, continue only if it's true
if (config.validate && !config.validate()) { return; } if (config.validate && !config.validate()) { return; }
i = 1; i = 1;

@ -1631,7 +1631,7 @@ define([
Store.leavePad(null, data, function () {}); Store.leavePad(null, data, function () {});
}; };
var conf = { var conf = {
//Cache: Cache, // XXX re-enable cache usage Cache: Cache, // XXX re-enable cache usage
onCacheStart: function () { onCacheStart: function () {
postMessage(clientId, "PAD_CACHE"); postMessage(clientId, "PAD_CACHE");
}, },
@ -2686,7 +2686,7 @@ define([
readOnly: false, readOnly: false,
validateKey: secret.keys.validateKey || undefined, validateKey: secret.keys.validateKey || undefined,
crypto: Crypto.createEncryptor(secret.keys), crypto: Crypto.createEncryptor(secret.keys),
//Cache: Cache, // XXX re-enable cache usage Cache: Cache, // XXX re-enable cache usage
userName: 'fs', userName: 'fs',
logLevel: 1, logLevel: 1,
ChainPad: ChainPad, ChainPad: ChainPad,

@ -175,7 +175,7 @@ define([
ChainPad: ChainPad, ChainPad: ChainPad,
classic: true, classic: true,
network: network, network: network,
//Cache: Cache, // XXX re-enable cache usage Cache: Cache, // XXX re-enable cache usage
metadata: { metadata: {
validateKey: secret.keys.validateKey || undefined, validateKey: secret.keys.validateKey || undefined,
owners: owners owners: owners

@ -427,7 +427,7 @@ define([
channel: secret.channel, channel: secret.channel,
crypto: crypto, crypto: crypto,
ChainPad: ChainPad, ChainPad: ChainPad,
//Cache: Cache, // XXX re-enable cache usage Cache: Cache, // XXX re-enable cache usage
metadata: { metadata: {
validateKey: secret.keys.validateKey || undefined, validateKey: secret.keys.validateKey || undefined,
}, },

@ -230,7 +230,7 @@ define([
var form = h('div.cp-support-form-container', content); var form = h('div.cp-support-form-container', content);
$(cancel).click(function () { $(cancel).click(function () {
$(form).closest('.cp-support-list-ticket').find('.cp-support-list-actions').show(); $(form).closest('.cp-support-list-ticket').find('.cp-support-list-actions').css('display', '');
$(form).remove(); $(form).remove();
}); });
@ -257,8 +257,9 @@ define([
var url; var url;
if (ctx.isAdmin) { if (ctx.isAdmin) {
ticketCategory = Messages['support_cat_'+(content.category || 'all')] + ' - '; ticketCategory = Messages['support_cat_'+(content.category || 'all')] + ' - ';
url = h('button.btn.btn-primary.fa.fa-clipboard'); url = h('button.btn.fa.fa-clipboard');
$(url).click(function () { $(url).click(function (e) {
e.stopPropagation();
var link = privateData.origin + privateData.pathname + '#' + 'support-' + content.id; var link = privateData.origin + privateData.pathname + '#' + 'support-' + content.id;
var success = Clipboard.copy(link); var success = Clipboard.copy(link);
if (success) { UI.log(Messages.shareSuccess); } if (success) { UI.log(Messages.shareSuccess); }
@ -269,7 +270,10 @@ define([
'data-cat': content.category, 'data-cat': content.category,
'data-id': content.id 'data-id': content.id
}, [ }, [
h('h2', [ticketCategory, ticketTitle, url]), h('h2', [
h('span', [ticketCategory, ticketTitle]),
h('span.cp-support-title-buttons',url)
]),
actions actions
])); ]));
@ -303,7 +307,7 @@ define([
var form = makeForm(ctx, function () { var form = makeForm(ctx, function () {
var sent = sendForm(ctx, content.id, form, content.sender); var sent = sendForm(ctx, content.id, form, content.sender);
if (sent) { if (sent) {
$(actions).show(); $(actions).css('display', '');
$(form).remove(); $(form).remove();
} }
}, content.title); }, content.title);

Loading…
Cancel
Save