diff --git a/src/components/EventEditor.vue b/src/components/EventEditor.vue
index 4c65cb5..739fb53 100644
--- a/src/components/EventEditor.vue
+++ b/src/components/EventEditor.vue
@@ -49,6 +49,10 @@ const calendarOptions = computed(() =>
}))
)
+const selectedCalendar = computed(() =>
+ (props.calendars || []).find(calendar => calendar.identifier === selectedCollectionId.value) ?? null
+)
+
// Permissions
const isExternalEvent = computed(() => {
return false
@@ -77,13 +81,12 @@ const cancelEdit = () => {
}
const saveEntity = async () => {
- if (!editableEntity.value) {
+ if (!editableEntity.value || !selectedCalendar.value) {
return
}
saving.value = true
- const targetCollection = (props.calendars || []).find(cal => cal.identifier === selectedCollectionId.value)
- emit('save', editableEntity.value as EntityObject, targetCollection || props.collection)
+ emit('save', editableEntity.value as EntityObject, selectedCalendar.value)
saving.value = false
}
@@ -127,7 +130,7 @@ watch(
(newEntity) => {
const entity = newEntity as EntityObject | null
draftEntity.value = entity?.clone ? entity.clone() : null
- selectedCollectionId.value = entity?.collection || props.collection?.identifier || props.calendars?.[0]?.identifier || ''
+ selectedCollectionId.value = entity?.collection || props.collection?.identifier || ''
},
{ immediate: true },
)
@@ -138,7 +141,7 @@ watch(
const entity = props.entity as EntityObject | null
if (newMode === 'edit' && entity?.clone) {
draftEntity.value = entity.clone()
- selectedCollectionId.value = entity.collection || props.collection?.identifier || props.calendars?.[0]?.identifier || ''
+ selectedCollectionId.value = entity.collection || props.collection?.identifier || ''
}
},
)
@@ -194,6 +197,7 @@ watch(
v-model="selectedCollectionId"
:items="calendarOptions"
label="Calendar"
+ :rules="[value => (value !== '' && value != null) || 'Calendar is required']"
variant="outlined"
density="compact"
class="mb-4"
@@ -293,6 +297,7 @@ watch(
color="primary"
variant="elevated"
@click="saveEntity"
+ :disabled="!selectedCalendar"
:loading="saving">
Save
diff --git a/src/components/TaskEditor.vue b/src/components/TaskEditor.vue
index 2c5ef2d..af9f2ea 100644
--- a/src/components/TaskEditor.vue
+++ b/src/components/TaskEditor.vue
@@ -34,6 +34,7 @@
v-model="selectedCollectionId"
:items="listOptions"
label="Task List"
+ :rules="[value => (value !== '' && value != null) || 'Task list is required']"
:readonly="!isEditing || !canChangeCollection"
:variant="isEditing && canChangeCollection ? 'outlined' : 'plain'"
class="mb-4"
@@ -243,13 +244,13 @@ watch(() => props.entity, (newEntity) => {
startDate.value = '';
}
- selectedCollectionId.value = draftEntity.value?.collection || props.collection?.identifier || props.lists[0]?.identifier || '';
+ selectedCollectionId.value = draftEntity.value?.collection || props.collection?.identifier || '';
}, { immediate: true });
watch(() => props.mode, (newMode) => {
if (newMode === 'edit' && props.entity) {
draftEntity.value = cloneEntity(props.entity);
- selectedCollectionId.value = draftEntity.value?.collection || props.collection?.identifier || props.lists[0]?.identifier || '';
+ selectedCollectionId.value = draftEntity.value?.collection || props.collection?.identifier || '';
}
});
@@ -260,6 +261,10 @@ const listOptions = computed(() =>
}))
);
+const selectedTaskList = computed(() =>
+ props.lists.find(list => list.identifier === selectedCollectionId.value) ?? null
+);
+
const priorityOptions = [
{ title: 'Low', value: 3 },
{ title: 'Medium', value: 2 },
@@ -288,8 +293,9 @@ async function handleSave() {
const { valid } = await formRef.value.validate();
if (!valid) return;
- const targetCollection = props.lists.find(list => list.identifier === selectedCollectionId.value);
- emit('save', editableEntity.value as EntityObject, targetCollection || props.collection);
+ if (!selectedTaskList.value) return;
+
+ emit('save', editableEntity.value as EntityObject, selectedTaskList.value);
}
function handleCancel() {
diff --git a/src/pages/ChronoPage.vue b/src/pages/ChronoPage.vue
index bf468f5..8aa62ef 100644
--- a/src/pages/ChronoPage.vue
+++ b/src/pages/ChronoPage.vue
@@ -1,4 +1,3 @@
-
@@ -218,7 +213,7 @@ watch(() => route.fullPath, async () => {
:selected-collection="selectedCollection"
type="calendar"
@select="selectCollection"
- @edit="openEditCalendar"
+ @edit="openCollectionEditor('calendar', $event)"
@toggle-visibility="toggleCalendarVisibility"
/>
route.fullPath, async () => {
:selected-collection="selectedCollection"
type="tasklist"
@select="selectCollection"
- @edit="openEditTaskList"
+ @edit="openCollectionEditor('tasklist', $event)"
/>
route.fullPath, async () => {
color="primary"
block
class="mt-3"
- @click="openCreateCalendar"
+ @click="openCollectionEditor('calendar')"
>
mdi-plus
New Calendar
@@ -248,17 +243,17 @@ watch(() => route.fullPath, async () => {
color="primary"
block
class="mt-3"
- @click="openCreateTaskList"
+ @click="openCollectionEditor('tasklist')"
>
mdi-plus
New Task List
-
+
Import iCalendar
-
+
@@ -307,8 +302,8 @@ watch(() => route.fullPath, async () => {
@event-click="editEvent"
@date-click="createEventFromDate"
@update:current-date="selectDate"
- @update:days-span="setDaysViewSpan"
- @update:agenda-span="setAgendaViewSpan"
+ @update:days-span="handleCalendarDaysViewSpanChange"
+ @update:agenda-span="handleCalendarAgendaViewSpanChange"
/>
{
selectedCollection.value = collection
}
- function openCollectionEditor(type: 'calendar' | 'tasklist') {
- const collection = new CollectionObject()
- collection.properties.fromJson({
- ...collection.properties.toJson(),
- content: [type === 'calendar' ? 'event' : 'task'],
- })
- editingCollection.value = collection
- collectionEditorMode.value = 'create'
+ function openCollectionEditor(type: 'calendar' | 'tasklist', collection?: CollectionObject) {
+ const target = collection ?? new CollectionObject()
+ if (!collection) {
+ target.properties.fromJson({
+ ...target.properties.toJson(),
+ content: [type === 'calendar' ? 'event' : 'task'],
+ })
+ }
+
+ editingCollection.value = target
+ collectionEditorMode.value = collection ? 'edit' : 'create'
collectionEditorType.value = type
showCollectionEditor.value = true
}
- function openCreateCalendar() {
- openCollectionEditor('calendar')
- }
-
- function openCreateTaskList() {
- openCollectionEditor('tasklist')
- }
-
- function openEditCalendar(collection: CollectionObject) {
- editingCollection.value = collection
- collectionEditorMode.value = 'edit'
- collectionEditorType.value = 'calendar'
- showCollectionEditor.value = true
- }
-
- function openEditTaskList(collection: CollectionObject) {
- editingCollection.value = collection
- collectionEditorMode.value = 'edit'
- collectionEditorType.value = 'tasklist'
- showCollectionEditor.value = true
- }
-
- function ensureSelectedCollection(type: 'calendar' | 'tasklist'): CollectionObject | null {
- const candidates = type === 'calendar' ? operationsStore.calendars : operationsStore.taskLists
- if (!selectedCollection.value && candidates.length > 0) selectedCollection.value = candidates[0]
- return selectedCollection.value
- }
-
function openEntityEditor(entity: EntityObject, type: 'event' | 'task', mode: 'edit' | 'view') {
selectedEntity.value = entity
entityEditorMode.value = mode
@@ -87,8 +62,6 @@ export const useChronoUiStore = defineStore('chronoUiStore', () => {
}
function createEventFromDate(date?: Date) {
- if (!ensureSelectedCollection('calendar')) return
-
const entity = new EntityObject()
entity.properties = new EventObject()
if (date) {
@@ -107,8 +80,6 @@ export const useChronoUiStore = defineStore('chronoUiStore', () => {
}
function createTask() {
- if (!ensureSelectedCollection('tasklist')) return
-
const entity = new EntityObject()
entity.properties = new TaskObject()
openEntityEditor(entity, 'task', 'edit')
@@ -217,10 +188,7 @@ export const useChronoUiStore = defineStore('chronoUiStore', () => {
selectSection,
selectDate,
selectCollection,
- openCreateCalendar,
- openCreateTaskList,
- openEditCalendar,
- openEditTaskList,
+ openCollectionEditor,
createEvent,
editEvent,
createTask,