Skip to content

Commit 1a70b24

Browse files
committed
Supported editing of cache_dir from user profile page
1 parent 078321a commit 1a70b24

File tree

3 files changed

+131
-14
lines changed

3 files changed

+131
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# Unreleased
44

5+
* Supported editing of cache_dir from user profile page (\#365).
56
* Added experimental workflow page with job monitoring (\#363).
67

78
# 0.7.0

src/routes/profile/+page.svelte

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,140 @@
11
<script>
22
import { page } from '$app/stores';
3+
import { displayStandardErrorAlert, getValidationMessagesMap } from '$lib/common/errors';
34
import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
45
56
/** @type {import('$lib/types').User} */
67
$: user = $page.data.userInfo;
8+
9+
/** @type {import('$lib/components/common/StandardErrorAlert.svelte').default|undefined} */
10+
let errorAlert = undefined;
11+
12+
let editCacheDir = false;
13+
let cacheDir = '';
14+
let cacheDirError = '';
15+
16+
function toggleEditCacheDir() {
17+
if (editCacheDir) {
18+
editCacheDir = false;
19+
cacheDirError = '';
20+
} else {
21+
editCacheDir = true;
22+
cacheDir = user.cache_dir || '';
23+
}
24+
}
25+
26+
async function saveCacheDir() {
27+
if (errorAlert) {
28+
errorAlert.hide();
29+
}
30+
const headers = new Headers();
31+
headers.set('Content-Type', 'application/json');
32+
const response = await fetch(`/api/auth/current-user`, {
33+
method: 'PATCH',
34+
credentials: 'include',
35+
headers,
36+
body: JSON.stringify({ cache_dir: cacheDir })
37+
});
38+
if (response.ok) {
39+
user.cache_dir = cacheDir;
40+
editCacheDir = false;
41+
} else {
42+
const result = await response.json();
43+
const errorMap = getValidationMessagesMap(result, response.status);
44+
if (errorMap && Object.keys(errorMap).length === 1 && 'cache_dir' in errorMap) {
45+
cacheDirError = errorMap['cache_dir'];
46+
} else {
47+
errorAlert = displayStandardErrorAlert(result, 'profileUpdate-error');
48+
}
49+
}
50+
}
751
</script>
852

953
<h3>My profile</h3>
1054

1155
<div class="row mt-4">
12-
<div class="col-md-8 col-lg-6">
56+
<div class="col-lg-10 col-xl-8">
1357
<table class="table">
58+
<colgroup>
59+
<col width="170" />
60+
<col width="auto" />
61+
<col width="auto" />
62+
</colgroup>
1463
<tbody>
1564
<tr>
1665
<th>User ID</th>
1766
<td>{user.id}</td>
67+
<td />
1868
</tr>
1969
<tr>
2070
<th>E-mail</th>
2171
<td>{user.email}</td>
72+
<td />
2273
</tr>
2374
<tr>
2475
<th>Username</th>
2576
<td>{user.username || '-'}</td>
77+
<td />
2678
</tr>
2779
<tr>
2880
<th>Active</th>
2981
<td><BooleanIcon value={user.is_active} /></td>
82+
<td />
3083
</tr>
3184
<tr>
3285
<th>Superuser</th>
3386
<td><BooleanIcon value={user.is_superuser} /></td>
87+
<td />
3488
</tr>
3589
<tr>
3690
<th>Verified</th>
3791
<td><BooleanIcon value={user.is_verified} /></td>
92+
<td />
3893
</tr>
3994
<tr>
4095
<th>Slurm user</th>
4196
<td>{user.slurm_user || '-'}</td>
97+
<td />
4298
</tr>
4399
<tr>
44100
<th>Cache dir</th>
45-
<td>{user.cache_dir || '-'}</td>
101+
<td>
102+
{#if editCacheDir}
103+
<div class="input-group" class:has-validation={cacheDirError}>
104+
<input
105+
type="text"
106+
class="form-control"
107+
id="cache-dir"
108+
bind:value={cacheDir}
109+
class:is-invalid={cacheDirError}
110+
on:keydown={(e) => {
111+
if (e.key === 'Enter') {
112+
saveCacheDir();
113+
}
114+
}}
115+
/>
116+
<button class="btn btn-outline-secondary" on:click={toggleEditCacheDir}>
117+
<i class="bi bi-arrow-counterclockwise" /> Undo
118+
</button>
119+
<button class="btn btn-primary" on:click={saveCacheDir}> Save </button>
120+
{#if cacheDirError}
121+
<div class="invalid-feedback">{cacheDirError}</div>
122+
{/if}
123+
</div>
124+
{:else}
125+
{user.cache_dir || '-'}
126+
{/if}
127+
</td>
128+
<td>
129+
{#if !editCacheDir}
130+
<button class="btn btn-primary pt-0 pb-0 float-end" on:click={toggleEditCacheDir}>
131+
<i class="bi bi-pencil" /> Edit
132+
</button>
133+
{/if}
134+
</td>
46135
</tr>
47136
</tbody>
48137
</table>
138+
<div id="profileUpdate-error" />
49139
</div>
50140
</div>

tests/profile.spec.js

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,45 @@
11
import { expect, test } from './base_test.js';
22

33
test('User profile', async ({ page }) => {
4-
await page.goto('/');
5-
await page.getByRole('button', { name: '[email protected]' }).click();
6-
await page.getByRole('link', { name: 'My profile' }).click();
7-
await page.waitForURL('/profile');
4+
await test.step('Open user profile page', async () => {
5+
await page.goto('/');
6+
await page.getByRole('button', { name: '[email protected]' }).click();
7+
await page.getByRole('link', { name: 'My profile' }).click();
8+
await page.waitForURL('/profile');
89

9-
const cells = await page.locator('table td').all();
10-
expect(await cells[0].innerText()).toEqual('1');
11-
expect(await cells[1].innerText()).toEqual('[email protected]');
12-
expect(await cells[2].innerText()).toEqual('admin');
13-
verifyChecked(cells, 3, true);
14-
verifyChecked(cells, 4, true);
15-
expect(await cells[6].innerText()).toEqual('-');
16-
expect(await cells[7].innerText()).toEqual('-');
10+
const cells = await page.locator('table td').all();
11+
expect(await cells[0].innerText()).toEqual('1');
12+
expect(await cells[2].innerText()).toEqual('[email protected]');
13+
expect(await cells[4].innerText()).toEqual('admin');
14+
verifyChecked(cells, 6, true);
15+
verifyChecked(cells, 8, true);
16+
expect(await cells[12].innerText()).toEqual('-');
17+
});
18+
19+
await test.step('Save cache dir using button', async () => {
20+
await page.getByRole('button', { name: 'Edit' }).click();
21+
await page.getByRole('textbox').waitFor();
22+
await page.getByRole('textbox').fill('');
23+
await page.getByRole('button', { name: 'Save' }).click();
24+
await page.getByText("String attribute 'cache_dir' cannot be empty").waitFor();
25+
await page.getByRole('textbox').fill('/tmp/foo1');
26+
await page.getByRole('button', { name: 'Save' }).click();
27+
await page.getByRole('button', { name: 'Edit' }).waitFor();
28+
});
29+
30+
await test.step('Save cache dir using enter', async () => {
31+
await page.getByRole('button', { name: 'Edit' }).click();
32+
await page.getByRole('textbox').waitFor();
33+
await page.getByRole('textbox').fill('/tmp/foo2\n');
34+
await page.getByRole('button', { name: 'Save' }).click();
35+
await page.getByRole('button', { name: 'Edit' }).waitFor();
36+
});
37+
38+
await test.step('Verify cache dir updated', async () => {
39+
await page.reload();
40+
const cells = await page.locator('table td').all();
41+
expect(await cells[14].innerText()).toEqual('/tmp/foo2');
42+
});
1743
});
1844

1945
/**

0 commit comments

Comments
 (0)