assorted home page fixes/improvements

* link to home page from other static pages
* home notice
  * moved to the top of the home page
  * configured via server API instead of application_config.js
  * WIP admin panel UI
* more debugging info for unsupported decrees
* lint compliance probably
This commit is contained in:
ansuz 2022-05-06 13:55:00 +05:30
parent 5fd4b7a3cb
commit a2731c44b0
8 changed files with 110 additions and 33 deletions

View file

@ -74,6 +74,7 @@ define([
return select; return select;
}; };
/* // XXX remove ?
var footerCol = function (title, L, n) { var footerCol = function (title, L, n) {
n = n || 3; n = n || 3;
return h('div.col-sm-' + n, [ return h('div.col-sm-' + n, [
@ -87,6 +88,7 @@ define([
) )
]); ]);
}; };
*/
var footLink = function (ref, loc, text, icon) { var footLink = function (ref, loc, text, icon) {
if (!ref) { return; } if (!ref) { return; }
@ -243,6 +245,11 @@ define([
// $('#menuCollapse').slideDown(); // $('#menuCollapse').slideDown();
// }); // });
var isHome = ['/', '/index.html'].includes(window.location.pathname);
var homeLink = h('a.nav-item.nav-link' /* .navbar-brand */, { href: '/index.html' }, [
'Home page', // XXX replace with image or whatever
]);
return h('nav.navbar.navbar-expand-lg', return h('nav.navbar.navbar-expand-lg',
// XXX DB add link back to index.html on other pages // XXX DB add link back to index.html on other pages
// h('a.navbar-brand', { href: '/index.html'}, [ // h('a.navbar-brand', { href: '/index.html'}, [
@ -255,8 +262,7 @@ define([
// button, // XXX collapse button // button, // XXX collapse button
// add .collapse.navbar-collapse.justify-content-end#menuCollapse to div below to enable collapse button // add .collapse.navbar-collapse.justify-content-end#menuCollapse to div below to enable collapse button
[ [
// XXX remove about page !isHome? homeLink: undefined,
// h('a.nav-item.nav-link', { href: '/what-is-cryptpad.html'}, Msg.about),
h('a.nav-item.nav-link', { href: '/features.html'}, Pages.areSubscriptionsAllowed()? Msg.pricing: Msg.features), h('a.nav-item.nav-link', { href: '/features.html'}, Pages.areSubscriptionsAllowed()? Msg.pricing: Msg.features),
h('a.nav-item.nav-link', { href: 'https://docs.cryptpad.fr'}, h('a.nav-item.nav-link', { href: 'https://docs.cryptpad.fr'},
[h('i.fa.fa-book', {'aria-hidden':'true'}),Msg.docs_link]), [h('i.fa.fa-book', {'aria-hidden':'true'}),Msg.docs_link]),

View file

@ -109,7 +109,8 @@ define([
var fastLink = k => pageLink(Pages.customURLs[k], k); var fastLink = k => pageLink(Pages.customURLs[k], k);
// XXX DB // XXX DB
Msg.terms = "Terms of Service"; Msg.terms = Msg.footer_tos; //"Terms of Service"; // XXX
Msg.home_location = "Encrypted data is hosted in {0}"; // XXX
// XXX DB: this may be wrong, pasted over form pages.js // XXX DB: this may be wrong, pasted over form pages.js
var imprintLink = fastLink('imprint'); var imprintLink = fastLink('imprint');
@ -121,10 +122,9 @@ define([
If the text is the key for the translation system then then the most appropriate translated text If the text is the key for the translation system then then the most appropriate translated text
will be displayed. Otherwise, the direct text will be included as HTML. will be displayed. Otherwise, the direct text will be included as HTML.
*/ */
if (AppConfig.homeNotice) { if (Pages.Instance.notice) {
notice = h('div.alert.alert-info', Pages.setHTML(h('span'), [ console.log(Pages.Instance.notice);
Msg[AppConfig.homeNotice] || AppConfig.homeNotice notice = h('div.alert.alert-info', Pages.setHTML(h('span'), Pages.Instance.notice));
]));
} }
// instance title // instance title
@ -134,15 +134,13 @@ define([
// instance location // instance location
var locationBlock; var locationBlock;
if (Pages.Instance.location) { if (Pages.Instance.location) {
locationBlock = h('div.cp-instance-location', [ locationBlock = h('div.cp-instance-location', [
h('i.fa.fa-map-pin', {'aria-hidden': 'true'}), h('i.fa.fa-map-pin', {'aria-hidden': 'true'}),
'Encrypted data is hosted in: ', // XXX translate Msg._getKey('home_location', [ Pages.Instance.location ]),
Pages.Instance.location,
]); ]);
} else { } else {
locationBlock = h('div', h('br')); // XXX locationBlock = h('div', h('br'));
} }
Msg.home_morestorage = 'For more storage space, and to support the project:'; // XXX Msg.home_morestorage = 'For more storage space, and to support the project:'; // XXX
@ -165,6 +163,7 @@ define([
return [ return [
h('div#cp-main', [ h('div#cp-main', [
Pages.infopageTopbar(), Pages.infopageTopbar(),
notice,
h('div.container.cp-container', [ h('div.container.cp-container', [
h('div.row.cp-home-hero', [ h('div.row.cp-home-hero', [
h('div.cp-title.col-md-6', [ h('div.cp-title.col-md-6', [
@ -174,7 +173,7 @@ define([
alt: '' alt: ''
}), }),
instanceTitle, instanceTitle,
UI.setHTML(h('span.tag-line'), Pages.Instance.description), Pages.setHTML(h('span.tag-line'), Pages.Instance.description),
locationBlock, locationBlock,
termsLink, termsLink,
privacyLink, privacyLink,
@ -199,7 +198,6 @@ define([
]) ])
]) ])
]), ]),
notice
]), ]),
Pages.infopageFooter(), Pages.infopageFooter(),
]), ]),

View file

@ -359,6 +359,7 @@ var instanceStatus = function (Env, Server, cb) {
instanceDescription: Env.instanceDescription, instanceDescription: Env.instanceDescription,
instanceJurisdiction: Env.instanceJurisdiction, instanceJurisdiction: Env.instanceJurisdiction,
instanceName: Env.instanceName, instanceName: Env.instanceName,
instanceNotice: Env.instanceNotice,
}); });
}; };

View file

@ -196,14 +196,45 @@ commands.SET_SUPPORT_MAILBOX = makeGenericSetter('supportMailbox', function (arg
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_PURPOSE', ["development"]]], console.log) // CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_PURPOSE', ["development"]]], console.log)
commands.SET_INSTANCE_PURPOSE = makeGenericSetter('instancePurpose', args_isString); commands.SET_INSTANCE_PURPOSE = makeGenericSetter('instancePurpose', args_isString);
var makeTranslation = function (attr) {
return function (Env, args) {
if (!Array.isArray(args)) { throw new Error("INVALID_ARGS"); }
var value = args[0];
var state = Env[attr];
if (typeof(value) === 'string') {
if (state.default === value) { return false; }
state.default = value;
return true;
}
if (value && typeof(value) === 'object') {
var changed = false;
Object.keys(value).forEach(function (lang) {
if (state[lang] === value[lang]) { return; }
state[lang] = value[lang];
changed = true;
});
return changed;
}
return false;
};
};
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_JURISDICTION', ['France']]], console.log) // CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_JURISDICTION', ['France']]], console.log)
commands.SET_INSTANCE_JURISDICTION = makeGenericSetter('instanceJurisdiction', args_isString); // CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_JURISDICTION', [{default:'France',de:'Frankreich'}]]], console.log)
commands.SET_INSTANCE_JURISDICTION = makeTranslation('instanceJurisdiction');
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_NAME', ['My Personal CryptPad']]], console.log) // CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_NAME', ['My Personal CryptPad']]], console.log)
commands.SET_INSTANCE_NAME = makeGenericSetter('instanceName', args_isString); // CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_NAME', [{default:'My Personal CryptPad', fr: "Mon CryptPad personnel"}]]], console.log)
commands.SET_INSTANCE_NAME = makeTranslation('instanceName');
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_DESCRIPTION', ['A personal instance, hosted for me and nobody else']]], console.log) // CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_DESCRIPTION', ['A personal instance, hosted for me and nobody else']]], console.log)
commands.SET_INSTANCE_DESCRIPTION = makeGenericSetter('instanceDescription', args_isString); // CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_DESCRIPTION', [{default:'A personal server, not intended for public usage', fr: 'Un serveur personnel, non destiné à un usage public'}]]], console.log)
commands.SET_INSTANCE_DESCRIPTION = makeTranslation('instanceDescription'); // XXX support translation
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_NOTICE', ['Our hosting costs have increased during the pandemic. Please consider donating!']]], console.log)
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_NOTICE', [{default:'Our hosting costs have increased during the pandemic. Please consider donating!',fr:'Nos coûts d'hébergement ont augmenté pendant la pandémie. Veuillez envisager de faire un don !']]], console.log)
commands.SET_INSTANCE_NOTICE = makeTranslation('instanceNotice');
// Maintenance: Empty string or an object with a start and end time // Maintenance: Empty string or an object with a start and end time
var isNumber = function (value) { var isNumber = function (value) {
@ -370,7 +401,7 @@ Decrees.load = function (Env, _cb) {
try { try {
handler(void 0, JSON.parse(text)); handler(void 0, JSON.parse(text));
} catch (err) { } catch (err) {
handler(err); handler(err, text);
} }
next(); next();
}, function (err) { }, function (err) {

View file

@ -192,9 +192,10 @@ module.exports.create = function (config) {
provideAggregateStatistics: false, provideAggregateStatistics: false,
updateAvailable: undefined, updateAvailable: undefined,
instanceName: '', instanceName: {},
instanceDescription: '', instanceDescription: {},
instanceJurisdiction: '', instanceJurisdiction: {},
instanceNotice: {},
myDomain: config.myDomain, myDomain: config.myDomain,
mySubdomain: config.mySubdomain, // only exists for the accounts integration mySubdomain: config.mySubdomain, // only exists for the accounts integration

View file

@ -270,15 +270,10 @@ var define = function (obj) {
app.get('/api/instance', function (req, res) { // XXX use caching? app.get('/api/instance', function (req, res) { // XXX use caching?
res.setHeader('Content-Type', 'text/javascript'); res.setHeader('Content-Type', 'text/javascript');
res.send(define({ res.send(define({
name: { name: Env.instanceName,
default: Env.instanceName, description: Env.instanceDescription,
}, location: Env.instanceJurisdiction,
description: { notice: Env.instanceNotice,
default: Env.instanceDescription,
},
location: {
default: Env.instanceJurisdiction,
},
})); }));
}); });

View file

@ -40,6 +40,7 @@
} }
.cp-admin-setlimit-form, .cp-admin-setlimit-form,
.cp-admin-setjurisdiction-form, .cp-admin-setjurisdiction-form,
.cp-admin-setnotice-form, // XXX not great
.cp-admin-setdescription-form { .cp-admin-setdescription-form {
+ button { + button {
margin-top: 5px !important; margin-top: 5px !important;

View file

@ -62,6 +62,7 @@ define([
'cp-admin-name', 'cp-admin-name',
'cp-admin-description', 'cp-admin-description',
'cp-admin-jurisdiction', 'cp-admin-jurisdiction',
'cp-admin-notice',
], ],
'quota': [ // Msg.admin_cat_quota 'quota': [ // Msg.admin_cat_quota
'cp-admin-defaultlimit', 'cp-admin-defaultlimit',
@ -429,7 +430,7 @@ define([
return $div; return $div;
}; };
create['jurisdiction'] = function () { create['jurisdiction'] = function () { // XXX make translateable
var key = 'jurisdiction'; var key = 'jurisdiction';
var $div = makeBlock(key, true); // Msg.admin_jurisdictionHint, Msg.admin_jurisdictionTitle, Msg.admin_jurisdictionButton var $div = makeBlock(key, true); // Msg.admin_jurisdictionHint, Msg.admin_jurisdictionTitle, Msg.admin_jurisdictionButton
var $button = $div.find('button').addClass('cp-listing-action').text(Messages.settings_save); var $button = $div.find('button').addClass('cp-listing-action').text(Messages.settings_save);
@ -468,6 +469,49 @@ define([
return $div; return $div;
}; };
Messages.admin_noticeTitle = "admin_noticeTitle";
Messages.admin_noticeHint = "admin_noticeHint";
//Messages.admin_noticeButton = "admin_noticeButton";
create['notice'] = function () { // XXX add input, make translateable
var key = 'notice';
var $div = makeBlock(key, true);
var $button = $div.find('button').addClass('cp-listing-action').text(Messages.settings_save);
var input = h('input.cp-listing-info', {
type: 'text',
value: APP.instanceStatus.instanceNotice || '',
placeholder: Messages.owner_unknownUser || '',
});
var $input = $(input);
var innerDiv = h('div.cp-admin-setnotice-form', input);
var spinner = UI.makeSpinner($(innerDiv));
$button.click(function () {
spinner.spin();
$button.attr('disabled', 'disabled');
sFrameChan.query('Q_ADMIN_RPC', {
cmd: 'ADMIN_DECREE',
data: ['SET_INSTANCE_NOTICE', [$input.val().trim()]]
}, function (e, response) {
$button.removeAttr('disabled');
spinner.hide();
if (e || response.error) {
UI.warn(Messages.error);
$input.val('');
console.error(e, response);
return;
}
UI.log(Messages._getKey('ui_saved', [Messages.admin_noticeTitle]));
});
});
$button.before(innerDiv);
return $div;
};
create['instance-info-notice'] = function () { create['instance-info-notice'] = function () {
return $(h('div.cp-admin-instance-info-notice.cp-sidebarlayout-element', return $(h('div.cp-admin-instance-info-notice.cp-sidebarlayout-element',
h('div.alert.alert-info.cp-admin-bigger-alert', [ h('div.alert.alert-info.cp-admin-bigger-alert', [
@ -478,7 +522,7 @@ define([
)); ));
}; };
create['name'] = function () { create['name'] = function () { // XXX make translateable
var key = 'name'; var key = 'name';
var $div = makeBlock(key, true); var $div = makeBlock(key, true);
// Msg.admin_nameHint, Msg.admin_nameTitle, Msg.admin_nameButton // Msg.admin_nameHint, Msg.admin_nameTitle, Msg.admin_nameButton
@ -519,7 +563,7 @@ define([
return $div; return $div;
}; };
create['description'] = function () { create['description'] = function () { // XXX support translation
var key = 'description'; var key = 'description';
var $div = makeBlock(key, true); // Msg.admin_descriptionHint var $div = makeBlock(key, true); // Msg.admin_descriptionHint
@ -1419,7 +1463,7 @@ define([
}; };
create['broadcast'] = function () { create['broadcast'] = function () { // XXX
var key = 'broadcast'; var key = 'broadcast';
var $div = makeBlock(key); // Msg.admin_broadcastHint, admin_broadcastTitle var $div = makeBlock(key); // Msg.admin_broadcastHint, admin_broadcastTitle