feat: Adjust copy for setup.

This commit is contained in:
Ruben Verborgh 2021-09-23 19:39:55 +01:00 committed by Joachim Van Herwegen
parent b592d449eb
commit 34a44d1636
7 changed files with 152 additions and 175 deletions

View File

@ -1,5 +1,7 @@
<% const isBlankForm = !('prefilled' in locals); %>
<% prefilled = locals.prefilled || {}; %>
<%
const isBlankForm = !('prefilled' in locals);
prefilled = locals.prefilled || {};
%>
<fieldset>
<legend>Your WebID</legend>
@ -47,41 +49,39 @@
<fieldset>
<legend>Your Pod</legend>
<p>
A Pod is a place to store your data.
<br>
If you create a new WebID, you must also create a Pod to store that WebID.
A Pod is a storage place for your data.
</p>
<ol>
<li class="checkbox">
<label>
<input type="checkbox" id="createPod" name="createPod"<%
if (isBlankForm || prefilled.createPod) { %> checked<% } %>>
Create a new Pod with my WebID as owner
Create a new Pod with my WebID as owner<% if (!locals.allowRoot) { %>.<% } %>
</label>
<ol id="createPodForm">
<li class="radio" id="rootPodOnForm">
<% if (locals.allowRoot) { %>
<li class="radio">
<label>
<input type="radio" id="rootPodOn" name="rootPod" value="on"<%
if (locals.allowRoot && (isBlankForm || prefilled.rootPod)) { %> checked<% } %>>
... in the root.
if (isBlankForm || prefilled.rootPod) { %> checked<% } %>>
in the root.
</label>
</li>
<li class="radio">
<label>
<input type="radio" id="rootPodOff" name="rootPod" value=""<%
if (!locals.allowRoot || (!isBlankForm && !prefilled.rootPod)) { %> checked<% } %>>
... in its own namespace.
if (!isBlankForm && !prefilled.rootPod) { %> checked<% } %>>
in its own namespace.
</label>
<ol id="podNameForm">
<li>
</li>
<% } %>
<li id="podNameForm">
<label for="podName">Pod name:</label>
<input id="podName" type="text" name="podName" value="<%= prefilled.podName || '' %>">
</li>
</ol>
</li>
</ol>
</li>
</ol>
</fieldset>
<fieldset>
@ -116,38 +116,47 @@
</div>
</fieldset>
<!-- Assist the user with filling out the form by hiding irrelevant fields -->
<script>
// Assist the user with filling out the form by hiding irrelevant fields
(() => {
// Wire up the UI elements
const elements = {};
// Wires up the DOM element with the specified ID
function registerElement(id) {
const element = document.getElementById(id) || document.createElement('input');
elements[id] = element;
element.addEventListener('change', synchronizeInputFields);
}
// Wire up all elements
[
'mainForm',
'createWebIdOn', 'createWebIdOff', 'createWebIdForm', 'existingWebIdForm', 'webId',
'createPod', 'createPodForm', 'rootPodOnForm', 'rootPodOn', 'rootPodOff', 'podNameForm', 'podName',
'createPod', 'createPodForm', 'rootPodOn', 'rootPodOff', 'podNameForm', 'podName',
'register', 'passwordForm', 'noPasswordForm',
].forEach(id => {
elements[id] = document.getElementById(id);
elements[id].addEventListener('change', updateUI);
});
elements.mainForm = document.getElementById('<%= formId %>');
].forEach(registerElement);
updateUI();
// Conditions under which elements should be visible
const visibilityConditions = {
createWebIdForm: () => elements.createWebIdOn.checked,
existingWebIdForm: () => elements.createWebIdOff.checked,
createPodForm: () => elements.createPod.checked,
podNameForm: () => !elements.rootPodOn.checked,
passwordForm: () => elements.createWebIdOn.checked || elements.register.checked,
noPasswordForm: () => !isVisible('passwordForm'),
};
// Updates the UI when something has changed
function updateUI({ srcElement } = {}) {
// When Pod creation is required, automatically tick the corresponding checkbox
// Ensures that the only relevant input fields are visible and enabled
function synchronizeInputFields({ srcElement } = {}) {
// The user needs a Pod if they want to create a WebID
if (elements.createWebIdOn.checked)
elements.createPod.checked = true;
elements.createPod.disabled = elements.createWebIdOn.checked;
// Hide irrelevant fields
setVisibility('createWebIdForm', elements.createWebIdOn.checked);
setVisibility('existingWebIdForm', elements.createWebIdOff.checked);
setVisibility('createPodForm', elements.createPod.checked);
setVisibility('rootPodOnForm', <%= locals.allowRoot %>);
setVisibility('podNameForm', elements.rootPodOff.checked);
setVisibility('passwordForm', elements.createWebIdOn.checked || elements.register.checked);
setVisibility('noPasswordForm', !isVisible('passwordForm'));
for (const [id, condition] of Object.entries(visibilityConditions))
setVisibility(id, condition());
// Lock pod creation if a WebID is requested
elements.createPod.disabled = elements.createWebIdOn.checked;
// If child elements have just been activated, focus on them
if (srcElement?.checked) {
@ -158,9 +167,6 @@
webId.focus();
break;
case elements.createPod:
if (elements.rootPodOn.checked) {
break;
}
case elements.rootPodOff:
elements.podName.focus();
break;
@ -192,12 +198,18 @@
return [...element.querySelectorAll("*")];
}
// TODO: take form id as input?
// Prepare the form when the DOM is ready
window.addEventListener('DOMContentLoaded', (event) => {
synchronizeInputFields();
elements.mainForm.classList.add('loaded');
});
// Enable all elements on form submission (otherwise their value is not submitted)
elements.mainForm.addEventListener('submit', () => {
for (const child of getDescendants(elements.mainForm))
for (const child of getDescendants(elements.mainForm)) {
if (child.name)
child.disabled = false;
}
});
elements.mainForm.addEventListener('formdata', updateUI);
})();
elements.mainForm.addEventListener('formdata', synchronizeInputFields);
</script>

View File

@ -5,7 +5,7 @@
<p class="error">Error: <%= message %></p>
<% } %>
<%- include('./register-partial.html.ejs', { allowRoot: false, formId: 'mainForm' }) %>
<%- include('./register-partial.html.ejs', { allowRoot: false }) %>
<p class="actions"><button type="submit" name="submit">Sign up</button></p>
</form>

View File

@ -22,22 +22,21 @@
<h2 id="users">Getting started as a <em>user</em></h2>
<p>
<strong><a href="/idp/register/">Sign up</a> for an account</strong>
<a href="/idp/register/">Sign up for an account</a>
to get started with your own Pod and WebID.
</p>
<p>
The <em>default</em> configuration stores data only in memory,
so be sure to choose a configuration that saves data to disk.
If you are exposing this server publicly,
<a href="#public">read the guidelines below</a>.
The default configuration stores data only in memory.
If you want to keep data permanently,
choose a configuration that saves data to disk instead.
</p>
<h2 id="developers">Getting started as a <em>developer</em></h2>
<p>
The <em>default</em> server configuration includes
this <strong>ready-to-use root Pod</strong> you're looking at.
That way, you don't need to create an account
to read and write data or to test apps.
<a href="./setup">Run the setup</a> to configure your server.
<br>
The default configuration includes
the <strong>ready-to-use root Pod</strong> you're currently looking at.
</p>
<p>
You can easily choose any folder on your disk
@ -46,28 +45,6 @@
Use the <code>--help</code> switch to learn more.
</p>
<h2 id="public">Making this server public</h2>
<p>
Before making this server public,
you might want to <strong>disable certain convenience features</strong>
so they remain only accessible to you:
</p>
<ul>
<li>
Modify or delete this welcome document
at <a href="index.html"><code>index.html</code></a>.
</li>
<li>
Prevent public write and control access to the root Pod
by modifying <a href="../../../.acl"><code>.acl</code></a>.
</li>
<li>
Disable Pod registration
by <a href="https://github.com/solid/community-server/blob/main/config/identity/README.md">changing
the configuration</a>.
</li>
</ul>
<h2>Have a wonderful Solid experience</h2>
<p>
<strong>Learn more about Solid

View File

@ -1,39 +1,7 @@
<h1>Welcome to Solid</h1>
<h1>Set up your Solid server</h1>
<p>
This server implements
the <a href="https://solid.github.io/specification/protocol">Solid protocol</a>
so you can create your own <a href="https://solidproject.org/about">Solid Pod</a>
and identity.
</p>
<h2 id="public">Making this server public</h2>
<p>
Before making this server public,
you might want to <strong>disable Pod registration</strong>
by <a href="https://github.com/solid/community-server/blob/main/config/identity/README.md">changing
the configuration</a>.
</p>
<h2 id="setup">Setting up the server</h2>
<p>
The <em>default</em> configuration stores data only in memory,
so be sure to choose a configuration that saves data to disk.
If you are exposing this server publicly,
<a href="#public">read the guidelines below</a>.
</p>
<p>
When using the file-based version of the server,
you can easily choose any folder on your disk to use as root.
<br>
Use the <code>--help</code> switch to learn more.
</p>
<p>
To make sure the server is set up exactly as you want it,
please fill in the form below.
</p>
<p>
In case you want to automate the server initialization and want to get rid of this setup screen,
update your config with new imports from <code>config/app/setup/</code> and possibly <code>config/app/init/</code>.
Your Solid server needs a <strong>one-time setup</strong>
so it acts exactly the way you want.
</p>
<form method="post" id="mainForm">
@ -43,46 +11,62 @@
<p class="error"><%= message %></p>
<% } %>
<fieldset>
<legend>Choose options</legend>
<legend>Accounts on this server</legend>
<ol>
<li class="checkbox">
<label>
<input type="checkbox" id="initialize" name="initialize" checked>
Allow access to the root container.
<input type="checkbox" checked disabled>
Enable account registration.
</label>
<p>
This defaults to public access for everyone.
Disabling this makes it impossible to access the root container and add resources,
but new pods can still be created through registration,
which is ideal if you only want data to be edited in the pods.
This option is irrelevant when creating a root pod with the option below.
You can disable account registration
by <a href="https://github.com/solid/community-server/blob/main/config/identity/README.md">changing the configuration</a>.
</p>
</li>
<li class="checkbox">
<label>
<input type="checkbox" id="registration" name="registration" checked>
Provision a pod, create a WebID, and/or register an identity.
<input type="checkbox" id="registration" name="registration">
Sign me up for an account.
</label>
<p>
Any existing root Pod will be disabled.
</p>
</li>
<li class="checkbox" id="initializeForm">
<label>
<input type="checkbox" id="initialize" name="initialize">
Expose a public root Pod.
</label>
<p>
By default, the public has read and write access to the root Pod.
<br>
You typically only want to choose this
for rapid testing and development.
</p>
</li>
</ol>
</fieldset>
<fieldset id="registrationForm">
<%- include('../identity/email-password/register-partial.html.ejs', { allowRoot: true, formId: 'mainForm' }) %>
<legend>Sign up</legend>
<%-
include('../identity/email-password/register-partial.html.ejs', {
allowRoot: true,
})
%>
</fieldset>
<p class="actions"><button type="submit" name="submit">Submit</button></p>
<p class="actions"><button type="submit">Complete setup</button></p>
</form>
<!-- Show or hide the account creation form when needed -->
<script>
const registrationCheckbox = document.getElementById('registration');
registrationCheckbox.addEventListener('change', updateUI);
const registrationForm = document.getElementById('registrationForm');
[
'registration', 'registrationForm', 'initializeForm',
].forEach(registerElement);
function updateUI() {
const visible = registrationCheckbox.checked;
registrationForm.classList[visible ? 'remove' : 'add']('hidden');
}
updateUI();
Object.assign(visibilityConditions, {
registrationForm: () => elements.registration.checked,
initializeForm: () => !elements.registration.checked,
});
</script>

View File

@ -1,24 +1,21 @@
<h1 id="public">Server successfully set up</h1>
<h1 id="public">Server setup complete</h1>
<p>
Congratulations!
Your Solid server is now ready to use.
<br>
You can now visit its <a href="./">homepage</a>.
</p>
<% if (initialize && !registration) { %>
<h2>Root Pod</h2>
<p>
You have chosen to allow the root container to be accessible.
<strong>The root Pod is publicly accessible.</strong>
<br>
Prevent public write and control access to the root
by modifying <a href=".acl"><code>.acl</code></a>.
by modifying its <a href=".acl">ACL document</a>.
</p>
<% } %>
<% if (registration) { %>
<%- include('../identity/email-password/register-response-partial.html.ejs', { authenticating: false }) %>
<% } %>
<h2>Have a wonderful Solid experience</h2>
<p>
<strong>Learn more about Solid
at <a href="https://solidproject.org/">solidproject.org</a>.</strong>
</p>
<p>
You are warmly invited
to <a href="https://github.com/solid/community-server/discussions">share your experiences</a>
and to <a href="https://github.com/solid/community-server/issues">report any bugs</a> you encounter.
</p>

View File

@ -151,6 +151,12 @@ fieldset > legend {
fieldset > legend + p {
margin: 0 0 .5em .25em;
}
fieldset > fieldset > legend {
font-size: 1.2em;
}
.hidden legend {
display: none;
}
fieldset ol {
list-style: none;
margin: 0;
@ -170,6 +176,7 @@ fieldset ol ol li:not(.checkbox, .radio) {
}
fieldset li label {
font-weight: 600;
cursor: pointer;
}
fieldset li li label {
font-weight: 500;
@ -220,7 +227,7 @@ form ul.actions > li {
}
form.loaded * {
max-height: 500px;
max-height: 1000px;
transition: max-height .2s;
}
form .hidden {

View File

@ -33,21 +33,21 @@ describe('A Solid server with setup', (): void => {
it('catches all requests.', async(): Promise<void> => {
let res = await fetch(baseUrl, { method: 'GET', headers: { accept: 'text/html' }});
expect(res.status).toBe(200);
await expect(res.text()).resolves.toContain('Welcome to Solid');
await expect(res.text()).resolves.toContain('Set up your Solid server');
res = await fetch(joinUrl(baseUrl, '/random/path/'), { method: 'GET', headers: { accept: 'text/html' }});
expect(res.status).toBe(200);
await expect(res.text()).resolves.toContain('Welcome to Solid');
await expect(res.text()).resolves.toContain('Set up your Solid server');
res = await fetch(joinUrl(baseUrl, '/random/path/'), { method: 'PUT', headers: { accept: 'text/html' }});
expect(res.status).toBe(405);
await expect(res.text()).resolves.toContain('Welcome to Solid');
await expect(res.text()).resolves.toContain('Set up your Solid server');
});
it('can create a server that disables root but allows registration.', async(): Promise<void> => {
let res = await fetch(setupUrl, { method: 'POST', headers: { accept: 'text/html' }});
expect(res.status).toBe(200);
await expect(res.text()).resolves.toContain('Server successfully set up');
await expect(res.text()).resolves.toContain('Server setup complete');
// Root access disabled
res = await fetch(baseUrl);
@ -74,7 +74,7 @@ describe('A Solid server with setup', (): void => {
body: JSON.stringify({ initialize: true }),
});
expect(res.status).toBe(200);
await expect(res.text()).resolves.toContain('Server successfully set up');
await expect(res.text()).resolves.toContain('Server setup complete');
// Root access enabled
res = await fetch(baseUrl);
@ -99,7 +99,7 @@ describe('A Solid server with setup', (): void => {
body: JSON.stringify({ registration: true, initialize: true, ...registerParams }),
});
expect(res.status).toBe(200);
await expect(res.text()).resolves.toContain('Server successfully set up');
await expect(res.text()).resolves.toContain('Server setup complete');
// Root profile created
res = await fetch(joinUrl(baseUrl, '/profile/card'));