Move apps/cory/ => apps/. Going to change import and export to support this.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4163 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
2023-02-02 00:18:22 +00:00
parent 6104af0d70
commit ec52e62908
53 changed files with 0 additions and 0 deletions

22
apps/admin/app.js Normal file
View File

@ -0,0 +1,22 @@
import * as tfrpc from '/tfrpc.js';
tfrpc.register(function delete_user(user) {
return core.deleteUser(user);
});
tfrpc.register(function global_settings_set(key, value) {
return core.globalSettingsSet(key, value);
});
async function main() {
let data = {
users: {},
granted: await core.allPermissionsGranted(),
settings: await core.globalSettingsDescriptions(),
};
for (let user of await core.users()) {
data.users[user] = await core.permissionsForUser(user);
}
await app.setDocument(utf8Decode(getFile('index.html')).replace('$data', JSON.stringify(data)));
}
main();

10
apps/admin/index.html Normal file
View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<script>const g_data = $data;</script>
</head>
<body style="color: #fff">
<h1>Tilde Friends Administration</h1>
</body>
<script type="module" src="script.js"></script>
</html>

13
apps/admin/lit.min.js vendored Normal file

File diff suppressed because one or more lines are too long

78
apps/admin/script.js Normal file
View File

@ -0,0 +1,78 @@
import {html, render} from './lit.min.js';
import * as tfrpc from '/static/tfrpc.js';
function delete_user(user) {
if (confirm(`Are you sure you want to delete the user "${user}"?`)) {
tfrpc.rpc.delete_user(user).then(function() {
alert(`User "${user}" deleted successfully.`);
}).catch(function(error) {
alert(`Failed to delete user "${user}": ${JSON.stringify(error, null, 2)}.`);
});
}
}
function global_settings_set(key, value) {
tfrpc.rpc.global_settings_set(key, value).then(function() {
alert(`Set "${key}" to "${value}".`);
}).catch(function(error) {
alert(`Failed to set "${key}": ${JSON.stringify(error, null, 2)}.`);
});
}
window.addEventListener('load', function() {
const permission_template = (permission) =>
html` <code>${permission}</code>`;
function input_template(key, description) {
if (description.type === 'boolean') {
return html`
<label ?for=${'gs_' + key} style="grid-column: 1">${key}: </label>
<input type="checkbox" ?checked=${description.value} ?id=${'gs_' + key} style="grid-column: 2"></input>
<div style="grid-column: 3">
<button @click=${(e) => global_settings_set(key, e.srcElement.parentElement.previousElementSibling.checked)}>Set</button>
<span>${description.description}</span>
</div>
`;
} else if (description.type === 'textarea') {
return html`
<label ?for=${'gs_' + key} style="grid-column: 1">${key}: </label>
<textarea style="vertical-align: top" rows=20 cols=80 ?id=${'gs_' + key}>${description.value}</textarea>
<div style="grid-column: 3">
<button @click=${(e) => global_settings_set(key, e.srcElement.parentElement.previousElementSibling.value)}>Set</button>
<span>${description.description}</span>
</div>
`;
} else {
return html`
<label ?for=${'gs_' + key} style="grid-column: 1">${key}: </label>
<input type="text" value="${description.value}" ?id=${'gs_' + key}></input>
<div style="grid-column: 3">
<button @click=${(e) => global_settings_set(key, e.srcElement.parentElement.previousElementSibling.value)}>Set</button>
<span>${description.description}</span>
</div>
`;
}
}
const user_template = (user, permissions) => html`
<li>
<button @click=${(e) => delete_user(user)}>
Delete
</button>
${user}:
${permissions.map(x => permission_template(x))}
</li>
`;
const users_template = (users) =>
html`<h2>Users</h2>
<ul>
${Object.entries(users).map(u => user_template(u[0], u[1]))}
</ul>`;
const page_template = (data) =>
html`<div>
<h2>Global Settings</h2>
<div style="display: grid">
${Object.keys(data.settings).sort().map(x => html`${input_template(x, data.settings[x])}`)}
</div>
${users_template(data.users)}
</div>`;
render(page_template(g_data), document.body);
});