Merge pull request #2050 from maxberger/master

UI: Remove dedicated bday, add support for conversion
This commit is contained in:
Peter Bieringer
2026-03-28 07:38:44 +01:00
committed by GitHub
8 changed files with 196 additions and 265 deletions

View File

@@ -364,30 +364,37 @@ def test_create_and_delete_share_by_bday(
page.click('article:not(.hidden) a[data-name="share"]', force=True, strict=True)
expect(
page.locator("tr[data-name='sharebdayrowtemplate']:not(.hidden)")
page.locator("tr[data-name='sharemaprowtemplate']:not(.hidden)")
).to_have_count(0)
page.click('button[data-name="sharebybday"]')
page.click('button[data-name="sharebymap"]')
page.click('label[for="newshare_conv_bday"]')
# verify user is auto-filled with current user (admin)
expect(page.locator('input[data-name="shareuser"]')).to_have_value("admin")
page.locator('input[data-name="sharehref"]').fill("bdaymapped")
# share to self (admin), which is allowed for conversions
page.locator('input[data-name="shareuser"]').fill("admin")
# verify that the permissions section is hidden entirely
expect(page.locator("input#newshare_attr_permissions_ro")).to_be_hidden()
expect(page.locator("input#newshare_attr_permissions_rw")).to_be_hidden()
# verify that the permissions section is disabled
expect(page.locator("input#newshare_attr_permissions_ro")).to_be_disabled()
expect(page.locator("input#newshare_attr_permissions_rw")).to_be_disabled()
page.click('#newshare button[data-name="submit"]')
expect(
page.locator("tr[data-name='sharebdayrowtemplate']:not(.hidden)")
page.locator("tr[data-name='sharemaprowtemplate']:not(.hidden)")
).to_have_count(1)
# verify no permissions pill in the bday row
expect(
page.locator(
"tr[data-name='sharebdayrowtemplate']:not(.hidden) span[data-name='ro']"
"tr[data-name='sharemaprowtemplate']:not(.hidden) span[data-name='ro']"
)
).to_have_count(0)
).to_be_hidden()
# Instead, there should be the conversion icon
expect(
page.locator(
"tr[data-name='sharemaprowtemplate']:not(.hidden) span[data-name='conversion']"
)
).to_have_count(1)
# Close the share scene and verify the virtual bday calendar is now in the collections list
page.click('#sharecollectionscene button[data-name="cancel"]')
@@ -401,12 +408,12 @@ def test_create_and_delete_share_by_bday(
page.hover("article:not(.hidden) >> nth=0")
page.click('article:not(.hidden) >> nth=0 >> a[data-name="share"]', force=True)
page.click(
"tr[data-name='sharebdayrowtemplate']:not(.hidden) button[data-name='delete']",
"tr[data-name='sharemaprowtemplate']:not(.hidden) button[data-name='delete']",
strict=True,
)
page.click('#deleteconfirmationscene button[data-name="delete"]')
expect(
page.locator("tr[data-name='sharebdayrowtemplate']:not(.hidden)")
page.locator("tr[data-name='sharemaprowtemplate']:not(.hidden)")
).to_have_count(0)
@@ -429,8 +436,9 @@ def test_bday_section_hidden_for_calendar(
page.click('article:not(.hidden) a[data-name="share"]', force=True, strict=True)
expect(page.locator("#sharecollectionscene")).to_be_visible()
expect(page.locator("div[data-name='sharebybday']")).to_be_hidden()
page.click('#sharecollectionscene button[data-name="cancel"]')
page.click('button[data-name="sharebymap"]')
expect(page.locator("details[data-name='conversions']")).to_be_hidden()
page.click('#newshare button[data-name="cancel"]')
def test_bday_section_visible_for_addressbook(
@@ -452,5 +460,6 @@ def test_bday_section_visible_for_addressbook(
page.click('article:not(.hidden) a[data-name="share"]', force=True, strict=True)
expect(page.locator("#sharecollectionscene")).to_be_visible()
expect(page.locator("div[data-name='sharebybday']")).to_be_visible()
page.click('#sharecollectionscene button[data-name="cancel"]')
page.click('button[data-name="sharebymap"]')
expect(page.locator("details[data-name='conversions']")).to_be_visible()
page.click('#newshare button[data-name="cancel"]')

View File

@@ -158,7 +158,7 @@
<button type="button" class="blue inline" data-name="edit"><img src="css/icons/edit.svg"
class="small_icon" alt="Edit"></button>
</td>
<td><span class="pill" data-name="rw">rw</span><span class="pill" data-name="ro">ro</span></td>
<td><span class="pill" data-name="rw">rw</span><span class="pill" data-name="ro">ro</span><span data-name="conversion"></span></td>
<td><input type="text" data-name="pathortoken" value="" readonly="" class="inline selectall"></td>
<td>
<button type="button" class="red inline" data-name="delete"><img src="css/icons/delete.svg"
@@ -184,7 +184,7 @@
<button type="button" class="blue inline" data-name="edit"><img src="css/icons/edit.svg"
class="small_icon" alt="Edit"></button>
</td>
<td><span class="pill" data-name="rw">rw</span><span class="pill" data-name="ro">ro</span></td>
<td><span class="pill" data-name="rw">rw</span><span class="pill" data-name="ro">ro</span><span data-name="conversion"></span></td>
<td><input type="text" data-name="pathortoken" value="" readonly="" class="inline selectall"></td>
<td>
<button type="button" class="red inline" data-name="delete"><img src="css/icons/delete.svg"
@@ -202,33 +202,6 @@
</table>
</details>
</div>
<div data-name="sharebybday">
<details open>
<summary>shared as bday calendar</summary>
<table>
<tbody>
<tr data-name="sharebdayrowtemplate" class="hidden">
<td>
<button type="button" class="blue inline" data-name="edit"><img src="css/icons/edit.svg"
class="small_icon" alt="Edit"></button>
</td>
<td><input type="text" data-name="pathortoken" value="" readonly="" class="inline selectall"></td>
<td>
<button type="button" class="red inline" data-name="delete"><img src="css/icons/delete.svg"
class="small_icon" alt="Delete"></button>
</td>
</tr>
<tr>
<td>
<button type="button" class="blue inline" data-name="sharebybday">
<img src="css/icons/new.svg" class="small_icon" alt="New Share as Bday Calendar">
</button>
</td>
</tr>
</tbody>
</table>
</details>
</div>
<form>
<button type="button" class="green" data-name="cancel">Close</button>
</form>
@@ -253,7 +226,7 @@
<td><input type="text" data-name="pathortoken" value="" readonly="" class="inline selectall"></td>
<td data-name="owner"></td>
<td data-name="permissions"><span class="pill" data-name="rw">rw</span><span class="pill"
data-name="ro">ro</span></td>
data-name="ro">ro</span><span data-name="conversion"></span></td>
<td><input type="checkbox" data-name="enabled"></td>
<td><input type="checkbox" data-name="shown"></td>
</tr>
@@ -285,11 +258,17 @@
</details>
<details open>
<summary>Permissions</summary>
<input type="radio" data-name="permissions" checked="true" id="newshare_attr_permissions_ro"
<input type="radio" data-name="permissions" checked id="newshare_attr_permissions_ro"
name="newshare_permissions"><label for="newshare_attr_permissions_ro">Readonly</label>
<input type="radio" data-name="permissions" checked="false" id="newshare_attr_permissions_rw"
<input type="radio" data-name="permissions" id="newshare_attr_permissions_rw"
name="newshare_permissions" /><label for="newshare_attr_permissions_rw">Read/Write</label>
</details>
<details data-name="conversions" class="hidden">
<summary>Conversions</summary>
<div data-name="conversions_container">
<!-- Dynamic radio buttons will be inserted here -->
</div>
</details>
<details data-name="properties_override">
<summary>Properties override</summary>
<div class="property-override">

View File

@@ -28,8 +28,7 @@ import { create_request, to_error_message } from "./common.js";
* @property {boolean} [PermittedCreateCollectionByMap]
* @property {boolean} [FeatureEnabledCollectionByToken]
* @property {boolean} [PermittedCreateCollectionByToken]
* @property {boolean} [FeatureEnabledCollectionByBday]
* @property {boolean} [PermittedCreateCollectionByBday]
* @property {Array<string>} [SupportedConversions]
*/
/**
@@ -133,13 +132,12 @@ export function discover_server_features(user, password, callback) {
* @property {string} [Permissions]
* @property {?boolean} [EnabledByOwner]
* @property {?boolean} [EnabledByUser]
* @property {?boolean} [Enabled]
* @property {?boolean} [HiddenByOwner]
* @property {?boolean} [HiddenByUser]
* @property {?boolean} [Hidden]
* @property {number} [TimestampCreated]
* @property {number} [TimestampUpdated]
* @property {Object<String, String>} [Properties]
* @property {string} [Conversion]
*/
@@ -154,13 +152,14 @@ export class Share {
/** @type {string} */ this.Owner = data.Owner || "";
/** @type {string} */ this.User = data.User || "";
/** @type {string} */ this.Permissions = data.Permissions || "r";
/** @type {?boolean} */ this.EnabledByOwner = data.EnabledByOwner ?? data.Enabled ?? false;
/** @type {?boolean} */ this.EnabledByUser = data.EnabledByUser ?? data.Enabled ?? null;
/** @type {?boolean} */ this.HiddenByOwner = data.HiddenByOwner ?? data.Hidden ?? false;
/** @type {?boolean} */ this.HiddenByUser = data.HiddenByUser ?? data.Hidden ?? null;
/** @type {?boolean} */ this.EnabledByOwner = data.EnabledByOwner ?? null;
/** @type {?boolean} */ this.EnabledByUser = data.EnabledByUser ?? null;
/** @type {?boolean} */ this.HiddenByOwner = data.HiddenByOwner ?? null;
/** @type {?boolean} */ this.HiddenByUser = data.HiddenByUser ?? null;
/** @type {number} */ this.TimestampCreated = data.TimestampCreated || 0;
/** @type {number} */ this.TimestampUpdated = data.TimestampUpdated || 0;
/** @type {Object<String, String>} */ this.Properties = data.Properties || {};
/** @type {string} */ this.Conversion = data.Conversion || "";
}
}
@@ -247,6 +246,7 @@ export function add_share_by_token(
Enabled: share.EnabledByOwner,
Hidden: share.HiddenByOwner,
Properties: share.Properties,
Conversion: share.Conversion,
},
function (response) {
let json_response = JSON.parse(response);
@@ -287,6 +287,7 @@ export function add_share_by_map(
Properties: share.Properties,
User: share.User,
PathOrToken: share.PathOrToken,
Conversion: share.Conversion,
},
function (response) {
let json_response = JSON.parse(response);
@@ -388,6 +389,7 @@ export function update_share_by_token(
Enabled: share.EnabledByOwner,
Hidden: share.HiddenByOwner,
Properties: share.Properties,
Conversion: share.Conversion,
},
function (response) {
let json_response = JSON.parse(response);
@@ -428,6 +430,7 @@ export function update_share_by_map(
Enabled: share.EnabledByOwner,
Hidden: share.HiddenByOwner,
Properties: share.Properties,
Conversion: share.Conversion,
},
function (response) {
let json_response = JSON.parse(response);
@@ -482,114 +485,3 @@ export function update_incoming_share(
);
}
/**
* @param {string} user
* @param {?string} password
* @param {Share} share
* @param {function(?string):void} callback
*/
export function add_share_by_bday(
user,
password,
share,
callback,
) {
call_sharing_api(
user,
password,
"bday/create",
{
PathMapped: share.PathMapped,
Permissions: share.Permissions,
Enabled: share.EnabledByOwner,
Hidden: share.HiddenByOwner,
Properties: share.Properties,
User: share.User,
PathOrToken: share.PathOrToken,
},
function (response) {
let json_response = JSON.parse(response);
if (json_response["Status"] !== "success") {
callback(json_response["Status"] || "Unknown error");
} else {
callback(null);
}
},
null,
function (error) {
callback(error);
}
);
}
/**
* @param {string} user
* @param {?string} password
* @param {Share} share
* @param {function(?string):void} callback
*/
export function delete_share_by_bday(
user,
password,
share,
callback,
) {
call_sharing_api(
user,
password,
"bday/delete",
{ PathOrToken: share.PathOrToken },
function (response) {
let json_response = JSON.parse(response);
if (json_response["Status"] !== "success") {
callback(json_response["Status"] || "Unknown error");
} else {
callback(null);
}
},
null,
function (error) {
callback(error);
}
);
}
/**
* @param {string} user
* @param {?string} password
* @param {Share} share
* @param {function(?string):void} callback
*/
export function update_share_by_bday(
user,
password,
share,
callback,
) {
call_sharing_api(
user,
password,
"bday/update",
{
PathOrToken: share.PathOrToken,
PathMapped: share.PathMapped,
User: share.User,
Permissions: share.Permissions,
Enabled: share.EnabledByOwner,
Hidden: share.HiddenByOwner,
Properties: share.Properties,
},
function (response) {
let json_response = JSON.parse(response);
if (json_response["Status"] !== "success") {
callback(json_response["Status"] || "Unknown error");
} else {
callback(null);
}
},
null,
function (error) {
callback(error);
}
);
}

View File

@@ -183,6 +183,7 @@ export class CollectionsScene {
let share_info = get_element(node, "[data-name=shared-by]");
let transformed_from = get_element(node, "[data-name=transformed-from]");
let share = (shares || []).find(
// TODO: Eventually remove the check for "bday"
s => (s.ShareType === "map" || s.ShareType === "bday") &&
(s.PathOrToken || "").replace(/\/+$/, "") === (collection.href || "").replace(/\/+$/, ""));
if (share) {

View File

@@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Share, add_share_by_bday, add_share_by_map, add_share_by_token, get_property_key, update_share_by_bday, update_share_by_map, update_share_by_token } from "../api/sharing.js";
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";
import { CollectionType } from "../models/collection.js";
import { collectionsCache } from "../utils/collections_cache.js";
import { ErrorHandler } from "../utils/error.js";
@@ -51,6 +51,8 @@ export class CreateEditShareScene {
/** @type {HTMLInputElement} */ let hidden_checkbox = /** @type {HTMLInputElement} */ (get_element(html_scene, "[data-name=hidden]"));
let permissions_ro_radio = /** @type {HTMLInputElement} */ (get_element_by_id("newshare_attr_permissions_ro"));
let permissions_rw_radio = /** @type {HTMLInputElement} */ (get_element_by_id("newshare_attr_permissions_rw"));
/** @type {HTMLDetailsElement} */ let conversions_details = /** @type {HTMLDetailsElement} */ (get_element(html_scene, "[data-name=conversions]"));
/** @type {HTMLElement} */ let conversions_container = get_element(html_scene, "[data-name=conversions_container]");
/** @type {HTMLDetailsElement} */ let properties_fieldset = /** @type {HTMLDetailsElement} */ (get_element(html_scene, "[data-name=properties_override]"));
/** @type {HTMLInputElement} */ let displayname_override_enabled = /** @type {HTMLInputElement} */ (get_element(html_scene, "[data-name=displayname_override_enabled]"));
@@ -67,12 +69,14 @@ export class CreateEditShareScene {
let errorHandler = new ErrorHandler(error_form);
let map_validator = new FormValidator(errorHandler);
if (shareType === "bday") {
// bday can share to self, so just validate non-empty
map_validator.addValidator(shareuser_input, validate_non_empty(shareuser_input, "Share User"));
} else {
map_validator.addValidator(shareuser_input, validate_not_empty_or_equals(shareuser_input, user, "Share User"));
}
map_validator.addValidator(shareuser_input, function () {
let conversion = get_selected_conversion();
if (conversion === "bday") {
return validate_non_empty(shareuser_input, "Share User")();
} else {
return validate_not_empty_or_equals(shareuser_input, user, "Share User")();
}
});
map_validator.addValidator(sharehref_input, validate_href(sharehref_input, "Share Href"));
sharehref_input.addEventListener("input", onCleanHREFinput);
@@ -86,7 +90,29 @@ export class CreateEditShareScene {
color_override_enabled.onchange = function () {
color_override_input.disabled = !color_override_enabled.checked;
};
function get_selected_conversion() {
/** @type {HTMLInputElement | null} */
let checked = conversions_container.querySelector("input[name=conversion]:checked");
return checked ? checked.value : "none";
}
function on_conversion_change() {
let conversion = get_selected_conversion();
if (conversion === "bday") {
permissions_ro_radio.checked = true;
permissions_rw_radio.checked = false;
permissions_ro_radio.disabled = true;
permissions_rw_radio.disabled = true;
enabled_checkbox.checked = true;
hidden_checkbox.checked = false;
} else {
permissions_ro_radio.disabled = false;
permissions_rw_radio.disabled = false;
}
if (shareType === "map") {
map_validator.validate();
}
}
function oncancel() {
try {
@@ -99,14 +125,17 @@ export class CreateEditShareScene {
function onsubmit() {
try {
if (shareType === "map" || shareType === "bday") {
if (shareType === "map") {
if (!map_validator.validate()) {
return false;
}
}
let enabled_by_owner = (shareType === "bday" && shareuser_input.value === user) ? true : enabled_checkbox.checked;
let hidden_by_owner = (shareType === "bday" && shareuser_input.value === user) ? false : hidden_checkbox.checked;
let permissions = permissions_rw_radio.checked ? "rw" : "r";
let conversion = get_selected_conversion();
let is_birthday = conversion === "bday";
let enabled_by_owner = is_birthday ? true : enabled_checkbox.checked;
let hidden_by_owner = is_birthday ? false : hidden_checkbox.checked;
let permissions = is_birthday ? "r" : (permissions_rw_radio.checked ? "rw" : "r");
/** @type {string} */ let conversion_value = conversion;
/** @type {Object<string, string>} */ let properties = {};
if (displayname_override_enabled.checked) {
@@ -129,9 +158,9 @@ export class CreateEditShareScene {
if (error) {
errorHandler.setError(error);
} else {
// For bday shares to the current user, invalidate the
// On any share-to-self (currently only bday conversion), invalidate the
// collections cache so the virtual calendar appears immediately.
if (shareType === "bday" && new_share.User === user) {
if (shareuser_input.value === user) {
collectionsCache.invalidate();
}
pop_scene();
@@ -148,22 +177,19 @@ export class CreateEditShareScene {
HiddenByUser: (edit && share) ? share.HiddenByUser : null,
Properties: properties,
User: (edit && share) ? share.User : shareuser_input.value,
PathOrToken: (edit && share) ? share.PathOrToken : ((shareType === "map" || shareType === "bday") ? "/" + shareuser_input.value + "/" + sharehref_input.value + "/" : ""),
PathOrToken: (edit && share) ? share.PathOrToken : (shareType === "map" ? "/" + shareuser_input.value + "/" + sharehref_input.value + "/" : ""),
Conversion: conversion_value,
});
if (edit) {
if (shareType === "map") {
update_share_by_map(user, password, new_share, callback);
} else if (shareType === "bday") {
update_share_by_bday(user, password, new_share, callback);
} else {
update_share_by_token(user, password, new_share, callback);
}
} else {
if (shareType === "map") {
add_share_by_map(user, password, new_share, callback);
} else if (shareType === "bday") {
add_share_by_bday(user, password, new_share, callback);
} else {
add_share_by_token(user, password, new_share, callback);
}
@@ -191,25 +217,52 @@ export class CreateEditShareScene {
title.textContent = edit ? "Edit Share" : "New Share";
submit_btn.textContent = edit ? "Save" : "Create";
shareuser_input.value = (edit && share) ? share.User : (shareType === "bday" ? user : "");
shareuser_input.value = (edit && share) ? share.User : "";
shareuser_input.disabled = edit;
enabled_checkbox.checked = (edit && share && share.EnabledByOwner !== null) ? share.EnabledByOwner : true;
hidden_checkbox.checked = (edit && share && share.HiddenByOwner !== null) ? share.HiddenByOwner : false;
if (shareType === "bday") {
// bday is always read-only; hide the permissions section entirely
permissions_ro_radio.checked = true;
permissions_rw_radio.checked = false;
permissions_ro_radio.disabled = true;
permissions_rw_radio.disabled = true;
permissions_ro_radio.closest("details")?.classList.add("hidden");
} else {
permissions_ro_radio.closest("details")?.classList.remove("hidden");
permissions_ro_radio.disabled = false;
permissions_rw_radio.disabled = false;
permissions_ro_radio.checked = (edit && share) ? share.Permissions.toLowerCase() === "r" : true;
permissions_rw_radio.checked = (edit && share) ? share.Permissions.toLowerCase() === "rw" : false;
}
let initial_conversion = (edit && share && share.Conversion) ? share.Conversion : "none";
collectionsCache.getServerFeatures(user, password, errorHandler.setError, (features) => {
conversions_container.innerHTML = "";
let supported = (features.sharing && features.sharing.SupportedConversions) || [];
if (supported.length > 0) {
let options = ["none", ...supported.filter(opt => opt !== "none")];
options.forEach(opt => {
let id = "newshare_conv_" + opt;
let radio = document.createElement("input");
radio.type = "radio";
radio.name = "conversion";
radio.value = opt;
radio.id = id;
radio.checked = (opt === initial_conversion);
radio.onchange = on_conversion_change;
let label = document.createElement("label");
label.htmlFor = id;
if (opt === "bday") {
label.textContent = "Birthday";
} else {
label.textContent = opt.charAt(0).toUpperCase() + opt.slice(1);
}
conversions_container.appendChild(radio);
conversions_container.appendChild(label);
});
let is_addressbook = collection.type === CollectionType.ADDRESSBOOK;
if (is_addressbook) {
conversions_details.classList.remove("hidden");
conversions_details.open = true;
} else {
conversions_details.classList.add("hidden");
}
} else {
conversions_details.classList.add("hidden");
}
on_conversion_change();
});
let displayname = collection.displayname || "";
let description = collection.description || "";
@@ -251,29 +304,44 @@ export class CreateEditShareScene {
color_override_input.value = color;
color_override_input.disabled = !color_override_enabled_value;
let is_calendar = CollectionType.is_subset(CollectionType.CALENDAR, collection.type);
let is_addressbook = collection.type === CollectionType.ADDRESSBOOK;
properties_fieldset.classList.remove("hidden");
if (displayname_override_enabled_value || description_override_enabled_value || color_override_enabled_value) {
properties_fieldset.open = true;
}
if (is_calendar || is_addressbook) {
if (description_override_enabled.parentElement) {
description_override_enabled.parentElement.classList.remove("hidden");
}
if (color_override_enabled.parentElement) {
color_override_enabled.parentElement.classList.remove("hidden");
let displayname_key = get_property_key(collection.type, "DISPLAYNAME");
if (!displayname_key) {
if (displayname_override_enabled.parentElement) {
displayname_override_enabled.parentElement.classList.add("hidden");
}
} else {
if (displayname_override_enabled.parentElement) {
displayname_override_enabled.parentElement.classList.remove("hidden");
}
}
let description_key = get_property_key(collection.type, "DESCRIPTION");
if (!description_key) {
if (description_override_enabled.parentElement) {
description_override_enabled.parentElement.classList.add("hidden");
}
if (color_override_enabled.parentElement) {
color_override_enabled.parentElement.classList.add("hidden");
} else {
if (description_override_enabled.parentElement) {
description_override_enabled.parentElement.classList.remove("hidden");
}
}
if (shareType === "map" || shareType === "bday") {
let color_key = get_property_key(collection.type, "COLOR");
if (!color_key) {
if (color_override_enabled.parentElement) {
color_override_enabled.parentElement.classList.add("hidden");
}
} else {
if (color_override_enabled.parentElement) {
color_override_enabled.parentElement.classList.remove("hidden");
}
}
if (shareType === "map") {
if (edit && share) {
sharehref_input.value = share.PathOrToken.split("/").filter(Boolean).pop() || "";
} else {

View File

@@ -23,7 +23,7 @@ import { update_incoming_share } from "../api/sharing.js";
import { collectionsCache } from "../utils/collections_cache.js";
import { ErrorHandler } from "../utils/error.js";
import { get_element, get_element_by_id } from "../utils/misc.js";
import { displayPermissions } from "../utils/permissions.js";
import { displayPermissionsOrConversion } from "../utils/permissions.js";
import { Scene, pop_scene } from "./scene_manager.js";
/**
@@ -99,6 +99,7 @@ export class IncomingSharingScene {
let prefix = "/" + user + "/";
let filtered_shares = shares.filter(
// TODO: Eventually remove bday
share => (share.ShareType === "map" || share.ShareType === "bday")
&& share.PathOrToken.startsWith(prefix));
@@ -127,7 +128,7 @@ export class IncomingSharingScene {
pathortoken.value = displayPath;
owner_td.textContent = share.Owner;
displayPermissions(share.Permissions, permissions_td);
displayPermissionsOrConversion(share.Conversion, share.Permissions, permissions_td);
let enabled = share.EnabledByUser !== null ? share.EnabledByUser : true;
let shown = share.HiddenByUser !== null ? !share.HiddenByUser : true;

View File

@@ -20,16 +20,15 @@
*/
import {
delete_share_by_bday,
delete_share_by_map,
delete_share_by_token,
reload_sharing_list,
} from "../api/sharing.js";
import { Collection, CollectionType } from "../models/collection.js";
import { Collection } from "../models/collection.js";
import { collectionsCache } from "../utils/collections_cache.js";
import { ErrorHandler } from "../utils/error.js";
import { get_element, get_element_by_id } from "../utils/misc.js";
import { displayPermissions } from "../utils/permissions.js";
import { displayPermissionsOrConversion } from "../utils/permissions.js";
import { CreateEditShareScene } from "./CreateEditShareScene.js";
import { DeleteConfirmationScene } from "./DeleteConfirmationScene.js";
import { Scene, pop_scene, push_scene } from "./scene_manager.js";
@@ -50,10 +49,8 @@ export class ShareCollectionScene {
/** @type {HTMLElement} */ let cancel_btn = get_element(html_scene, "[data-name=cancel]");
/** @type {HTMLElement} */ let share_by_token_btn = get_element(html_scene, "button[data-name=sharebytoken]");
/** @type {HTMLElement} */ let share_by_map_btn = get_element(html_scene, "button[data-name=sharebymap]");
/** @type {HTMLElement} */ let share_by_bday_btn = get_element(html_scene, "button[data-name=sharebybday]");
/** @type {HTMLElement} */ let share_by_token_div = get_element(html_scene, "div[data-name=sharebytoken]");
/** @type {HTMLElement} */ let share_by_map_div = get_element(html_scene, "div[data-name=sharebymap]");
/** @type {HTMLElement} */ let share_by_bday_div = get_element(html_scene, "div[data-name=sharebybday]");
/** @type {HTMLElement} */ let error_form = get_element(html_scene, "[data-name=error]");
let errorHandler = new ErrorHandler(error_form);
@@ -79,11 +76,6 @@ export class ShareCollectionScene {
push_scene(create_edit_share_scene);
}
function onsharebybday() {
let create_edit_share_scene = new CreateEditShareScene(user, password, collection, "bday");
push_scene(create_edit_share_scene);
}
this.show = function () {
this.release();
html_scene.classList.remove("hidden");
@@ -123,25 +115,6 @@ export class ShareCollectionScene {
if (share_by_map_div) share_by_map_div.classList.add("hidden");
}
if (features.sharing && features.sharing.PermittedCreateCollectionByBday) {
let is_addressbook = collection.type === CollectionType.ADDRESSBOOK;
if (share_by_bday_btn) {
if (is_addressbook) {
share_by_bday_btn.classList.remove("hidden");
share_by_bday_btn.onclick = onsharebybday;
} else {
share_by_bday_btn.classList.add("hidden");
}
}
} else {
if (share_by_bday_btn) share_by_bday_btn.classList.add("hidden");
}
if (features.sharing && features.sharing.FeatureEnabledCollectionByBday && collection.type === CollectionType.ADDRESSBOOK) {
if (share_by_bday_div) share_by_bday_div.classList.remove("hidden");
} else {
if (share_by_bday_div) share_by_bday_div.classList.add("hidden");
}
});
title.textContent = collection.displayname || collection.href;
@@ -164,7 +137,7 @@ export class ShareCollectionScene {
*/
function update_share_list(user, password, collection, errorHandler) {
let share_rows = document.querySelectorAll(
"[data-name=sharetokenrowtemplate], [data-name=sharemaprowtemplate], [data-name=sharebdayrowtemplate]",
"[data-name=sharetokenrowtemplate], [data-name=sharemaprowtemplate]",
);
share_rows.forEach(function (row) {
if (!row.classList.contains("hidden")) {
@@ -206,7 +179,7 @@ function add_share_row_node(user, password, collection, share, template, delete_
}
let permissions = (share["Permissions"] || "").toLowerCase();
displayPermissions(permissions, node);
displayPermissionsOrConversion(share["Conversion"], permissions, node);
/** @type {HTMLElement} */ let edit_btn = get_element(node, "[data-name=edit]");
edit_btn.onclick = function () {
@@ -242,7 +215,6 @@ function add_share_row_node(user, password, collection, share, template, delete_
function add_share_rows(user, password, collection, shares, errorHandler) {
/** @type {HTMLElement} */ let token_template = get_element(document, "[data-name=sharetokenrowtemplate]");
/** @type {HTMLElement} */ let map_template = get_element(document, "[data-name=sharemaprowtemplate]");
/** @type {HTMLElement} */ let bday_template = get_element(document, "[data-name=sharebdayrowtemplate]");
shares.forEach(function (share) {
let pathortoken = share["PathOrToken"] || "";
let pathmapped = share["PathMapped"] || "";
@@ -252,11 +224,10 @@ function add_share_rows(user, password, collection, shares, errorHandler) {
) {
if (share["ShareType"] === "token") {
add_share_row_node(user, password, collection, share, token_template, "share", delete_share_by_token, errorHandler);
} else if (share["ShareType"] === "map") {
}
// TODO: Eventually remove bday
else if (share["ShareType"] === "map" || share["ShareType"] === "bday") {
add_share_row_node(user, password, collection, share, map_template, "map", delete_share_by_map, errorHandler);
} else if (share["ShareType"] === "bday") {
let onDeleteSuccess = (share["User"] === user) ? function () { collectionsCache.invalidate(); } : undefined;
add_share_row_node(user, password, collection, share, bday_template, "bday", delete_share_by_bday, errorHandler, onDeleteSuccess);
}
}
});
@@ -269,8 +240,7 @@ export function maybe_enable_sharing_options(features) {
if (!features || !features.sharing) return;
let map_is_enabled = features.sharing.FeatureEnabledCollectionByMap || false;
let token_is_enabled = features.sharing.FeatureEnabledCollectionByToken || false;
let bday_is_enabled = features.sharing.FeatureEnabledCollectionByBday || false;
let any_sharing_enabled = map_is_enabled || token_is_enabled || bday_is_enabled;
let any_sharing_enabled = map_is_enabled || token_is_enabled;
let share_options = document.querySelectorAll("[data-name=shareoption]");
for (let i = 0; i < share_options.length; i++) {

View File

@@ -16,23 +16,34 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { get_element } from "../utils/misc.js";
/**
* @param {string} conversion
* @param {string} permissions
* @param {HTMLElement} node
*/
export function displayPermissions(permissions, node) {
permissions = (permissions || "").toLowerCase();
if (permissions === "rw") {
const roElement = node.querySelector("[data-name=ro]");
if (roElement && roElement.parentNode) {
roElement.parentNode.removeChild(roElement);
}
} else if (permissions === "r") {
const rwElement = node.querySelector("[data-name=rw]");
if (rwElement && rwElement.parentNode) {
rwElement.parentNode.removeChild(rwElement);
}
export function displayPermissionsOrConversion(conversion, permissions, node) {
const conversionElement = get_element(node, "[data-name=conversion]");
const roElement = get_element(node, "[data-name=ro]");
const rwElement = get_element(node, "[data-name=rw]");
let fixedConversion = (conversion || "").toLowerCase();
if (fixedConversion === "bday") {
conversionElement.classList.remove("hidden");
roElement.classList.add("hidden");
rwElement.classList.add("hidden");
} else {
console.warn("Unknown permissions", permissions);
permissions = (permissions || "").toLowerCase();
if (permissions === "rw") {
rwElement.classList.remove("hidden");
roElement.classList.add("hidden");
conversionElement.classList.add("hidden");
} else if (permissions === "r") {
roElement.classList.remove("hidden");
rwElement.classList.add("hidden");
conversionElement.classList.add("hidden");
} else {
console.warn("Unknown permissions", permissions);
}
}
}