Skip to content

Commit

Permalink
Augment the category menu by system tags and already used categories.
Browse files Browse the repository at this point in the history
This commit add all available "collaborative tags" and all already used
categories into option groups of the tags-menu of the side-bar editor.

Determining the set of already used categories is a little bit ugly: it
used the oc_calendarobject_props table which might be considered
"internal". However, this is the Nextcloud calendar app which only talks
to the Nextcloud calendar server. So using this "internal ingredient"
might be acceptable.

This commit addresses and is a related to a couple of open issues:

nextcloud#3735 Calendar Categories: Propose Categories already used

- this should be fixed by this commit

nextcloud#1644 Add own categories, delete default ones

- this is partly fixed in the sense that collaboritive tags are now also
  proposed as calendar categories.
- still default categories cannot be deleted
- however, using option groups one at least has some sort of overview
  about the origin of the proposed category

nextcloud/server#29950 Save VEVENT CATEGORIES as vcategory

- this issue is totally "ignored" by this commit as the proposed
  solution there is not needed (the categories are already there in the
  oc_calendarobject_props table)
- that would have to be discussed there: but my impression that the
  tables and classed mentioned there are obsolete and no longer used.
  • Loading branch information
rotdrop committed Aug 28, 2024
1 parent 26508f7 commit feac11c
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 22 deletions.
42 changes: 26 additions & 16 deletions lib/Service/CategoriesService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/**
* Calendar App
*
* @copyright 2023 Claus-Justus Heine <himself@claus-justus-heine.de>
* @copyright 2023, 2024 Claus-Justus Heine <himself@claus-justus-heine.de>
*
* @author Claus-Justus Heine <himself@claus-justus-heine.de>
*
Expand Down Expand Up @@ -151,21 +151,31 @@ public function getCategories(): array {
$standardCategories = array_merge($systemTagCategoryLabels, $rfcCategoryLabels);
$customCategoryLabels = array_values(array_filter($this->getUsedCategories(), fn($label) => !in_array($label, $standardCategories)));

$categories = [
[
'group' => $this->l->t('Custom Categories'),
'options' => array_map(fn(string $label) => [ 'label' => $label, 'value' => $label ], $customCategoryLabels),
],
[
'group' => $this->l->t('Collaborative Tags'),
'options' => array_map(fn(string $label) => [ 'label' => $label, 'value' => $label ], $systemTagCategoryLabels),
],
[
'group' => $this->l->t('Standard Categories'),
'options' => array_map(fn(string $label) => [ 'label' => $label, 'value' => $label ], $rfcCategoryLabels),
],
];

// $categories = [
// [
// 'group' => $this->l->t('Custom Categories'),
// 'options' => array_map(fn(string $label) => [ 'label' => $label, 'value' => $label ], $customCategoryLabels),
// ],
// [
// 'group' => $this->l->t('Collaborative Tags'),
// 'options' => array_map(fn(string $label) => [ 'label' => $label, 'value' => $label ], $systemTagCategoryLabels),
// ],
// [
// 'group' => $this->l->t('Standard Categories'),
// 'options' => array_map(fn(string $label) => [ 'label' => $label, 'value' => $label ], $rfcCategoryLabels),
// ],
// ];

// As VueSelect still does not support option groups, provide the
// options as flat arrays and leave it to Vue to style the headings
$categories = array_merge(
[ [ 'label' => $this->l->t('Custom Categories'), 'value' => null, 'isGroupHeading' => true, ], ],
array_map(fn(string $label) => [ 'label' => $label, 'value' => $label, 'isGroupHeading' => false, ], $customCategoryLabels),
[ [ 'label' => $this->l->t('Collaborative Tags'), 'value' => null, 'isGroupHeading' => true, ], ],
array_map(fn(string $label) => [ 'label' => $label, 'value' => $label, 'isGroupHeading' => false, ], $systemTagCategoryLabels),
[ [ 'label' => $this->l->t('Standard Categories'), 'value' => null, 'isGroupHeading' => true, ] ],
array_map(fn(string $label) => [ 'label' => $label, 'value' => $label, 'isGroupHeading' => false, ], $rfcCategoryLabels),
);

return $categories;
}
Expand Down
24 changes: 22 additions & 2 deletions src/components/Editor/Properties/PropertySelectMultiple.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ export default {
type: Boolean,
default: false,
},
customLabelHeading: {
type: String,
default: 'Custom Categories',
},
},
data() {
return {
Expand All @@ -95,6 +99,10 @@ export default {
},
options() {
const options = this.propModel.options.slice()
const customOptionsHeading = options.find(option => option.isGroupHeading && option.label === this.customLabelHeading)
if (!customOptionsHeading) {
options.push({ label: this.customLabelHeading, isGroupHeading: true, value: null })
}
for (const category of (this.selectionData ?? [])) {
if (options.find(option => option.value === category.value)) {
continue
Expand All @@ -104,6 +112,7 @@ export default {
options.push({
value: category.value,
label: category.label,
isGroupHeading: false,
})
}
Expand All @@ -121,14 +130,25 @@ export default {
}
}
return options
.sort((a, b) => {
const groupHeadingIndices = options.reduce((acc, el, i) => el.isGroupHeading ? [...acc, i] : acc, [])
groupHeadingIndices.push(options.length)
let start = groupHeadingIndices.shift() // should be 0
const sorted = []
for (const index of groupHeadingIndices) {
const slice = options.slice(start + 1, index)
slice.sort((a, b) => {
return a.label.localeCompare(
b.label,
getLocale().replace('_', '-'),
{ sensitivity: 'base' },
)
})
sorted.push(options[start])
sorted.splice(start + 1, 0, ...slice)
start = index
}
return sorted
},
},
created() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

<template>
<span class="property-select-multiple-colored-tag">
<div class="property-select-multiple-colored-tag__color-indicator" :style="{ 'background-color': color}" />
<span class="property-select-multiple-colored-tag__label">{{ label }}</span>
<div v-if="!isGroupLabel" class="property-select-multiple-colored-tag__color-indicator" :style="{ 'background-color': color }" />
<span v-if="!isGroupLabel" class="property-select-multiple-colored-tag__label">{{ label }}</span>
<span v-else class="property-select-multiple-colored-tag__group_label">{{ label }}</span>
<div v-if="closeable" class="icon icon-close" @click="deselect" />
</span>
</template>
Expand All @@ -29,6 +30,9 @@ export default {
},
emits: ['deselect'],
computed: {
isGroupLabel() {
return typeof this.option !== 'string' && this.option.isGroupHeading
},
label() {
const option = this.option
logger.debug('Option render', { option })
Expand Down
6 changes: 6 additions & 0 deletions src/mixins/EditorMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import useCalendarsStore from '../store/calendars.js'
import useCalendarObjectsStore from '../store/calendarObjects.js'
import useCalendarObjectInstanceStore from '../store/calendarObjectInstance.js'
import { mapStores, mapState } from 'pinia'
import { loadState } from '@nextcloud/initial-state'

/**
* This is a mixin for the editor. It contains common Vue stuff, that is
Expand Down Expand Up @@ -297,6 +298,11 @@ export default {
rfcProps() {
return getRFCProperties()
},
categoryOptions() {
const categories = { ...this.rfcProps.categories }
categories.options = loadState('calendar', 'categories')
return categories
},
/**
* Returns whether or not this event can be downloaded from the server
*
Expand Down
3 changes: 2 additions & 1 deletion src/views/EditSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,9 @@

<PropertySelectMultiple :colored-options="true"
:is-read-only="isReadOnly"
:prop-model="rfcProps.categories"
:prop-model="categoryOptions"
:value="categories"
:custom-label-heading="t('calendar', 'Custom Categories')"
@add-single-value="addCategory"
@remove-single-value="removeCategory" />

Expand Down
3 changes: 2 additions & 1 deletion src/views/EditSimple.vue
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,9 @@
@update:value="updateDescription" />
<PropertySelectMultiple :colored-options="true"
:is-read-only="isReadOnly"
:prop-model="rfcProps.categories"
:prop-model="categoryOptions"
:value="categories"
:custom-label-heading="t('calendar', 'Custom Categories')"
@add-single-value="addCategory"
@remove-single-value="removeCategory" />

Expand Down

0 comments on commit feac11c

Please sign in to comment.