Skip to content

Commit

Permalink
feat(systemtags): add color support
Browse files Browse the repository at this point in the history
Signed-off-by: skjnldsv <[email protected]>
  • Loading branch information
skjnldsv committed Nov 14, 2024
1 parent 51a2dff commit 373e8a2
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 53 deletions.
5 changes: 5 additions & 0 deletions apps/dav/lib/SystemTag/SystemTagPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
public const NUM_FILES_PROPERTYNAME = '{http://nextcloud.org/ns}files-assigned';
public const REFERENCE_FILEID_PROPERTYNAME = '{http://nextcloud.org/ns}reference-fileid';
public const OBJECTIDS_PROPERTYNAME = '{http://nextcloud.org/ns}object-ids';
public const COLOR_PROPERTYNAME = '{http://nextcloud.org/ns}color';

/**
* @var \Sabre\DAV\Server $server
Expand Down Expand Up @@ -243,6 +244,10 @@ public function handleGetProperties(
return $this->tagManager->canUserAssignTag($node->getSystemTag(), $this->userSession->getUser()) ? 'true' : 'false';
});

$propFind->handle(self::COLOR_PROPERTYNAME, function () use ($node) {
return $node->getSystemTag()->getColor() ?? '';
});

$propFind->handle(self::GROUPS_PROPERTYNAME, function () use ($node) {
if (!$this->groupManager->isAdmin($this->userSession->getUser()->getUID())) {
// property only available for admins
Expand Down
2 changes: 1 addition & 1 deletion apps/dav/lib/SystemTag/SystemTagsInUseCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public function getChildren(): array {
$result = $this->systemTagsInFilesDetector->detectAssignedSystemTagsIn($userFolder, $this->mediaType);
$children = [];
foreach ($result as $tagData) {
$tag = new SystemTag((string)$tagData['id'], $tagData['name'], (bool)$tagData['visibility'], (bool)$tagData['editable'], $tagData['etag']);
$tag = new SystemTag((string)$tagData['id'], $tagData['name'], (bool)$tagData['visibility'], (bool)$tagData['editable'], $tagData['etag'], $tagData['color']);
// read only, so we can submit the isAdmin parameter as false generally
$node = new SystemTagNode($tag, $user, false, $this->systemTagManager, $this->tagMapper);
$node->setNumberOfFiles((int)$tagData['number_files']);
Expand Down
2 changes: 2 additions & 0 deletions apps/systemtags/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
'OCA\\SystemTags\\Listeners\\BeforeSabrePubliclyLoadedListener' => $baseDir . '/../lib/Listeners/BeforeSabrePubliclyLoadedListener.php',
'OCA\\SystemTags\\Listeners\\BeforeTemplateRenderedListener' => $baseDir . '/../lib/Listeners/BeforeTemplateRenderedListener.php',
'OCA\\SystemTags\\Listeners\\LoadAdditionalScriptsListener' => $baseDir . '/../lib/Listeners/LoadAdditionalScriptsListener.php',
'OCA\\SystemTags\\Migration\\Version31000Date20241018063111' => $baseDir . '/../lib/Migration/Version31000Date20241018063111.php',
'OCA\\SystemTags\\Migration\\Version31000Date20241114171300' => $baseDir . '/../lib/Migration/Version31000Date20241114171300.php',
'OCA\\SystemTags\\Search\\TagSearchProvider' => $baseDir . '/../lib/Search/TagSearchProvider.php',
'OCA\\SystemTags\\Settings\\Admin' => $baseDir . '/../lib/Settings/Admin.php',
);
2 changes: 2 additions & 0 deletions apps/systemtags/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class ComposerStaticInitSystemTags
'OCA\\SystemTags\\Listeners\\BeforeSabrePubliclyLoadedListener' => __DIR__ . '/..' . '/../lib/Listeners/BeforeSabrePubliclyLoadedListener.php',
'OCA\\SystemTags\\Listeners\\BeforeTemplateRenderedListener' => __DIR__ . '/..' . '/../lib/Listeners/BeforeTemplateRenderedListener.php',
'OCA\\SystemTags\\Listeners\\LoadAdditionalScriptsListener' => __DIR__ . '/..' . '/../lib/Listeners/LoadAdditionalScriptsListener.php',
'OCA\\SystemTags\\Migration\\Version31000Date20241018063111' => __DIR__ . '/..' . '/../lib/Migration/Version31000Date20241018063111.php',
'OCA\\SystemTags\\Migration\\Version31000Date20241114171300' => __DIR__ . '/..' . '/../lib/Migration/Version31000Date20241114171300.php',
'OCA\\SystemTags\\Search\\TagSearchProvider' => __DIR__ . '/..' . '/../lib/Search/TagSearchProvider.php',
'OCA\\SystemTags\\Settings\\Admin' => __DIR__ . '/..' . '/../lib/Settings/Admin.php',
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OC\Core\Migrations;
namespace OCA\SystemTags\Migration;

use Closure;
use Doctrine\DBAL\Types\Types;
Expand All @@ -26,12 +26,6 @@
#[AddIndex(table: 'systemtag_object_mapping', type: IndexType::INDEX, description: 'Adding objecttype index to systemtag_object_mapping')]
class Version31000Date20241018063111 extends SimpleMigrationStep {

/**
* @param IOutput $output
* @param Closure(): ISchemaWrapper $schemaClosure
* @param array $options
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
Expand Down
43 changes: 43 additions & 0 deletions apps/systemtags/lib/Migration/Version31000Date20241114171300.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\SystemTags\Migration;

use Closure;
use Doctrine\DBAL\Types\Types;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\Attributes\AddColumn;
use OCP\Migration\Attributes\ColumnType;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

/**
* Add objecttype index to systemtag_object_mapping
*/
#[AddColumn(table: 'systemtag', name: 'color', type: ColumnType::STRING, description: 'Adding color for systemtag table')]
class Version31000Date20241114171300 extends SimpleMigrationStep {

public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();

if ($schema->hasTable('systemtag')) {
$table = $schema->getTable('systemtag');

if (!$table->hasColumn('color')) {
$table->addColumn('color', Types::STRING, [
'notnull' => false,
'length' => 6,
]);
}
}

return $schema;
}
}
105 changes: 80 additions & 25 deletions apps/systemtags/src/components/SystemTagPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,48 @@
</div>

<!-- Tags list -->
<div class="systemtags-picker__tags"
<ul class="systemtags-picker__tags"
data-cy-systemtags-picker-tags>
<NcCheckboxRadioSwitch v-for="tag in filteredTags"
<li v-for="tag in filteredTags"
:key="tag.id"
:label="tag.displayName"
:checked="isChecked(tag)"
:indeterminate="isIndeterminate(tag)"
:disabled="!tag.canAssign"
:data-cy-systemtags-picker-tag="tag.id"
class="systemtags-picker__tag"
@update:checked="onCheckUpdate(tag, $event)">
{{ formatTagName(tag) }}
</NcCheckboxRadioSwitch>
<NcButton v-if="canCreateTag"
:disabled="status === Status.CREATING_TAG"
alignment="start"
class="systemtags-picker__tag-create"
native-type="submit"
type="tertiary"
data-cy-systemtags-picker-button-create
@click="onNewTag">
{{ input.trim() }}<br>
<span class="systemtags-picker__tag-create-subline">{{ t('systemtags', 'Create new tag') }}</span>
<template #icon>
<PlusIcon />
</template>
</NcButton>
</div>
:style="{'--color-primary-element': tag.color ? `#${tag.color}` : null}"
class="systemtags-picker__tag">
<NcCheckboxRadioSwitch :checked="isChecked(tag)"
:disabled="!tag.canAssign"
:indeterminate="isIndeterminate(tag)"
:label="tag.displayName"
class="systemtags-picker__tag-checkbox"
@update:checked="onCheckUpdate(tag, $event)">
{{ formatTagName(tag) }}
</NcCheckboxRadioSwitch>

<!-- Color picker -->
<NcColorPicker v-slot="{ attrs }"
:data-cy-systemtags-picker-tag-color="tag.id"
:value="tag.color ? `#${tag.color}` : primaryColor"
class="systemtags-picker__tag-color"
@update:value="onColorChange(tag, $event)">
<CircleIcon v-bind="attrs" :size="24" />
</NcColorPicker>
</li>
<li>
<NcButton v-if="canCreateTag"
:disabled="status === Status.CREATING_TAG"
alignment="start"
class="systemtags-picker__tag-create"
native-type="submit"
type="tertiary"
data-cy-systemtags-picker-button-create
@click="onNewTag">
{{ input.trim() }}<br>
<span class="systemtags-picker__tag-create-subline">{{ t('systemtags', 'Create new tag') }}</span>
<template #icon>
<PlusIcon />
</template>
</NcButton>
</li>
</ul>

<!-- Note -->
<div class="systemtags-picker__note">
Expand Down Expand Up @@ -104,12 +118,14 @@ import { defineComponent } from 'vue'
import { emit } from '@nextcloud/event-bus'
import { sanitize } from 'dompurify'
import { showError, showInfo } from '@nextcloud/dialogs'
import { getCapabilities } from '@nextcloud/capabilities'
import { getLanguage, n, t } from '@nextcloud/l10n'
import escapeHTML from 'escape-html'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
import NcChip from '@nextcloud/vue/dist/Components/NcChip.js'
import NcColorPicker from '@nextcloud/vue/dist/Components/NcColorPicker.js'
import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js'
import NcEmptyContent from '@nextcloud/vue/dist/Components/NcEmptyContent.js'
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
Expand All @@ -118,11 +134,14 @@ import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import TagIcon from 'vue-material-design-icons/Tag.vue'
import CheckIcon from 'vue-material-design-icons/CheckCircle.vue'
import PlusIcon from 'vue-material-design-icons/Plus.vue'
import CircleIcon from 'vue-material-design-icons/Circle.vue'
import { getNodeSystemTags, setNodeSystemTags } from '../utils'
import { createTag, fetchTag, fetchTags, getTagObjects, setTagObjects } from '../services/api'
import logger from '../services/logger'
const primaryColor = getCapabilities()?.theming?.['color-element'] || '#00679e'
type TagListCount = {
string: number
}
Expand All @@ -143,13 +162,15 @@ export default defineComponent({
NcCheckboxRadioSwitch,
// eslint-disable-next-line vue/no-unused-components
NcChip,
NcColorPicker,
NcDialog,
NcEmptyContent,
NcLoadingIcon,
NcNoteCard,
NcTextField,
PlusIcon,
TagIcon,
CircleIcon,
},
props: {
Expand All @@ -162,6 +183,7 @@ export default defineComponent({
setup() {
return {
emit,
primaryColor,
Status,
t,
}
Expand Down Expand Up @@ -345,6 +367,10 @@ export default defineComponent({
return tag.displayName
},
onColorChange(tag: TagWithId, color: string) {
tag.color = color.replace('#', '')
},
isChecked(tag: TagWithId): boolean {
return tag.displayName in this.tagList
&& this.tagList[tag.displayName] === this.nodes.length
Expand Down Expand Up @@ -506,6 +532,35 @@ export default defineComponent({
gap: var(--default-grid-baseline);
display: flex;
flex-direction: column;
li {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
// Make switch full width
:deep(.checkbox-radio-switch) {
width: 100%;
.checkbox-content {
// adjust width
max-width: none;
// recalculate padding
box-sizing: border-box;
min-height: calc(var(--default-grid-baseline) * 2 + var(--default-clickable-area));
}
}
}
.systemtags-picker__tag-color {
margin-inline-start: var(--default-grid-baseline);
color: var(--color-primary-element);
width: var(--default-clickable-area);
height: var(--default-clickable-area);
display: flex;
}
.systemtags-picker__tag-create {
:deep(span) {
text-align: start;
Expand Down
3 changes: 2 additions & 1 deletion apps/systemtags/src/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ import { formatTag, parseIdFromLocation, parseTags } from '../utils'
import { logger } from '../logger.js'

export const fetchTagsPayload = `<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
<d:prop>
<oc:id />
<oc:display-name />
<oc:user-visible />
<oc:user-assignable />
<oc:can-assign />
<d:getetag />
<nc:color />
</d:prop>
</d:propfind>`

Expand Down
2 changes: 2 additions & 0 deletions apps/systemtags/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export interface BaseTag {
userVisible: boolean
userAssignable: boolean
readonly canAssign: boolean // Computed server-side
etag?: string
color?: string
}

export type Tag = BaseTag & {
Expand Down
23 changes: 5 additions & 18 deletions lib/private/SystemTag/SystemTag.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,26 @@ public function __construct(
private bool $userVisible,
private bool $userAssignable,
private ?string $etag = null,
private ?string $color = null
) {
}

/**
* {@inheritdoc}
*/
public function getId(): string {
return $this->id;
}

/**
* {@inheritdoc}
*/
public function getName(): string {
return $this->name;
}

/**
* {@inheritdoc}
*/
public function isUserVisible(): bool {
return $this->userVisible;
}

/**
* {@inheritdoc}
*/
public function isUserAssignable(): bool {
return $this->userAssignable;
}

/**
* {@inheritdoc}
*/
public function getAccessLevel(): int {
if (!$this->userVisible) {
return self::ACCESS_LEVEL_INVISIBLE;
Expand All @@ -63,10 +49,11 @@ public function getAccessLevel(): int {
return self::ACCESS_LEVEL_PUBLIC;
}

/**
* {@inheritdoc}
*/
public function getETag(): ?string {
return $this->etag;
}

public function getColor(): ?string {
return $this->color;
}
}
2 changes: 1 addition & 1 deletion lib/private/SystemTag/SystemTagManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ public function canUserSeeTag(ISystemTag $tag, ?IUser $user): bool {
}

private function createSystemTagFromRow($row): SystemTag {
return new SystemTag((string)$row['id'], $row['name'], (bool)$row['visibility'], (bool)$row['editable'], $row['etag']);
return new SystemTag((string)$row['id'], $row['name'], (bool)$row['visibility'], (bool)$row['editable'], $row['etag'], $row['color']);
}

/**
Expand Down
7 changes: 7 additions & 0 deletions lib/public/SystemTag/ISystemTag.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,11 @@ public function getAccessLevel(): int;
* @since 31.0.0
*/
public function getETag(): ?string;

/**
* Returns the color of the tag
*
* @since 31.0.0
*/
public function getColor(): ?string;
}

0 comments on commit 373e8a2

Please sign in to comment.