Kalender-Sichtbarkeit persistent speichern + Sidebar-Overflow-Fix
- sidebar_hidden-Spalte zu calendars und google_calendars hinzugefügt - Ausblenden-Button persistiert jetzt server-seitig (cross-device) - Einblenden in Einstellungen schreibt sidebar_hidden=false zurück - Sidebar: overflow-x hidden verhindert dass lange Namen den Button rausschieben
This commit is contained in:
@@ -31,6 +31,18 @@ def _migrate():
|
|||||||
logging.info("Migration: added week_start_day column")
|
logging.info("Migration: added week_start_day column")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # Column already exists
|
pass # Column already exists
|
||||||
|
try:
|
||||||
|
conn.execute(text("ALTER TABLE calendars ADD COLUMN sidebar_hidden BOOLEAN DEFAULT 0"))
|
||||||
|
conn.commit()
|
||||||
|
logging.info("Migration: added sidebar_hidden to calendars")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
conn.execute(text("ALTER TABLE google_calendars ADD COLUMN sidebar_hidden BOOLEAN DEFAULT 0"))
|
||||||
|
conn.commit()
|
||||||
|
logging.info("Migration: added sidebar_hidden to google_calendars")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
_migrate()
|
_migrate()
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ class Calendar(Base):
|
|||||||
name = Column(String(100), nullable=False)
|
name = Column(String(100), nullable=False)
|
||||||
color = Column(String(7), nullable=True)
|
color = Column(String(7), nullable=True)
|
||||||
enabled = Column(Boolean, default=True)
|
enabled = Column(Boolean, default=True)
|
||||||
|
sidebar_hidden = Column(Boolean, default=False)
|
||||||
|
|
||||||
account = relationship("CalDAVAccount", back_populates="calendars")
|
account = relationship("CalDAVAccount", back_populates="calendars")
|
||||||
|
|
||||||
@@ -168,5 +169,6 @@ class GoogleCalendar(Base):
|
|||||||
name = Column(String(255), nullable=False)
|
name = Column(String(255), nullable=False)
|
||||||
color = Column(String(7), nullable=True)
|
color = Column(String(7), nullable=True)
|
||||||
enabled = Column(Boolean, default=True)
|
enabled = Column(Boolean, default=True)
|
||||||
|
sidebar_hidden = Column(Boolean, default=False)
|
||||||
|
|
||||||
account = relationship("GoogleAccount", back_populates="calendars")
|
account = relationship("GoogleAccount", back_populates="calendars")
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class CalendarUpdate(BaseModel):
|
|||||||
enabled: Optional[bool] = None
|
enabled: Optional[bool] = None
|
||||||
color: Optional[str] = None
|
color: Optional[str] = None
|
||||||
name: Optional[str] = None
|
name: Optional[str] = None
|
||||||
|
sidebar_hidden: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
class EventCreate(BaseModel):
|
class EventCreate(BaseModel):
|
||||||
@@ -67,6 +68,7 @@ def _account_dict(a: models.CalDAVAccount) -> dict:
|
|||||||
"color": c.color or a.color,
|
"color": c.color or a.color,
|
||||||
"enabled": c.enabled,
|
"enabled": c.enabled,
|
||||||
"cal_id": c.cal_id,
|
"cal_id": c.cal_id,
|
||||||
|
"sidebar_hidden": bool(c.sidebar_hidden),
|
||||||
}
|
}
|
||||||
for c in a.calendars
|
for c in a.calendars
|
||||||
],
|
],
|
||||||
@@ -225,6 +227,8 @@ def update_calendar(
|
|||||||
calendar.color = data.color
|
calendar.color = data.color
|
||||||
if data.name is not None:
|
if data.name is not None:
|
||||||
calendar.name = data.name
|
calendar.name = data.name
|
||||||
|
if data.sidebar_hidden is not None:
|
||||||
|
calendar.sidebar_hidden = data.sidebar_hidden
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ def _account_dict(a: models.GoogleAccount) -> dict:
|
|||||||
"name": c.name,
|
"name": c.name,
|
||||||
"color": c.color or "#4285f4",
|
"color": c.color or "#4285f4",
|
||||||
"enabled": c.enabled,
|
"enabled": c.enabled,
|
||||||
|
"sidebar_hidden": bool(c.sidebar_hidden),
|
||||||
}
|
}
|
||||||
for c in a.calendars
|
for c in a.calendars
|
||||||
],
|
],
|
||||||
@@ -325,6 +326,7 @@ class GoogleCalendarUpdate(BaseModel):
|
|||||||
enabled: Optional[bool] = None
|
enabled: Optional[bool] = None
|
||||||
color: Optional[str] = None
|
color: Optional[str] = None
|
||||||
name: Optional[str] = None
|
name: Optional[str] = None
|
||||||
|
sidebar_hidden: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
@router.put("/calendars/{calendar_id}")
|
@router.put("/calendars/{calendar_id}")
|
||||||
@@ -351,6 +353,8 @@ def update_calendar(
|
|||||||
gcal.color = data.color
|
gcal.color = data.color
|
||||||
if data.name is not None:
|
if data.name is not None:
|
||||||
gcal.name = data.name
|
gcal.name = data.name
|
||||||
|
if data.sidebar_hidden is not None:
|
||||||
|
gcal.sidebar_hidden = data.sidebar_hidden
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|||||||
@@ -335,6 +335,7 @@ a { color: var(--primary); text-decoration: none; }
|
|||||||
border-right: 1px solid var(--border);
|
border-right: 1px solid var(--border);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
transition: transform var(--transition);
|
transition: transform var(--transition);
|
||||||
}
|
}
|
||||||
.sidebar.collapsed { transform: translateX(calc(-1 * var(--sidebar-w))); margin-right: calc(-1 * var(--sidebar-w)); }
|
.sidebar.collapsed { transform: translateX(calc(-1 * var(--sidebar-w))); margin-right: calc(-1 * var(--sidebar-w)); }
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ function renderCalendarList() {
|
|||||||
// ── CalDAV accounts ────────────────────────────────────
|
// ── CalDAV accounts ────────────────────────────────────
|
||||||
if (state.accounts.length) {
|
if (state.accounts.length) {
|
||||||
html += state.accounts.map(acc => {
|
html += state.accounts.map(acc => {
|
||||||
const visibleCals = acc.calendars.filter(c => !c._hidden);
|
const visibleCals = acc.calendars.filter(c => !c.sidebar_hidden);
|
||||||
if (!visibleCals.length) return '';
|
if (!visibleCals.length) return '';
|
||||||
return `<div class="cal-account-name">${escHtml(acc.name)}</div>` +
|
return `<div class="cal-account-name">${escHtml(acc.name)}</div>` +
|
||||||
visibleCals.map(cal =>
|
visibleCals.map(cal =>
|
||||||
@@ -311,7 +311,7 @@ function renderCalendarList() {
|
|||||||
// ── Google accounts ───────────────────────────────────
|
// ── Google accounts ───────────────────────────────────
|
||||||
if (state.googleAccounts.length) {
|
if (state.googleAccounts.length) {
|
||||||
html += state.googleAccounts.map(acc => {
|
html += state.googleAccounts.map(acc => {
|
||||||
const visibleCals = acc.calendars.filter(c => !c._hidden);
|
const visibleCals = acc.calendars.filter(c => !c.sidebar_hidden);
|
||||||
if (!visibleCals.length) return `<div class="cal-account-name">${escHtml(acc.email)}</div>`;
|
if (!visibleCals.length) return `<div class="cal-account-name">${escHtml(acc.email)}</div>`;
|
||||||
return `<div class="cal-account-name">${escHtml(acc.email)}</div>` +
|
return `<div class="cal-account-name">${escHtml(acc.email)}</div>` +
|
||||||
visibleCals.map(cal =>
|
visibleCals.map(cal =>
|
||||||
@@ -467,10 +467,10 @@ function renderCalendarList() {
|
|||||||
const source = btn.dataset.source;
|
const source = btn.dataset.source;
|
||||||
if (source === 'caldav') {
|
if (source === 'caldav') {
|
||||||
const calId = parseInt(btn.dataset.calId);
|
const calId = parseInt(btn.dataset.calId);
|
||||||
await api.put(`/caldav/calendars/${calId}`, { enabled: false });
|
await api.put(`/caldav/calendars/${calId}`, { enabled: false, sidebar_hidden: true });
|
||||||
for (const acc of state.accounts) {
|
for (const acc of state.accounts) {
|
||||||
for (const cal of acc.calendars) {
|
for (const cal of acc.calendars) {
|
||||||
if (cal.id === calId) { cal.enabled = false; cal._hidden = true; }
|
if (cal.id === calId) { cal.enabled = false; cal.sidebar_hidden = true; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (source === 'local') {
|
} else if (source === 'local') {
|
||||||
@@ -485,10 +485,10 @@ function renderCalendarList() {
|
|||||||
state.icalSubscriptions = state.icalSubscriptions.filter(s => s.id !== subId);
|
state.icalSubscriptions = state.icalSubscriptions.filter(s => s.id !== subId);
|
||||||
} else if (source === 'google') {
|
} else if (source === 'google') {
|
||||||
const calId = parseInt(btn.dataset.calId);
|
const calId = parseInt(btn.dataset.calId);
|
||||||
await api.put(`/google/calendars/${calId}`, { enabled: false });
|
await api.put(`/google/calendars/${calId}`, { enabled: false, sidebar_hidden: true });
|
||||||
for (const acc of state.googleAccounts) {
|
for (const acc of state.googleAccounts) {
|
||||||
for (const cal of acc.calendars) {
|
for (const cal of acc.calendars) {
|
||||||
if (cal.id === calId) { cal.enabled = false; cal._hidden = true; }
|
if (cal.id === calId) { cal.enabled = false; cal.sidebar_hidden = true; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1113,12 +1113,12 @@ function renderHiddenCalendars() {
|
|||||||
const hidden = [];
|
const hidden = [];
|
||||||
for (const acc of state.accounts) {
|
for (const acc of state.accounts) {
|
||||||
for (const cal of acc.calendars) {
|
for (const cal of acc.calendars) {
|
||||||
if (!cal.enabled || cal._hidden) hidden.push({ id: cal.id, name: cal.name, acc: acc.name, source: 'caldav' });
|
if (cal.sidebar_hidden) hidden.push({ id: cal.id, name: cal.name, acc: acc.name, source: 'caldav' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const acc of state.googleAccounts) {
|
for (const acc of state.googleAccounts) {
|
||||||
for (const cal of acc.calendars) {
|
for (const cal of acc.calendars) {
|
||||||
if (!cal.enabled || cal._hidden) hidden.push({ id: cal.id, name: cal.name, acc: acc.email, source: 'google' });
|
if (cal.sidebar_hidden) hidden.push({ id: cal.id, name: cal.name, acc: acc.email, source: 'google' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hidden.length) {
|
if (!hidden.length) {
|
||||||
@@ -1136,17 +1136,17 @@ function renderHiddenCalendars() {
|
|||||||
const calId = parseInt(btn.dataset.restoreCal);
|
const calId = parseInt(btn.dataset.restoreCal);
|
||||||
const source = btn.dataset.restoreSource;
|
const source = btn.dataset.restoreSource;
|
||||||
if (source === 'google') {
|
if (source === 'google') {
|
||||||
await api.put(`/google/calendars/${calId}`, { enabled: true });
|
await api.put(`/google/calendars/${calId}`, { enabled: true, sidebar_hidden: false });
|
||||||
for (const acc of state.googleAccounts) {
|
for (const acc of state.googleAccounts) {
|
||||||
for (const cal of acc.calendars) {
|
for (const cal of acc.calendars) {
|
||||||
if (cal.id === calId) { cal.enabled = true; delete cal._hidden; }
|
if (cal.id === calId) { cal.enabled = true; cal.sidebar_hidden = false; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await api.put(`/caldav/calendars/${calId}`, { enabled: true });
|
await api.put(`/caldav/calendars/${calId}`, { enabled: true, sidebar_hidden: false });
|
||||||
for (const acc of state.accounts) {
|
for (const acc of state.accounts) {
|
||||||
for (const cal of acc.calendars) {
|
for (const cal of acc.calendars) {
|
||||||
if (cal.id === calId) { cal.enabled = true; delete cal._hidden; }
|
if (cal.id === calId) { cal.enabled = true; cal.sidebar_hidden = false; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user