Skip to content

Commit

Permalink
zsh:1: command not found: :wq
Browse files Browse the repository at this point in the history
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
  • Loading branch information
skjnldsv committed Dec 4, 2024
1 parent 5cc9574 commit 5445107
Show file tree
Hide file tree
Showing 11 changed files with 484 additions and 320 deletions.
2 changes: 1 addition & 1 deletion apps/systemtags/appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<summary>Collaborative tagging functionality which shares tags among people.</summary>
<description>Collaborative tagging functionality which shares tags among people. Great for teams.
(If you are a provider with a multi-tenancy installation, it is advised to deactivate this app as tags are shared.)</description>
<version>1.21.0</version>
<version>1.21.1</version>
<licence>agpl</licence>
<author>Vincent Petry</author>
<author>Joas Schilling</author>
Expand Down
166 changes: 138 additions & 28 deletions apps/systemtags/src/components/SystemTagPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,55 @@
</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="tagListStyle(tag)"
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 :data-cy-systemtags-picker-tag-color="tag.id"
:value="`#${tag.color}`"
class="systemtags-picker__tag-color"
@update:value="onColorChange(tag, $event)">
<NcButton :aria-label="t('systemtags', 'Change tag color')" type="tertiary">
<template #icon>
<CircleIcon v-if="tag.color" :size="24" fill-color="var(--color-circle-icon)" />
<CircleOutlineIcon v-else :size="24" fill-color="var(--color-circle-icon)" />
<PencilIcon />
</template>
</NcButton>
</NcColorPicker>
</li>

<!-- Create new tag -->
<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 @@ -110,19 +131,28 @@ 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'
import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
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 CircleIcon from 'vue-material-design-icons/Circle.vue'
import CircleOutlineIcon from 'vue-material-design-icons/CircleOutline.vue'
import PencilIcon from 'vue-material-design-icons/Pencil.vue'
import PlusIcon from 'vue-material-design-icons/Plus.vue'
import TagIcon from 'vue-material-design-icons/Tag.vue'

import { createTag, fetchTag, fetchTags, getTagObjects, setTagObjects, updateTag } from '../services/api'
import { getNodeSystemTags, setNodeSystemTags } from '../utils'
import { createTag, fetchTag, fetchTags, getTagObjects, setTagObjects } from '../services/api'
import { elementColor, invertTextColor, isDarkModeEnabled } from '../utils/colorUtils'
import logger from '../services/logger'

const mainBackgroundColor = getComputedStyle(document.body)
.getPropertyValue('--color-main-background')
.replace('#', '') || (isDarkModeEnabled() ? '000000' : 'ffffff')

type TagListCount = {
string: number
}
Expand All @@ -139,15 +169,19 @@ export default defineComponent({

components: {
CheckIcon,
CircleIcon,
CircleOutlineIcon,
NcButton,
NcCheckboxRadioSwitch,
// eslint-disable-next-line vue/no-unused-components
NcChip,
NcColorPicker,
NcDialog,
NcEmptyContent,
NcLoadingIcon,
NcNoteCard,
NcTextField,
PencilIcon,
PlusIcon,
TagIcon,
},
Expand Down Expand Up @@ -329,7 +363,14 @@ export default defineComponent({
// Format & sanitize a tag chip for v-html tag rendering
formatTagChip(tag: TagWithId): string {
const chip = this.$refs.chip as NcChip
const chipHtml = chip.$el.outerHTML
const chipCloneEl = chip.$el.cloneNode(true) as HTMLElement
if (tag.color) {
const style = this.tagListStyle(tag)
Object.entries(style).forEach(([key, value]) => {
chipCloneEl.style.setProperty(key, value)
})
}
const chipHtml = chipCloneEl.outerHTML
return chipHtml.replace('%s', escapeHTML(sanitize(tag.displayName)))
},

Expand All @@ -345,6 +386,11 @@ export default defineComponent({
return tag.displayName
},

onColorChange(tag: TagWithId, color: string) {
tag.color = color.replace('#', '')
updateTag(tag)
},

isChecked(tag: TagWithId): boolean {
return tag.displayName in this.tagList
&& this.tagList[tag.displayName] === this.nodes.length
Expand Down Expand Up @@ -480,6 +526,28 @@ export default defineComponent({
showInfo(t('systemtags', 'File tags modification canceled'))
this.$emit('close', null)
},

tagListStyle(tag: TagWithId): Record<string, string> {
// No color, no style
if (!tag.color) {
return {
// See inline system tag color
'--color-circle-icon': 'var(--color-text-maxcontrast)',
}
}

// Make the checkbox color the same as the tag color
// as well as the circle icon color picker
const primaryElement = elementColor(`#${tag.color}`, `#${mainBackgroundColor}`)
const textColor = invertTextColor(primaryElement) ? '#000000' : '#ffffff'
return {
'--color-circle-icon': 'var(--color-primary-element)',
'--color-primary': primaryElement,
'--color-primary-text': textColor,
'--color-primary-element': primaryElement,
'--color-primary-element-text': textColor,
}
},
},
})
</script>
Expand All @@ -506,6 +574,48 @@ 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 button {
margin-inline-start: calc(var(--default-grid-baseline) * 2);

span.pencil-icon {
display: none;
color: var(--color-main-text);
}

&:focus,
&:hover,
&[aria-expanded='true'] {
.pencil-icon {
display: block;
}
.circle-icon,
.circle-outline-icon {
display: none;
}
}
}

.systemtags-picker__tag-create {
:deep(span) {
text-align: start;
Expand Down
10 changes: 9 additions & 1 deletion apps/systemtags/src/css/fileEntryInlineSystemTags.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 22px; // min-size - 2 * 5px padding
line-height: 20px; // min-size - 2 * 5px padding - 2 * 1px border
text-align: center;

&--more {
Expand All @@ -34,6 +34,14 @@
& + .files-list__system-tag {
margin-inline-start: 5px;
}

// With color
&[data-systemtag-color] {
border-color: var(--systemtag-color);
color: var(--systemtag-color);
border-width: 2px;
line-height: 18px; // min-size - 2 * 5px padding - 2 * 2px border
}
}

@media (min-width: 512px) {
Expand Down
4 changes: 4 additions & 0 deletions apps/systemtags/src/event-bus.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { Node } from '@nextcloud/files'
import type { TagWithId } from './types'

declare module '@nextcloud/event-bus' {
interface NextcloudEvents {
'systemtags:node:updated': Node
'systemtags:tag:deleted': TagWithId
'systemtags:tag:updated': TagWithId
'systemtags:tag:created': TagWithId
}
}

Expand Down
17 changes: 14 additions & 3 deletions apps/systemtags/src/files_actions/inlineSystemTagsAction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { action } from './inlineSystemTagsAction'
import { describe, expect, test } from 'vitest'
import { File, Permission, View, FileAction } from '@nextcloud/files'
import { beforeEach, describe, expect, test, vi } from 'vitest'
import { emit, subscribe } from '@nextcloud/event-bus'
import { File, Permission, View, FileAction } from '@nextcloud/files'
import { setNodeSystemTags } from '../utils'
import * as serviceTagApi from '../services/api'
import { set } from 'lodash'

const view = {
id: 'files',
Expand Down Expand Up @@ -53,6 +55,13 @@ describe('Inline system tags action conditions tests', () => {
})

describe('Inline system tags action render tests', () => {

beforeEach(() => {
vi.spyOn(serviceTagApi, 'fetchTags').mockImplementation(async () => {
return []
})
})

test('Render something even when Node does not have system tags', async () => {
const file = new File({
id: 1,
Expand Down Expand Up @@ -165,7 +174,9 @@ describe('Inline system tags action render tests', () => {

// Subscribe to the event
const eventPromise = new Promise((resolve) => {
subscribe('systemtags:node:updated', resolve)
subscribe('systemtags:node:updated', () => {
setTimeout(resolve, 100)
})
})

// Change tags
Expand Down
Loading

0 comments on commit 5445107

Please sign in to comment.