fix(web): can't edit calendars shared with me; struck-pencil read-only marker

- Sidebar: don't start an inline rename on a calendar I don't own (owned=false)
  — the save would only 403. Colour picker was already gated.
- Sidebar: show a struck-through pencil icon on read-only shared calendars.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-06 18:38:01 +02:00
parent 79fdf4f54a
commit 2ae8499247
3 changed files with 11 additions and 2 deletions

View File

@@ -2148,6 +2148,8 @@ a { color: var(--primary); text-decoration: none; }
/* Group emoji + icon picker */ /* Group emoji + icon picker */
.group-emoji { flex: 0 0 auto; font-size: 16px; cursor: pointer; line-height: 1; } .group-emoji { flex: 0 0 auto; font-size: 16px; cursor: pointer; line-height: 1; }
.cal-shared-flag { flex: 0 0 auto; font-size: 12px; opacity: .8; } .cal-shared-flag { flex: 0 0 auto; font-size: 12px; opacity: .8; }
/* Read-only (shared with me) indicator: a struck-through pencil. */
.cal-readonly-flag { color: var(--text-3); opacity: .7; margin-left: 2px; }
.group-icon-picker { display: flex; flex-wrap: wrap; gap: 6px; } .group-icon-picker { display: flex; flex-wrap: wrap; gap: 6px; }
.group-icon-opt { .group-icon-opt {
width: 38px; height: 38px; width: 38px; height: 38px;

View File

@@ -733,7 +733,7 @@ function renderCalendarList() {
// (e.g. Guido's "Persönlich" appears as "Guido"); the original calendar // (e.g. Guido's "Persönlich" appears as "Guido"); the original calendar
// name stays in the sub-label so it's still identifiable. // name stays in the sub-label so it's still identifiable.
entries.push({ key: `local:${cal.id}`, source: 'local', dataId: `data-cal-id="${cal.id}"`, entries.push({ key: `local:${cal.id}`, source: 'local', dataId: `data-cal-id="${cal.id}"`,
name: cal.shared_by || cal.name, color: cal.color, enabled: cal.enabled, name: cal.shared_by || cal.name, color: cal.color, enabled: cal.enabled, readOnly,
sourceLabel: `${t('shared_with_me')} · ${cal.name}${readOnly ? ' · ' + t('perm_read') : ''}`, remove: null }); sourceLabel: `${t('shared_with_me')} · ${cal.name}${readOnly ? ' · ' + t('perm_read') : ''}`, remove: null });
}); });
// Group calendars (owned by the creator or reached via membership) — shown so // Group calendars (owned by the creator or reached via membership) — shown so
@@ -793,6 +793,7 @@ function renderCalendarList() {
${e.isGroupCal ? `<span class="cal-shared-flag" title="${escHtml(e.sourceLabel)}">${groupIconSvg(e.groupIcon || 'people', 13)}</span>` : ''} ${e.isGroupCal ? `<span class="cal-shared-flag" title="${escHtml(e.sourceLabel)}">${groupIconSvg(e.groupIcon || 'people', 13)}</span>` : ''}
${e.groupVisible ? `<span class="cal-shared-flag cal-shared-flag-own" title="${t('group_visible_flag')}">${shareIconSvg(state.settings?.share_calendar_icon || 'share', 13)}</span>` : ''} ${e.groupVisible ? `<span class="cal-shared-flag cal-shared-flag-own" title="${t('group_visible_flag')}">${shareIconSvg(state.settings?.share_calendar_icon || 'share', 13)}</span>` : ''}
<span class="cal-item-name" data-source="${e.source}">${escHtml(e.name)}</span> <span class="cal-item-name" data-source="${e.source}">${escHtml(e.name)}</span>
${e.readOnly ? `<span class="cal-shared-flag cal-readonly-flag" title="${t('perm_read')}"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"/><line x1="3" y1="3" x2="21" y2="21"/></svg></span>` : ''}
${e.reminders ? `<button class="icon-btn mini-btn cal-item-bell ${e.remindersEnabled ? '' : 'off'}" data-source="${e.source}" ${e.dataId} title="${e.remindersEnabled ? t('calendar_reminders_on') : t('calendar_reminders_off')}">${e.remindersEnabled ? BELL : BELL_OFF}</button>` : ''} ${e.reminders ? `<button class="icon-btn mini-btn cal-item-bell ${e.remindersEnabled ? '' : 'off'}" data-source="${e.source}" ${e.dataId} title="${e.remindersEnabled ? t('calendar_reminders_on') : t('calendar_reminders_off')}">${e.remindersEnabled ? BELL : BELL_OFF}</button>` : ''}
${e.remove ? `<button class="icon-btn mini-btn cal-item-remove" data-source="${e.source}" ${e.dataId} title="${e.remove.title}">${e.remove.icon}</button>` : ''} ${e.remove ? `<button class="icon-btn mini-btn cal-item-remove" data-source="${e.source}" ${e.dataId} title="${e.remove.title}">${e.remove.icon}</button>` : ''}
</div>` </div>`
@@ -956,6 +957,12 @@ function renderCalendarList() {
e.stopPropagation(); e.stopPropagation();
const item = nameEl.closest('.cal-item'); const item = nameEl.closest('.cal-item');
const source = nameEl.dataset.source; const source = nameEl.dataset.source;
// Can't rename a calendar shared with me — only the owner may. Renaming
// would just 403 on save, so don't even start editing.
if (source === 'local') {
const cal = state.localCalendars.find(c => c.id === parseInt(item?.dataset.calId));
if (cal && cal.owned === false) return;
}
const currentName = nameEl.textContent; const currentName = nameEl.textContent;
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'text'; input.type = 'text';

View File

@@ -1,2 +1,2 @@
// Increment APP_VERSION with every code change // Increment APP_VERSION with every code change
export const APP_VERSION = 'v71'; export const APP_VERSION = 'v72';