Merge dev into main (v0.59.1)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 30s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 30s
This commit is contained in:
commit
f22a18c89d
6 files changed
+55
-7
No files matched your search
+8
-1
@@ -6,6 +6,12 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.59.1] - 2026-11-02
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Desktop: Das Layout verschiebt sich nicht mehr um ein paar Pixel, wenn eine Seite scrollbar wird (z. B. ein breites Kanban-Board) oder beim Wechsel zwischen Seiten mit und ohne Scrollbalken. Der Platz für den Scrollbalken bleibt immer frei.
|
||||||
|
- Aufgaben: Beim Wechsel der Aufgabenliste blitzten kurz die Aufgaben der vorherigen Liste auf, besonders beim Wechsel zwischen Listen- und Kanban-Ansicht. Jetzt erscheint die neue Liste sofort mit ihren Aufgaben.
|
||||||
|
|
||||||
## [0.59.0] - 2026-11-02
|
## [0.59.0] - 2026-11-02
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -853,7 +859,8 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V
|
|||||||
- Geteilte Listen (Einkaufs-, Pack- und Checklisten) mit `#Kategorie`-Gruppierung, Mengenangaben und Echtzeit-Abhaken.
|
- Geteilte Listen (Einkaufs-, Pack- und Checklisten) mit `#Kategorie`-Gruppierung, Mengenangaben und Echtzeit-Abhaken.
|
||||||
- Benutzer-, Gruppen- und Admin-Verwaltung (Ersteinrichtungs-Assistent, Einladungscodes, Profilbilder, persönliche API-Keys & Webhook-Ingest `/api/v1/webhooks/ingest`, JSON-Datenexport) sowie CSS-Theme-Engine mit 4 Themes (`Dark`, `Light`, `High Contrast`, `Soft`) und PWA-Unterstützung.
|
- Benutzer-, Gruppen- und Admin-Verwaltung (Ersteinrichtungs-Assistent, Einladungscodes, Profilbilder, persönliche API-Keys & Webhook-Ingest `/api/v1/webhooks/ingest`, JSON-Datenexport) sowie CSS-Theme-Engine mit 4 Themes (`Dark`, `Light`, `High Contrast`, `Soft`) und PWA-Unterstützung.
|
||||||
|
|
||||||
[Unreleased]: https://git.dsit.me/sandrodach/MindSift/compare/v0.59.0...dev
|
[Unreleased]: https://git.dsit.me/sandrodach/MindSift/compare/v0.59.1...dev
|
||||||
|
[0.59.1]: https://git.dsit.me/sandrodach/MindSift/compare/v0.59.0...v0.59.1
|
||||||
[0.59.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.58.0...v0.59.0
|
[0.59.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.58.0...v0.59.0
|
||||||
[0.58.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.57.0...v0.58.0
|
[0.58.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.57.0...v0.58.0
|
||||||
[0.57.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.56.0...v0.57.0
|
[0.57.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.56.0...v0.57.0
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
[](#)
|
[](#)
|
||||||
[](#-schnellstart)
|
[](#-schnellstart)
|
||||||
[](#-deine-daten-gehören-dir)
|
[](#-deine-daten-gehören-dir)
|
||||||
[](CHANGELOG.md)
|
[](CHANGELOG.md)
|
||||||
|
|
||||||
**MindSift** ist eine selbst gehostete Schaltstelle für spontane Gedanken, Aufgaben mit Kanban-Board, hierarchische Outliner-Notizen, die mehrere Personen gleichzeitig bearbeiten können, und gemeinsame Listen. Alles läuft als ein einzelner Container mit eingebetteter SQLite-Datenbank, auf deinem eigenen Server.
|
**MindSift** ist eine selbst gehostete Schaltstelle für spontane Gedanken, Aufgaben mit Kanban-Board, hierarchische Outliner-Notizen, die mehrere Personen gleichzeitig bearbeiten können, und gemeinsame Listen. Alles läuft als ein einzelner Container mit eingebetteter SQLite-Datenbank, auf deinem eigenen Server.
|
||||||
|
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mindsift-frontend",
|
"name": "mindsift-frontend",
|
||||||
"version": "0.59.0",
|
"version": "0.59.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mindsift-frontend",
|
"name": "mindsift-frontend",
|
||||||
"version": "0.59.0",
|
"version": "0.59.1",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource-variable/inter": "5.3.0",
|
"@fontsource-variable/inter": "5.3.0",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "mindsift-frontend",
|
"name": "mindsift-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.59.0",
|
"version": "0.59.1",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
|||||||
const [filter, setFilter] = useState<'open' | 'done' | 'discarded'>('open');
|
const [filter, setFilter] = useState<'open' | 'done' | 'discarded'>('open');
|
||||||
const [tasks, setTasks] = useState<Thought[]>([]);
|
const [tasks, setTasks] = useState<Thought[]>([]);
|
||||||
const [taskLists, setTaskLists] = useState<TaskList[]>([]);
|
const [taskLists, setTaskLists] = useState<TaskList[]>([]);
|
||||||
const [selectedListId, setSelectedListId] = useState<string>(
|
const [selectedListId, setSelectedListIdState] = useState<string>(
|
||||||
() => remembered.listId || 'all'
|
() => remembered.listId || 'all'
|
||||||
);
|
);
|
||||||
const viewMode: ViewMode = viewModes[selectedListId] || 'list';
|
const viewMode: ViewMode = viewModes[selectedListId] || 'list';
|
||||||
@@ -304,6 +304,10 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
|||||||
]);
|
]);
|
||||||
if (seq !== loadSeqRef.current) return; // a newer reload is under way
|
if (seq !== loadSeqRef.current) return; // a newer reload is under way
|
||||||
loadedListRef.current = listId;
|
loadedListRef.current = listId;
|
||||||
|
listCacheRef.current.set(listId, {
|
||||||
|
tasks: Array.isArray(allTasks) ? allTasks : [],
|
||||||
|
trash: Array.isArray(trash) ? trash : [],
|
||||||
|
});
|
||||||
setTasks(Array.isArray(allTasks) ? allTasks : []);
|
setTasks(Array.isArray(allTasks) ? allTasks : []);
|
||||||
setTaskLists(Array.isArray(allLists) ? allLists : []);
|
setTaskLists(Array.isArray(allLists) ? allLists : []);
|
||||||
// The remembered list was deleted or unshared meanwhile
|
// The remembered list was deleted or unshared meanwhile
|
||||||
@@ -327,6 +331,33 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
|||||||
const selectedListIdRef = useRef(selectedListId);
|
const selectedListIdRef = useRef(selectedListId);
|
||||||
selectedListIdRef.current = selectedListId;
|
selectedListIdRef.current = selectedListId;
|
||||||
|
|
||||||
|
// Last known tasks of every list opened in this session. Switching lists shows them in the same render
|
||||||
|
// as the new list's view (list or Kanban), so the board never flashes the previous list's tasks; the
|
||||||
|
// reload then brings them up to date. A list not opened yet takes its share of "Alle Aufgaben".
|
||||||
|
const listCacheRef = useRef(new Map<string, { tasks: Thought[]; trash: TrashedTask[] }>());
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loading && loadedListRef.current === selectedListId) {
|
||||||
|
listCacheRef.current.set(selectedListId, { tasks, trash: taskTrash });
|
||||||
|
}
|
||||||
|
}, [tasks, taskTrash, loading, selectedListId]);
|
||||||
|
const setSelectedListId = useCallback((id: string) => {
|
||||||
|
if (id === selectedListIdRef.current) return;
|
||||||
|
const cache = listCacheRef.current;
|
||||||
|
let known = cache.get(id);
|
||||||
|
const all = cache.get('all');
|
||||||
|
if (!known && id !== 'all' && all) {
|
||||||
|
known = {
|
||||||
|
tasks: all.tasks.filter((t) => t.taskListId === id),
|
||||||
|
trash: all.trash.filter((t) => t.taskListId === id),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
setTasks(known ? known.tasks : []);
|
||||||
|
setTaskTrash(known ? known.trash : []);
|
||||||
|
setLoading(!known);
|
||||||
|
loadedListRef.current = known ? id : null;
|
||||||
|
setSelectedListIdState(id);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const onRefreshStatsRef = useRef(onRefreshStats);
|
const onRefreshStatsRef = useRef(onRefreshStats);
|
||||||
onRefreshStatsRef.current = onRefreshStats;
|
onRefreshStatsRef.current = onRefreshStats;
|
||||||
// The realtime handler is registered once; it must reload with the current list, not the first one
|
// The realtime handler is registered once; it must reload with the current list, not the first one
|
||||||
@@ -1371,7 +1402,9 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
|||||||
try {
|
try {
|
||||||
await api.deleteTaskList(listId);
|
await api.deleteTaskList(listId);
|
||||||
setTaskLists((prev) => prev.filter((l) => l.id !== listId));
|
setTaskLists((prev) => prev.filter((l) => l.id !== listId));
|
||||||
setSelectedListId('all');
|
// Plain switch: the deleted list's tasks belong to "Alle Aufgaben" anyway (and the menu effect keeps
|
||||||
|
// this handler out of its dependencies)
|
||||||
|
setSelectedListIdState('all');
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
alert(err.message);
|
alert(err.message);
|
||||||
}
|
}
|
||||||
@@ -1568,6 +1601,7 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
|||||||
groupBy,
|
groupBy,
|
||||||
defaultGroupBy,
|
defaultGroupBy,
|
||||||
setViewMode,
|
setViewMode,
|
||||||
|
setSelectedListId,
|
||||||
sortBy,
|
sortBy,
|
||||||
openTasks.length,
|
openTasks.length,
|
||||||
doneTasks.length,
|
doneTasks.length,
|
||||||
|
|||||||
@@ -29,6 +29,13 @@
|
|||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Room for the scrollbar is always kept: pages that scroll (e.g. a wide Kanban board) and pages that do
|
||||||
|
not keep the same width, so nothing shifts when switching tabs. Overlay scrollbars (phones) are not
|
||||||
|
affected. */
|
||||||
|
html {
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: var(--bg-app);
|
background-color: var(--bg-app);
|
||||||
color: var(--text-main);
|
color: var(--text-main);
|
||||||
|
|||||||
Reference in new issue
Block a user