Skip to content

Commit 4eb0935

Browse files
authored
Merge pull request #2099 from maxberger/master
Misc UI Improvements
2 parents 7d07962 + 7f38950 commit 4eb0935

16 files changed

Lines changed: 180 additions & 39 deletions

integ_tests/test_basic_operation.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"""
2020

2121
import pathlib
22+
import re
2223
from typing import Any, Generator
2324

2425
import pytest
@@ -44,7 +45,7 @@ def test_index_html_loads(page: Page, radicale_server: str, config: Config) -> N
4445
console_msgs: list[str] = []
4546
page.on("console", lambda msg: console_msgs.append(msg.text))
4647
page.goto(radicale_server)
47-
expect(page).to_have_title("Radicale Web Interface")
48+
expect(page).to_have_title(re.compile("Radicale Web Interface - .* - Login"))
4849
# There should be no errors on the console, except for the expected 401/403 from auto-login check
4950
errors = [
5051
msg

integ_tests/test_sharing.py

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def test_create_and_delete_share_by_key(
5454
).to_have_count(0)
5555

5656
page.click('button[data-name="sharebytoken"]')
57-
page.click('#newshare button[data-name="submit"]')
57+
page.click('#createeditsharescene button[data-name="submit"]')
5858
expect(
5959
page.locator("tr[data-name='sharetokenrowtemplate']:not(.hidden)")
6060
).to_have_count(1)
@@ -63,14 +63,24 @@ def test_create_and_delete_share_by_key(
6363
"tr[data-name='sharetokenrowtemplate']:not(.hidden) span[data-name='ro']"
6464
)
6565
).to_be_visible()
66+
expect(
67+
page.locator(
68+
"tr[data-name='sharetokenrowtemplate']:not(.hidden) span[data-name='rw']"
69+
)
70+
).to_be_hidden()
71+
expect(
72+
page.locator(
73+
"tr[data-name='sharetokenrowtemplate']:not(.hidden) span[data-name='conversion']"
74+
)
75+
).to_be_hidden()
6676
page.click('tr:not(.hidden) button[data-name="delete"]', strict=True)
6777
page.click('#deleteconfirmationscene button[data-name="delete"]')
6878
expect(
6979
page.locator("tr[data-name='sharetokenrowtemplate']:not(.hidden)")
7080
).to_have_count(0)
7181
page.click('button[data-name="sharebytoken"]')
7282
page.click('label[for="newshare_attr_permissions_rw"]')
73-
page.click('#newshare button[data-name="submit"]')
83+
page.click('#createeditsharescene button[data-name="submit"]')
7484
expect(
7585
page.locator("tr[data-name='sharetokenrowtemplate']:not(.hidden)")
7686
).to_have_count(1)
@@ -79,6 +89,16 @@ def test_create_and_delete_share_by_key(
7989
"tr[data-name='sharetokenrowtemplate']:not(.hidden) span[data-name='rw']"
8090
)
8191
).to_be_visible()
92+
expect(
93+
page.locator(
94+
"tr[data-name='sharetokenrowtemplate']:not(.hidden) span[data-name='ro']"
95+
)
96+
).to_be_hidden()
97+
expect(
98+
page.locator(
99+
"tr[data-name='sharetokenrowtemplate']:not(.hidden) span[data-name='conversion']"
100+
)
101+
).to_be_hidden()
82102
page.click('tr:not(.hidden) button[data-name="delete"]', strict=True)
83103
page.click('#deleteconfirmationscene button[data-name="delete"]')
84104
expect(
@@ -101,7 +121,7 @@ def test_create_and_delete_share_by_map(
101121
page.click('button[data-name="sharebymap"]')
102122
page.locator('input[data-name="shareuser"]').fill("max")
103123
page.locator('input[data-name="sharehref"]').fill("1234")
104-
page.click('#newshare button[data-name="submit"]')
124+
page.click('#createeditsharescene button[data-name="submit"]')
105125
expect(
106126
page.locator("tr[data-name='sharemaprowtemplate']:not(.hidden)")
107127
).to_have_count(1)
@@ -119,7 +139,7 @@ def test_create_and_delete_share_by_map(
119139
page.click('label[for="newshare_attr_permissions_rw"]')
120140
page.locator('input[data-name="shareuser"]').fill("max")
121141
page.locator('input[data-name="sharehref"]').fill("1234")
122-
page.click('#newshare button[data-name="submit"]')
142+
page.click('#createeditsharescene button[data-name="submit"]')
123143
expect(
124144
page.locator("tr[data-name='sharemaprowtemplate']:not(.hidden)")
125145
).to_have_count(1)
@@ -184,7 +204,7 @@ def test_share_with_property_overrides(
184204
page.click('label[for="newshare_attr_color_enabled"]')
185205
page.locator('input[data-name="color_override"]').fill("#00ff00")
186206

187-
page.click('#newshare button[data-name="submit"]')
207+
page.click('#createeditsharescene button[data-name="submit"]')
188208

189209
# Verify the share was created
190210
expect(
@@ -229,7 +249,7 @@ def test_share_journal_no_overrides(
229249
expect(page.locator('input[data-name="color_override_enabled"]')).to_be_hidden()
230250

231251
# Create the share
232-
page.click('#newshare button[data-name="submit"]')
252+
page.click('#createeditsharescene button[data-name="submit"]')
233253

234254
# Verify the share was created
235255
expect(
@@ -247,7 +267,7 @@ def test_edit_share_by_token(
247267

248268
# Create RO share
249269
page.click('button[data-name="sharebytoken"]')
250-
page.click('#newshare button[data-name="submit"]')
270+
page.click('#createeditsharescene button[data-name="submit"]')
251271
expect(
252272
page.locator(
253273
"tr[data-name='sharetokenrowtemplate']:not(.hidden) span[data-name='ro']"
@@ -256,9 +276,9 @@ def test_edit_share_by_token(
256276

257277
# Edit to RW
258278
page.click('tr:not(.hidden) button[data-name="edit"]')
259-
expect(page.locator("#newshare h1")).to_have_text("Edit Share")
279+
expect(page.locator("#createeditsharescene h1")).to_have_text("Edit Share")
260280
page.click('label[for="newshare_attr_permissions_rw"]')
261-
page.click('#newshare button[data-name="submit"]')
281+
page.click('#createeditsharescene button[data-name="submit"]')
262282

263283
# Verify RW
264284
expect(
@@ -280,7 +300,7 @@ def test_edit_share_by_map(
280300
page.click('button[data-name="sharebymap"]')
281301
page.locator('input[data-name="shareuser"]').fill("max")
282302
page.locator('input[data-name="sharehref"]').fill("mapped")
283-
page.click('#newshare button[data-name="submit"]')
303+
page.click('#createeditsharescene button[data-name="submit"]')
284304
expect(
285305
page.locator(
286306
"tr[data-name='sharemaprowtemplate']:not(.hidden) span[data-name='ro']"
@@ -289,14 +309,14 @@ def test_edit_share_by_map(
289309

290310
# Edit map share
291311
page.click('tr:not(.hidden) button[data-name="edit"]')
292-
expect(page.locator("#newshare h1")).to_have_text("Edit Share")
312+
expect(page.locator("#createeditsharescene h1")).to_have_text("Edit Share")
293313
expect(page.locator('input[data-name="shareuser"]')).to_be_disabled()
294314
expect(page.locator('input[data-name="sharehref"]')).to_be_disabled()
295315

296316
# Change permissions and enabled status
297317
page.click('label[for="newshare_attr_permissions_rw"]')
298-
page.uncheck('#newshare input[data-name="enabled"]')
299-
page.click('#newshare button[data-name="submit"]')
318+
page.uncheck('#createeditsharescene input[data-name="enabled"]')
319+
page.click('#createeditsharescene button[data-name="submit"]')
300320

301321
# Verify changes
302322
expect(
@@ -307,8 +327,10 @@ def test_edit_share_by_map(
307327
# If disabled, it might not show up or show differently, but our current UI doesn't visually distinguish enabled/disabled in the list yet
308328
# Let's verify by re-opening edit scene
309329
page.click('tr:not(.hidden) button[data-name="edit"]')
310-
expect(page.locator('#newshare input[data-name="enabled"]')).not_to_be_checked()
311-
page.click('#newshare button[data-name="cancel"]')
330+
expect(
331+
page.locator('#createeditsharescene input[data-name="enabled"]')
332+
).not_to_be_checked()
333+
page.click('#createeditsharescene button[data-name="cancel"]')
312334

313335

314336
def test_share_by_map_validation(
@@ -324,21 +346,21 @@ def test_share_by_map_validation(
324346
# Try empty user
325347
page.locator('input[data-name="shareuser"]').fill("")
326348
page.locator('input[data-name="sharehref"]').fill("1234")
327-
page.click('#newshare button[data-name="submit"]')
328-
expect(page.locator('#newshare [data-name="error"]:not(.hidden)')).to_contain_text(
329-
"Share User is empty"
330-
)
349+
page.click('#createeditsharescene button[data-name="submit"]')
350+
expect(
351+
page.locator('#createeditsharescene [data-name="error"]:not(.hidden)')
352+
).to_contain_text("Share User is empty")
331353

332354
# Try logged in user
333355
page.locator('input[data-name="shareuser"]').fill("admin")
334-
page.click('#newshare button[data-name="submit"]')
335-
expect(page.locator('#newshare [data-name="error"]:not(.hidden)')).to_contain_text(
336-
"Share User cannot be admin"
337-
)
356+
page.click('#createeditsharescene button[data-name="submit"]')
357+
expect(
358+
page.locator('#createeditsharescene [data-name="error"]:not(.hidden)')
359+
).to_contain_text("Share User cannot be admin")
338360

339361
# Valid user
340362
page.locator('input[data-name="shareuser"]').fill("max")
341-
page.click('#newshare button[data-name="submit"]')
363+
page.click('#createeditsharescene button[data-name="submit"]')
342364

343365
# Verify success
344366
expect(
@@ -377,7 +399,7 @@ def test_create_and_delete_share_by_bday(
377399
expect(page.locator("input#newshare_attr_permissions_ro")).to_be_disabled()
378400
expect(page.locator("input#newshare_attr_permissions_rw")).to_be_disabled()
379401

380-
page.click('#newshare button[data-name="submit"]')
402+
page.click('#createeditsharescene button[data-name="submit"]')
381403
expect(
382404
page.locator("tr[data-name='sharemaprowtemplate']:not(.hidden)")
383405
).to_have_count(1)
@@ -388,6 +410,11 @@ def test_create_and_delete_share_by_bday(
388410
"tr[data-name='sharemaprowtemplate']:not(.hidden) span[data-name='ro']"
389411
)
390412
).to_be_hidden()
413+
expect(
414+
page.locator(
415+
"tr[data-name='sharemaprowtemplate']:not(.hidden) span[data-name='rw']"
416+
)
417+
).to_be_hidden()
391418

392419
# Instead, there should be the conversion icon
393420
expect(
@@ -438,7 +465,7 @@ def test_bday_section_hidden_for_calendar(
438465
expect(page.locator("#sharecollectionscene")).to_be_visible()
439466
page.click('button[data-name="sharebymap"]')
440467
expect(page.locator("details[data-name='conversions']")).to_be_hidden()
441-
page.click('#newshare button[data-name="cancel"]')
468+
page.click('#createeditsharescene button[data-name="cancel"]')
442469

443470

444471
def test_bday_section_visible_for_addressbook(
@@ -462,7 +489,7 @@ def test_bday_section_visible_for_addressbook(
462489
expect(page.locator("#sharecollectionscene")).to_be_visible()
463490
page.click('button[data-name="sharebymap"]')
464491
expect(page.locator("details[data-name='conversions']")).to_be_visible()
465-
page.click('#newshare button[data-name="cancel"]')
492+
page.click('#createeditsharescene button[data-name="cancel"]')
466493

467494

468495
@pytest.fixture

integ_tests/test_sharing_login.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def test_incoming_shares(page: Page, radicale_server: str, permissions: str) ->
4747
page.locator('input[data-name="sharehref"]').fill("mapped")
4848
if permissions == "rw":
4949
page.check("#newshare_attr_permissions_rw")
50-
page.click('#newshare button[data-name="submit"]')
50+
page.click('#createeditsharescene button[data-name="submit"]')
5151
expect(
5252
page.locator("tr[data-name='sharemaprowtemplate']:not(.hidden)")
5353
).to_have_count(1)

radicale/web/internal_data/index.html

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ <h1>Edit Collection</h1>
149149

150150
<section id="sharecollectionscene" class="container hidden">
151151
<h1>Sharing</h1>
152-
<p>Manage sharing for collection <span class="title" data-name="title">title</span>
153-
</p>
152+
<p>Manage sharing for collection <span class="title" data-name="title">title</span></p>
153+
<p data-name="description"></p>
154154
<div data-name="sharebytoken">
155155
<details open>
156156
<summary>By Token</summary>
@@ -257,8 +257,10 @@ <h1>Incoming Shares</h1>
257257
<span class="error hidden" data-name="error"></span>
258258
</section>
259259

260-
<section id="newshare" class="container hidden">
260+
<section id="createeditsharescene" class="container hidden">
261261
<h1>New Share</h1>
262+
<p class="title" data-name="title"></p>
263+
<p data-name="description"></p>
262264
<form>
263265
<details open data-name="sharemapfields" class="hidden">
264266
<summary>Map Target</summary>

radicale/web/internal_data/js/scenes/CollectionsScene.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,4 +312,10 @@ export class CollectionsScene {
312312
}
313313

314314
is_transient() { return false; }
315+
316+
title_object() {
317+
if (this._principal_collection.displayname && this._principal_collection.displayname.length > 0)
318+
return this._principal_collection.displayname;
319+
else return this._user;
320+
}
315321
}

radicale/web/internal_data/js/scenes/CreateEditCollectionScene.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import { create_collection, edit_collection } from "../api/api.js";
2323
import { COLOR_RE } from "../constants.js";
2424
import { Collection, CollectionType } from "../models/collection.js";
25+
import { extract_title } from "../utils/collection_utils.js";
2526
import { collectionsCache } from "../utils/collections_cache.js";
2627
import { ErrorHandler } from "../utils/error.js";
2728
import { FormValidator, validate_color, validate_href } from "../utils/form_validator.js";
@@ -224,4 +225,9 @@ export class CreateEditCollectionScene {
224225
this._create_edit_req = null;
225226
}
226227
}
228+
229+
title_object() {
230+
return extract_title(this._collection);
231+
}
232+
227233
}

radicale/web/internal_data/js/scenes/CreateEditShareScene.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import { Share, add_share_by_map, add_share_by_token, get_property_key, update_share_by_map, update_share_by_token } from "../api/sharing.js";
2323
import { CollectionType, Permission } from "../models/collection.js";
24+
import { extract_title, update_title_and_description } from "../utils/collection_utils.js";
2425
import { collectionsCache } from "../utils/collections_cache.js";
2526
import { ErrorHandler } from "../utils/error.js";
2627
import { FormValidator, validate_href, validate_non_empty, validate_not_empty_or_equals } from "../utils/form_validator.js";
@@ -47,7 +48,9 @@ export class CreateEditShareScene {
4748
this._edit = !!share;
4849
this._pathMapped = collection.href;
4950

50-
this._html_scene = get_element_by_id("newshare");
51+
this._html_scene = get_element_by_id("createeditsharescene");
52+
this._title = get_element(this._html_scene, "[data-name=title]");
53+
this._description = get_element(this._html_scene, "[data-name=description]");
5154
this._form = /** @type {HTMLFormElement} */ (get_element(this._html_scene, "form"));
5255
this._sharemapfields = get_element(this._html_scene, "[data-name=sharemapfields]");
5356
this._shareuser_input = /** @type {HTMLInputElement} */ (get_element(this._html_scene, "[data-name=shareuser]"));
@@ -404,6 +407,8 @@ export class CreateEditShareScene {
404407
this._errorHandler.clearError();
405408
}
406409
this._on_permissions_change();
410+
411+
update_title_and_description(this._collection, this._title, this._description);
407412
}
408413

409414
hide() {
@@ -416,4 +421,9 @@ export class CreateEditShareScene {
416421
}
417422

418423
is_transient() { return false; }
424+
425+
title_object() {
426+
return extract_title(this._collection);
427+
}
428+
419429
}

radicale/web/internal_data/js/scenes/DeleteConfirmationScene.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,4 +153,6 @@ export class DeleteConfirmationScene {
153153
this._delete_req = null;
154154
}
155155
}
156+
157+
title_object() { return ""; }
156158
}

radicale/web/internal_data/js/scenes/IncomingSharingScene.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import { collectionsCache } from "../utils/collections_cache.js";
2424
import { ErrorHandler } from "../utils/error.js";
2525
import { get_element, get_element_by_id } from "../utils/misc.js";
2626
import { displayPermissionsOrConversion } from "../utils/permissions.js";
27-
import { Scene, pop_scene } from "./scene_manager.js";
2827
import { UrlTextHandler } from "../utils/url_text.js";
28+
import { Scene, pop_scene } from "./scene_manager.js";
2929

3030
/**
3131
* @implements {Scene}
@@ -166,4 +166,6 @@ export class IncomingSharingScene {
166166
});
167167
this._nodes = [];
168168
}
169+
170+
title_object() { return ""; }
169171
}

radicale/web/internal_data/js/scenes/LoadingScene.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ export class LoadingScene {
3737
}
3838
release() { }
3939
is_transient() { return true; }
40+
title_object() { return "Loading..."}
4041
}

0 commit comments

Comments
 (0)