diff --git a/static/manage-edit-group.html b/static/manage-edit-group.html
new file mode 100644
index 0000000..aa8142c
--- /dev/null
+++ b/static/manage-edit-group.html
@@ -0,0 +1,28 @@
+
+
+
+ Edit group
+
+
+
+
+
+
+
+
+ Edit group
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/manage-edit-group.js b/static/manage-edit-group.js
new file mode 100644
index 0000000..2cadb71
--- /dev/null
+++ b/static/manage-edit-group.js
@@ -0,0 +1,41 @@
+async function doit(group) {
+ let de = await getGroup(group);
+ let d = document.getElementById('description');
+ for(let k in de.data) {
+ let p = document.createElement('p');
+ p.textContent = `${k}: ${de.data[k]}`;
+ d.appendChild(p);
+ }
+
+ let users = await listUsers(group);
+ let u = document.getElementById('users');
+ for(let i = 0; i < users.length; i++) {
+ let username = users[i];
+ let ut = await getUser(group, username, false);
+ let p = document.createElement('p');
+ p.textContent = `${username} ${ut.data.permissions}`
+ u.appendChild(p);
+ }
+
+ let tokens = await listTokens(group);
+ let t = document.getElementById('tokens');
+ for(let i = 0; i < tokens.length; i++) {
+ let token = tokens[i];
+ let tt = await getToken(group, token);
+ let p = document.createElement('p');
+ p.textContent = `${token} ${tt.expires || '(no expiration)'}`
+ t.appendChild(p);
+ }
+}
+
+
+function displayError(message) {
+ document.getElementById('errormessage').textContent = (message || '');
+}
+
+let parms = new URLSearchParams(window.location.search);
+if(!parms.has('group')) {
+ displayError('Unknown group');
+} else {
+ doit(parms.get('group')).catch(displayError);
+}
diff --git a/static/manage-groups.html b/static/manage-groups.html
new file mode 100644
index 0000000..fb149ca
--- /dev/null
+++ b/static/manage-groups.html
@@ -0,0 +1,24 @@
+
+
+
+ Manage groups
+
+
+
+
+
+
+
+
+ Manage groups
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/manage-groups.js b/static/manage-groups.js
new file mode 100644
index 0000000..80e754e
--- /dev/null
+++ b/static/manage-groups.js
@@ -0,0 +1,46 @@
+async function doit() {
+ let groups = await listGroups();
+ let s = document.getElementById('groups');
+ for(let i = 0; i < groups.length; i++) {
+ let group = groups[i];
+ let e = document.createElement('button');
+ e.textContent = "Edit";
+ e.onclick = e => {
+ e.preventDefault();
+ editHandler(group);
+ }
+ let d = document.createElement('button');
+ d.textContent = "Delete";
+ d.onclick = e => {
+ e.preventDefault();
+ deleteHandler(group);
+ }
+ let p = document.createElement('p');
+ p.textContent = group;
+ p.appendChild(e);
+ p.appendChild(d);
+ s.appendChild(p);
+ }
+}
+
+function editHandler(group) {
+ document.location.href = `/manage-edit-group.html?group=${encodeURI(group)}`
+}
+
+async function deleteHandler(group) {
+ let ok = confirm(`Do you want to delete group ${group}?`);
+ if(ok) {
+ try {
+ await deleteGroup(group);
+ location.reload();
+ } catch(e) {
+ displayError(e);
+ }
+ }
+}
+
+function displayError(message) {
+ document.getElementById('errormessage').textContent = (message || '');
+}
+
+doit().catch(displayError);
diff --git a/static/tsconfig.json b/static/tsconfig.json
index fdfcc72..552d5df 100644
--- a/static/tsconfig.json
+++ b/static/tsconfig.json
@@ -15,6 +15,8 @@
"files": [
"protocol.js",
"galene.js",
- "management.js"
+ "management.js",
+ "manage-groups.js",
+ "manage-edit-group.js"
]
}