Merge dev into main (v0.59.0)
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
1ce9d67e00
5 files changed
+49
-13
No files matched your search
+7
-1
@@ -6,6 +6,11 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.59.0] - 2026-11-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Aufgaben: Jede Aufgabenliste merkt sich, ob sie als Liste oder als Kanban-Board angezeigt wird, „Alle Aufgaben“ ebenso (pro Gerät).
|
||||||
|
|
||||||
## [0.58.0] - 2026-11-02
|
## [0.58.0] - 2026-11-02
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -848,7 +853,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.58.0...dev
|
[Unreleased]: https://git.dsit.me/sandrodach/MindSift/compare/v0.59.0...dev
|
||||||
|
[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
|
||||||
[0.56.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.55.0...v0.56.0
|
[0.56.0]: https://git.dsit.me/sandrodach/MindSift/compare/v0.55.0...v0.56.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.58.0",
|
"version": "0.59.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mindsift-frontend",
|
"name": "mindsift-frontend",
|
||||||
"version": "0.58.0",
|
"version": "0.59.0",
|
||||||
"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.58.0",
|
"version": "0.59.0",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -92,7 +92,15 @@ const kanbanBoardStyle = (wide: boolean, columns: number): React.CSSProperties =
|
|||||||
};
|
};
|
||||||
|
|
||||||
type GroupBy = 'none' | 'list' | 'tag' | 'status' | 'priority' | 'due';
|
type GroupBy = 'none' | 'list' | 'tag' | 'status' | 'priority' | 'due';
|
||||||
type TasksSession = { listId: string; viewMode: 'list' | 'kanban'; groupAll: GroupBy; groupList: GroupBy };
|
type ViewMode = 'list' | 'kanban';
|
||||||
|
// viewModes: list or Kanban per task list ("all" for Alle Aufgaben); viewMode is the old single value
|
||||||
|
type TasksSession = {
|
||||||
|
listId: string;
|
||||||
|
viewModes: Record<string, ViewMode>;
|
||||||
|
viewMode?: ViewMode;
|
||||||
|
groupAll: GroupBy;
|
||||||
|
groupList: GroupBy;
|
||||||
|
};
|
||||||
|
|
||||||
// "Alle Aufgaben" is grouped by task list unless the user picks something else; a single list has no
|
// "Alle Aufgaben" is grouped by task list unless the user picks something else; a single list has no
|
||||||
// grouping by default (grouping it by list would give one group)
|
// grouping by default (grouping it by list would give one group)
|
||||||
@@ -123,11 +131,20 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
|||||||
onInitialTaskShown,
|
onInitialTaskShown,
|
||||||
openTasksCount,
|
openTasksCount,
|
||||||
}) => {
|
}) => {
|
||||||
// Open list, view and grouping are remembered on this device (new tab, restart of the installed app)
|
// Open list, view per list and grouping are remembered on this device (new tab, restart of the
|
||||||
|
// installed app)
|
||||||
const remembered = useMemo(() => readViewMemory<TasksSession>('tasks'), []);
|
const remembered = useMemo(() => readViewMemory<TasksSession>('tasks'), []);
|
||||||
const [viewMode, setViewMode] = useState<'list' | 'kanban'>(() =>
|
const [viewModes, setViewModes] = useState<Record<string, ViewMode>>(() => {
|
||||||
remembered.viewMode === 'kanban' ? 'kanban' : 'list'
|
const out: Record<string, ViewMode> = {};
|
||||||
);
|
if (remembered.viewModes && typeof remembered.viewModes === 'object') {
|
||||||
|
for (const [id, mode] of Object.entries(remembered.viewModes)) {
|
||||||
|
if (mode === 'kanban') out[id] = 'kanban';
|
||||||
|
}
|
||||||
|
} else if (remembered.viewMode === 'kanban' && remembered.listId) {
|
||||||
|
out[remembered.listId] = 'kanban'; // stored before views were kept per list
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
});
|
||||||
const [groupAll, setGroupAll] = useState<GroupBy>(() =>
|
const [groupAll, setGroupAll] = useState<GroupBy>(() =>
|
||||||
remembered.groupAll && remembered.groupAll in GROUP_LABELS ? remembered.groupAll : DEFAULT_GROUP_ALL
|
remembered.groupAll && remembered.groupAll in GROUP_LABELS ? remembered.groupAll : DEFAULT_GROUP_ALL
|
||||||
);
|
);
|
||||||
@@ -153,13 +170,25 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
|||||||
// only a convenience
|
// only a convenience
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const isKanbanWide = viewMode === 'kanban' && kanbanWide;
|
|
||||||
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, setSelectedListId] = useState<string>(
|
||||||
() => remembered.listId || 'all'
|
() => remembered.listId || 'all'
|
||||||
);
|
);
|
||||||
|
const viewMode: ViewMode = viewModes[selectedListId] || 'list';
|
||||||
|
// Only Kanban is stored; the list view is the default
|
||||||
|
const setViewMode = useCallback(
|
||||||
|
(mode: ViewMode) =>
|
||||||
|
setViewModes((prev) => {
|
||||||
|
const next = { ...prev };
|
||||||
|
if (mode === 'kanban') next[selectedListId] = 'kanban';
|
||||||
|
else delete next[selectedListId];
|
||||||
|
return next;
|
||||||
|
}),
|
||||||
|
[selectedListId]
|
||||||
|
);
|
||||||
|
const isKanbanWide = viewMode === 'kanban' && kanbanWide;
|
||||||
const isAllTasks = selectedListId === 'all';
|
const isAllTasks = selectedListId === 'all';
|
||||||
const groupBy: GroupBy = isAllTasks ? groupAll : groupList;
|
const groupBy: GroupBy = isAllTasks ? groupAll : groupList;
|
||||||
const setGroupBy = (g: GroupBy) => (isAllTasks ? setGroupAll(g) : setGroupList(g));
|
const setGroupBy = (g: GroupBy) => (isAllTasks ? setGroupAll(g) : setGroupList(g));
|
||||||
@@ -169,8 +198,8 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
|||||||
.filter((id) => isAllTasks || id !== 'list')
|
.filter((id) => isAllTasks || id !== 'list')
|
||||||
.map((id) => ({ id, label: GROUP_LABELS[id] }));
|
.map((id) => ({ id, label: GROUP_LABELS[id] }));
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
writeViewMemory<TasksSession>('tasks', { listId: selectedListId, viewMode, groupAll, groupList });
|
writeViewMemory<TasksSession>('tasks', { listId: selectedListId, viewModes, groupAll, groupList });
|
||||||
}, [selectedListId, viewMode, groupAll, groupList]);
|
}, [selectedListId, viewModes, groupAll, groupList]);
|
||||||
const [teams, setTeams] = useState<Team[]>([]);
|
const [teams, setTeams] = useState<Team[]>([]);
|
||||||
const [collaborators, setCollaborators] = useState<User[]>([]);
|
const [collaborators, setCollaborators] = useState<User[]>([]);
|
||||||
// Task trash of the selected list (or all): deleted tasks and cleared or cleaned-up completed ones
|
// Task trash of the selected list (or all): deleted tasks and cleared or cleaned-up completed ones
|
||||||
@@ -1538,6 +1567,7 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
|||||||
selectedTag,
|
selectedTag,
|
||||||
groupBy,
|
groupBy,
|
||||||
defaultGroupBy,
|
defaultGroupBy,
|
||||||
|
setViewMode,
|
||||||
sortBy,
|
sortBy,
|
||||||
openTasks.length,
|
openTasks.length,
|
||||||
doneTasks.length,
|
doneTasks.length,
|
||||||
|
|||||||
Reference in new issue
Block a user