feat: use module store
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
+86
-444
@@ -1,17 +1,11 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { computed, onMounted, watch } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useDisplay } from 'vuetify';
|
||||
import { useModuleStore } from '@KTXC/stores/moduleStore';
|
||||
import { useCollectionsStore } from '@ChronoManager/stores/collectionsStore';
|
||||
import { useEntitiesStore } from '@ChronoManager/stores/entitiesStore';
|
||||
import { useServicesStore } from '@ChronoManager/stores/servicesStore';
|
||||
import { CollectionObject } from '@ChronoManager/models/collection';
|
||||
import { EntityObject } from '@ChronoManager/models/entity';
|
||||
import { EventObject } from '@ChronoManager/models/event';
|
||||
import { TaskObject } from '@ChronoManager/models/task';
|
||||
import { ServiceObject } from '@ChronoManager/models/service';
|
||||
import type { CalendarView as CalendarViewType } from '@/types';
|
||||
import { useChronoStore } from '@/stores/chronoStore';
|
||||
import CollectionList from '@/components/CollectionList.vue';
|
||||
import CollectionEditor from '@/components/CollectionEditor.vue';
|
||||
import CalendarView from '@/components/CalendarView.vue';
|
||||
@@ -29,423 +23,82 @@ const isChronoManagerAvailable = computed(() => {
|
||||
return moduleStore.has('chrono_manager') || moduleStore.has('ChronoManager')
|
||||
});
|
||||
|
||||
// Stores
|
||||
const collectionsStore = useCollectionsStore();
|
||||
const entitiesStore = useEntitiesStore();
|
||||
const servicesStore = useServicesStore();
|
||||
const chronoStore = useChronoStore();
|
||||
const route = useRoute();
|
||||
|
||||
// View state
|
||||
const viewMode = ref<'calendar' | 'tasks'>('calendar');
|
||||
const calendarView = ref<CalendarViewType>('days');
|
||||
const currentDate = ref(new Date());
|
||||
const sidebarVisible = ref(true);
|
||||
const {
|
||||
calendarView,
|
||||
daysViewSpan,
|
||||
agendaViewSpan,
|
||||
currentDate,
|
||||
sidebarVisible,
|
||||
selectedCollection,
|
||||
showEventEditor,
|
||||
showTaskEditor,
|
||||
showCollectionEditor,
|
||||
selectedEntity,
|
||||
entityEditorMode,
|
||||
editingCollection,
|
||||
collectionEditorMode,
|
||||
collectionEditorType,
|
||||
calendars,
|
||||
taskLists,
|
||||
isTaskView,
|
||||
filteredEvents,
|
||||
filteredTasks,
|
||||
collections,
|
||||
} = storeToRefs(chronoStore);
|
||||
|
||||
// Data - using manager objects directly
|
||||
const collections = ref<CollectionObject[]>([]);
|
||||
const entities = ref<EntityObject[]>([]);
|
||||
const selectedCollection = ref<CollectionObject | null>(null);
|
||||
const {
|
||||
initialize,
|
||||
setViewMode,
|
||||
setCalendarView,
|
||||
setDaysViewSpan,
|
||||
setAgendaViewSpan,
|
||||
selectCalendar,
|
||||
openEditCalendar,
|
||||
toggleCalendarVisibility,
|
||||
selectTaskList,
|
||||
openEditTaskList,
|
||||
createEventFromDate,
|
||||
startEditingSelectedEntity,
|
||||
cancelEditingSelectedEntity,
|
||||
closeEntityEditor,
|
||||
editEvent,
|
||||
editTask,
|
||||
toggleTaskComplete,
|
||||
saveEvent,
|
||||
deleteEvent,
|
||||
saveTask,
|
||||
deleteTask,
|
||||
saveCollection,
|
||||
deleteCollection,
|
||||
openCreateCalendar,
|
||||
openCreateTaskList,
|
||||
} = chronoStore;
|
||||
|
||||
// Computed - filter collections and entities
|
||||
const calendars = computed(() => {
|
||||
return collections.value.filter(col => col.properties.contents?.event);
|
||||
});
|
||||
|
||||
const taskLists = computed(() => {
|
||||
return collections.value.filter(col => col.properties.contents?.task);
|
||||
});
|
||||
|
||||
const events = computed(() => {
|
||||
return entities.value.filter(entity => entity.properties && (entity.properties as any).type === 'event');
|
||||
});
|
||||
|
||||
const tasks = computed(() => {
|
||||
return entities.value.filter(entity => entity.properties && (entity.properties as any).type === 'task');
|
||||
});
|
||||
|
||||
// Dialog state
|
||||
const showEventEditor = ref(false);
|
||||
const showTaskEditor = ref(false);
|
||||
const showCollectionEditor = ref(false);
|
||||
const selectedEntity = ref<EntityObject | null>(null);
|
||||
const entityEditorMode = ref<'edit' | 'view'>('view');
|
||||
const editingCollection = ref<CollectionObject | null>(null);
|
||||
const collectionEditorMode = ref<'create' | 'edit'>('create');
|
||||
const collectionEditorType = ref<'calendar' | 'tasklist'>('calendar');
|
||||
|
||||
// Computed
|
||||
const isTaskView = computed(() => viewMode.value === 'tasks');
|
||||
|
||||
const filteredEvents = computed(() => {
|
||||
const visibleCalendarIds = calendars.value
|
||||
.filter(cal => cal.properties.visibility !== false)
|
||||
.map(cal => cal.identifier);
|
||||
|
||||
return events.value.filter(event =>
|
||||
visibleCalendarIds.includes(event.collection)
|
||||
);
|
||||
});
|
||||
|
||||
const filteredTasks = computed(() => {
|
||||
return tasks.value;
|
||||
});
|
||||
|
||||
// Methods
|
||||
function selectCalendar(calendar: CollectionObject) {
|
||||
selectedCollection.value = calendar;
|
||||
console.log('[Chrono] - Selected calendar:', calendar);
|
||||
function syncViewModeFromRoute() {
|
||||
const routePath = route.path;
|
||||
const mode = routePath.endsWith('/tasks') ? 'tasks' : 'calendar';
|
||||
setViewMode(mode);
|
||||
}
|
||||
|
||||
function createCalendar() {
|
||||
editingCollection.value = new CollectionObject();
|
||||
editingCollection.value.properties.contents = { event: true };
|
||||
collectionEditorMode.value = 'create';
|
||||
collectionEditorType.value = 'calendar';
|
||||
showCollectionEditor.value = true;
|
||||
function handleCalendarViewChange(view: 'days' | 'month' | 'agenda') {
|
||||
setCalendarView(view);
|
||||
}
|
||||
|
||||
function editCalendar(collection: CollectionObject) {
|
||||
editingCollection.value = collection;
|
||||
collectionEditorMode.value = 'edit';
|
||||
collectionEditorType.value = 'calendar';
|
||||
showCollectionEditor.value = true;
|
||||
}
|
||||
|
||||
async function toggleCalendarVisibility(collection: CollectionObject) {
|
||||
try {
|
||||
await collectionsStore.update(
|
||||
collection.provider,
|
||||
collection.service,
|
||||
collection.identifier,
|
||||
collection.properties
|
||||
);
|
||||
console.log('[Chrono] - Toggled calendar visibility:', collection);
|
||||
} catch (error) {
|
||||
console.error('[Chrono] - Failed to toggle calendar visibility:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function selectTaskList(list: CollectionObject) {
|
||||
selectedCollection.value = list;
|
||||
console.log('[Chrono] - Selected task list:', list);
|
||||
}
|
||||
|
||||
function createTaskList() {
|
||||
editingCollection.value = new CollectionObject();
|
||||
editingCollection.value.properties.contents = { task: true };
|
||||
collectionEditorMode.value = 'create';
|
||||
collectionEditorType.value = 'tasklist';
|
||||
showCollectionEditor.value = true;
|
||||
}
|
||||
|
||||
function editTaskList(collection: CollectionObject) {
|
||||
editingCollection.value = collection;
|
||||
collectionEditorMode.value = 'edit';
|
||||
collectionEditorType.value = 'tasklist';
|
||||
showCollectionEditor.value = true;
|
||||
}
|
||||
|
||||
function createEvent() {
|
||||
// Select first calendar collection or use selected
|
||||
if (!selectedCollection.value && calendars.value.length > 0) {
|
||||
selectedCollection.value = calendars.value[0];
|
||||
}
|
||||
|
||||
if (!selectedCollection.value) {
|
||||
console.warn('[Chrono] - No calendar collection available');
|
||||
return;
|
||||
}
|
||||
|
||||
selectedEntity.value = new EntityObject();
|
||||
selectedEntity.value.properties = new EventObject();
|
||||
entityEditorMode.value = 'edit';
|
||||
showEventEditor.value = true;
|
||||
}
|
||||
|
||||
function editEvent(entity: EntityObject) {
|
||||
selectedEntity.value = entity;
|
||||
entityEditorMode.value = 'view';
|
||||
showEventEditor.value = true;
|
||||
}
|
||||
|
||||
async function saveEvent(entity: EntityObject, collection?: CollectionObject | null) {
|
||||
try {
|
||||
if (!(collection instanceof CollectionObject)) {
|
||||
collection = selectedCollection.value;
|
||||
}
|
||||
if (!collection) {
|
||||
console.error('[Chrono] - No collection selected');
|
||||
return;
|
||||
}
|
||||
|
||||
const eventData = entity.properties as EventObject;
|
||||
eventData.modified = new Date().toISOString();
|
||||
|
||||
if (!entity.identifier) {
|
||||
eventData.created = new Date().toISOString();
|
||||
selectedEntity.value = await entitiesStore.create(
|
||||
collection.provider,
|
||||
collection.service,
|
||||
collection.identifier,
|
||||
eventData.toJson()
|
||||
);
|
||||
} else {
|
||||
selectedEntity.value = await entitiesStore.update(
|
||||
collection.provider,
|
||||
collection.service,
|
||||
collection.identifier,
|
||||
entity.identifier,
|
||||
eventData.toJson()
|
||||
);
|
||||
}
|
||||
|
||||
entityEditorMode.value = 'view';
|
||||
} catch (error) {
|
||||
console.error('[Chrono] - Failed to save event:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteEvent(entity: EntityObject, collection?: CollectionObject | null) {
|
||||
try {
|
||||
if (!(collection instanceof CollectionObject)) {
|
||||
collection = collections.value.find(c => c.identifier === entity.collection);
|
||||
}
|
||||
if (!collection) {
|
||||
console.error('[Chrono] - No collection found');
|
||||
return;
|
||||
}
|
||||
|
||||
await entitiesStore.delete(collection.provider, collection.service, collection.identifier, entity.identifier);
|
||||
selectedEntity.value = null;
|
||||
entityEditorMode.value = 'view';
|
||||
showEventEditor.value = false;
|
||||
} catch (error) {
|
||||
console.error('[Chrono] - Failed to delete event:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function handleDateClick(date: Date) {
|
||||
// Select first calendar collection or use selected
|
||||
if (!selectedCollection.value && calendars.value.length > 0) {
|
||||
selectedCollection.value = calendars.value[0];
|
||||
}
|
||||
|
||||
if (!selectedCollection.value) {
|
||||
console.warn('[Chrono] - No calendar collection available');
|
||||
return;
|
||||
}
|
||||
|
||||
selectedEntity.value = new EntityObject();
|
||||
selectedEntity.value.properties = new EventObject();
|
||||
const eventData = selectedEntity.value.properties as EventObject;
|
||||
eventData.startsOn = date.toISOString();
|
||||
eventData.endsOn = new Date(date.getTime() + 60 * 60 * 1000).toISOString();
|
||||
entityEditorMode.value = 'edit';
|
||||
showEventEditor.value = true;
|
||||
}
|
||||
|
||||
function handleEditorEdit() {
|
||||
console.log('[Chrono] - Editor editing started');
|
||||
entityEditorMode.value = 'edit';
|
||||
}
|
||||
|
||||
function handleEditorCancel() {
|
||||
console.log('[Chrono] - Editor editing cancelled');
|
||||
entityEditorMode.value = 'view';
|
||||
}
|
||||
|
||||
function handleEditorClose() {
|
||||
console.log('[Chrono] - Editor closed');
|
||||
selectedEntity.value = null;
|
||||
entityEditorMode.value = 'view';
|
||||
showEventEditor.value = false;
|
||||
showTaskEditor.value = false;
|
||||
}
|
||||
|
||||
function createTask() {
|
||||
// Select first task list collection or use selected
|
||||
if (!selectedCollection.value && taskLists.value.length > 0) {
|
||||
selectedCollection.value = taskLists.value[0];
|
||||
}
|
||||
|
||||
if (!selectedCollection.value) {
|
||||
console.warn('[Chrono] - No task list available');
|
||||
return;
|
||||
}
|
||||
|
||||
selectedEntity.value = new EntityObject();
|
||||
selectedEntity.value.properties = new TaskObject();
|
||||
entityEditorMode.value = 'edit';
|
||||
showTaskEditor.value = true;
|
||||
}
|
||||
|
||||
function editTask(entity: EntityObject) {
|
||||
selectedEntity.value = entity;
|
||||
entityEditorMode.value = 'view';
|
||||
showTaskEditor.value = true;
|
||||
}
|
||||
|
||||
async function saveTask(entity: EntityObject, collection?: CollectionObject | null) {
|
||||
try {
|
||||
if (!(collection instanceof CollectionObject)) {
|
||||
collection = selectedCollection.value;
|
||||
}
|
||||
if (!collection) {
|
||||
console.error('[Chrono] - No collection selected');
|
||||
return;
|
||||
}
|
||||
|
||||
const taskData = entity.properties as TaskObject;
|
||||
taskData.modified = new Date().toISOString();
|
||||
|
||||
if (!entity.identifier) {
|
||||
taskData.created = new Date().toISOString();
|
||||
selectedEntity.value = await entitiesStore.create(
|
||||
collection.provider,
|
||||
collection.service,
|
||||
collection.identifier,
|
||||
taskData.toJson()
|
||||
);
|
||||
} else {
|
||||
selectedEntity.value = await entitiesStore.update(
|
||||
collection.provider,
|
||||
collection.service,
|
||||
collection.identifier,
|
||||
entity.identifier,
|
||||
taskData.toJson()
|
||||
);
|
||||
}
|
||||
|
||||
entityEditorMode.value = 'view';
|
||||
} catch (error) {
|
||||
console.error('[Chrono] - Failed to save task:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteTask(entity: EntityObject, collection?: CollectionObject | null) {
|
||||
try {
|
||||
if (!(collection instanceof CollectionObject)) {
|
||||
collection = collections.value.find(c => c.identifier === entity.collection);
|
||||
}
|
||||
if (!collection) {
|
||||
console.error('[Chrono] - No collection found');
|
||||
return;
|
||||
}
|
||||
|
||||
await entitiesStore.delete(collection.provider, collection.service, collection.identifier, entity.identifier);
|
||||
selectedEntity.value = null;
|
||||
entityEditorMode.value = 'view';
|
||||
showTaskEditor.value = false;
|
||||
} catch (error) {
|
||||
console.error('[Chrono] - Failed to delete task:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleTaskComplete(taskId: string | number) {
|
||||
try {
|
||||
const entity = entities.value.find(e => e.identifier === taskId);
|
||||
if (!entity || !entity.properties) return;
|
||||
|
||||
const collection = collections.value.find(c => c.identifier === entity.collection);
|
||||
if (!collection) return;
|
||||
|
||||
const taskData = entity.properties as TaskObject;
|
||||
const isCompleted = taskData.status === 'completed';
|
||||
|
||||
taskData.status = isCompleted ? 'needs-action' : 'completed';
|
||||
taskData.completedOn = isCompleted ? null : new Date().toISOString();
|
||||
taskData.progress = isCompleted ? null : 100;
|
||||
taskData.modified = new Date().toISOString();
|
||||
|
||||
await entitiesStore.update(
|
||||
collection.provider,
|
||||
collection.service,
|
||||
collection.identifier,
|
||||
entity.identifier,
|
||||
taskData.toJson()
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('[Chrono] - Failed to toggle task completion:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function saveCollection(collection: CollectionObject, service: ServiceObject) {
|
||||
try {
|
||||
if (collectionEditorMode.value === 'create') {
|
||||
await collectionsStore.create(
|
||||
service.provider,
|
||||
service.identifier || '',
|
||||
null,
|
||||
collection.properties
|
||||
);
|
||||
console.log('[Chrono] - Created collection:', collection);
|
||||
} else {
|
||||
await collectionsStore.update(
|
||||
collection.provider,
|
||||
collection.service,
|
||||
collection.identifier,
|
||||
collection.properties
|
||||
);
|
||||
console.log('[Chrono] - Modified collection:', collection);
|
||||
}
|
||||
// Reload collections
|
||||
collections.value = Object.values(await collectionsStore.list());
|
||||
} catch (error) {
|
||||
console.error('[Chrono] - Failed to save collection:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteCollection(collection: CollectionObject) {
|
||||
try {
|
||||
await collectionsStore.delete(collection.provider, collection.service, collection.identifier);
|
||||
console.log('[Chrono] - Deleted collection:', collection);
|
||||
// Reload collections
|
||||
collections.value = Object.values(await collectionsStore.list());
|
||||
if (selectedCollection.value?.identifier === collection.identifier) {
|
||||
selectedCollection.value = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Chrono] - Failed to delete collection:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize data from stores
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// Load collections (calendars and task lists)
|
||||
collections.value = Object.values(await collectionsStore.list());
|
||||
|
||||
// Load entities (events and tasks) for available collection sources only
|
||||
const sources = collections.value.reduce<Record<string, Record<string, Record<string | number, true>>>>((acc, collection) => {
|
||||
if (!acc[collection.provider]) {
|
||||
acc[collection.provider] = {};
|
||||
}
|
||||
|
||||
const serviceKey = String(collection.service);
|
||||
if (!acc[collection.provider][serviceKey]) {
|
||||
acc[collection.provider][serviceKey] = {};
|
||||
}
|
||||
|
||||
acc[collection.provider][serviceKey][collection.identifier] = true;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
if (Object.keys(sources).length > 0) {
|
||||
entities.value = Object.values(await entitiesStore.list(sources));
|
||||
} else {
|
||||
entities.value = [];
|
||||
}
|
||||
|
||||
console.log('[Chrono] - Loaded data from ChronoManager:', {
|
||||
collections: collections.value.length,
|
||||
calendars: calendars.value.length,
|
||||
events: events.value.length,
|
||||
tasks: tasks.value.length,
|
||||
taskLists: taskLists.value.length,
|
||||
});
|
||||
syncViewModeFromRoute();
|
||||
await initialize();
|
||||
} catch (error) {
|
||||
console.error('[Chrono] - Failed to load data from ChronoManager:', error);
|
||||
}
|
||||
});
|
||||
|
||||
watch(() => route.fullPath, () => {
|
||||
syncViewModeFromRoute();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -467,33 +120,16 @@ onMounted(async () => {
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<!-- View Toggle -->
|
||||
<v-btn-toggle
|
||||
v-model="viewMode"
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
class="mr-2"
|
||||
>
|
||||
<v-btn value="calendar" size="small">
|
||||
<v-icon>mdi-calendar</v-icon>
|
||||
<span class="ml-1 d-none d-sm-inline">Calendar</span>
|
||||
</v-btn>
|
||||
<v-btn value="tasks" size="small">
|
||||
<v-icon>mdi-checkbox-marked-outline</v-icon>
|
||||
<span class="ml-1 d-none d-sm-inline">Tasks</span>
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
|
||||
<!-- View Switcher for Calendar -->
|
||||
<v-btn-toggle
|
||||
v-if="!isTaskView"
|
||||
v-model="calendarView"
|
||||
:model-value="calendarView"
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
mandatory
|
||||
class="mr-2"
|
||||
@update:model-value="handleCalendarViewChange"
|
||||
>
|
||||
<v-btn value="days" size="small">Days</v-btn>
|
||||
<v-btn value="month" size="small">Month</v-btn>
|
||||
@@ -514,18 +150,20 @@ onMounted(async () => {
|
||||
<div class="pa-4">
|
||||
<CollectionList
|
||||
v-if="!isTaskView"
|
||||
:collections="collections"
|
||||
:selected-collection="selectedCollection"
|
||||
type="calendar"
|
||||
@select="selectCalendar"
|
||||
@edit="editCalendar"
|
||||
@edit="openEditCalendar"
|
||||
@toggle-visibility="toggleCalendarVisibility"
|
||||
/>
|
||||
<CollectionList
|
||||
v-else
|
||||
:collections="collections"
|
||||
:selected-collection="selectedCollection"
|
||||
type="tasklist"
|
||||
@select="selectTaskList"
|
||||
@edit="editTaskList"
|
||||
@edit="openEditTaskList"
|
||||
/>
|
||||
|
||||
<v-btn
|
||||
@@ -534,7 +172,7 @@ onMounted(async () => {
|
||||
color="primary"
|
||||
block
|
||||
class="mt-3"
|
||||
@click="createCalendar"
|
||||
@click="openCreateCalendar"
|
||||
>
|
||||
<v-icon start>mdi-plus</v-icon>
|
||||
New Calendar
|
||||
@@ -545,7 +183,7 @@ onMounted(async () => {
|
||||
color="primary"
|
||||
block
|
||||
class="mt-3"
|
||||
@click="createTaskList"
|
||||
@click="openCreateTaskList"
|
||||
>
|
||||
<v-icon start>mdi-plus</v-icon>
|
||||
New Task List
|
||||
@@ -591,8 +229,12 @@ onMounted(async () => {
|
||||
:current-date="currentDate"
|
||||
:events="filteredEvents"
|
||||
:calendars="calendars"
|
||||
:initial-days-span="daysViewSpan"
|
||||
:initial-agenda-view-span="agendaViewSpan"
|
||||
@event-click="editEvent"
|
||||
@date-click="handleDateClick"
|
||||
@date-click="createEventFromDate"
|
||||
@update:days-span="setDaysViewSpan"
|
||||
@update:agenda-span="setAgendaViewSpan"
|
||||
/>
|
||||
|
||||
<TaskView
|
||||
@@ -615,9 +257,9 @@ onMounted(async () => {
|
||||
:calendars="calendars"
|
||||
@save="saveEvent"
|
||||
@delete="deleteEvent"
|
||||
@edit="handleEditorEdit"
|
||||
@cancel="handleEditorCancel"
|
||||
@close="handleEditorClose"
|
||||
@edit="startEditingSelectedEntity"
|
||||
@cancel="cancelEditingSelectedEntity"
|
||||
@close="closeEntityEditor"
|
||||
/>
|
||||
</v-dialog>
|
||||
|
||||
@@ -631,9 +273,9 @@ onMounted(async () => {
|
||||
:lists="taskLists"
|
||||
@save="saveTask"
|
||||
@delete="deleteTask"
|
||||
@edit="handleEditorEdit"
|
||||
@cancel="handleEditorCancel"
|
||||
@close="handleEditorClose"
|
||||
@edit="startEditingSelectedEntity"
|
||||
@cancel="cancelEditingSelectedEntity"
|
||||
@close="closeEntityEditor"
|
||||
/>
|
||||
</v-dialog>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user