mirror of
https://github.com/nextcloud/server.git
synced 2026-03-12 13:44:53 -04:00
Merge pull request #57865 from nextcloud/backport/57855/stable33
[stable33] refactor(systemtags): migrate to Vue 3 and `script setup`
This commit is contained in:
commit
f878a4e14f
385 changed files with 1518 additions and 2606 deletions
|
|
@ -1,8 +1,9 @@
|
|||
import type { Node } from '@nextcloud/files'
|
||||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Node } from '@nextcloud/files'
|
||||
import type { FileStat, ResponseDataDetailed } from 'webdav'
|
||||
|
||||
import { getClient, getDefaultPropfind, getRootPath, resultToNode } from '@nextcloud/files/dav'
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ use OCP\BeforeSabrePubliclyLoadedEvent;
|
|||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\SystemTag\ManagerEvent;
|
||||
use OCP\SystemTag\MapperEvent;
|
||||
use OCP\Util;
|
||||
|
||||
class Application extends App implements IBootstrap {
|
||||
public const APP_ID = 'systemtags';
|
||||
|
|
@ -43,16 +42,6 @@ class Application extends App implements IBootstrap {
|
|||
|
||||
public function boot(IBootContext $context): void {
|
||||
$context->injectFn(function (IEventDispatcher $dispatcher) use ($context): void {
|
||||
/*
|
||||
* @todo move the OCP events and then move the registration to `register`
|
||||
*/
|
||||
$dispatcher->addListener(
|
||||
LoadAdditionalScriptsEvent::class,
|
||||
function (): void {
|
||||
Util::addInitScript(self::APP_ID, 'init');
|
||||
}
|
||||
);
|
||||
|
||||
$managerListener = function (ManagerEvent $event) use ($context): void {
|
||||
/** @var Listener $listener */
|
||||
$listener = $context->getServerContainer()->query(Listener::class);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class BeforeTemplateRenderedListener implements IEventListener {
|
|||
return;
|
||||
}
|
||||
Util::addInitScript(Application::APP_ID, 'init');
|
||||
Util::addStyle(Application::APP_ID, 'init');
|
||||
|
||||
$restrictSystemTagsCreationToAdmin = $this->appConfig->getValueBool(Application::APP_ID, 'restrict_creation_to_admin', false);
|
||||
$this->initialState->provideInitialState('restrictSystemTagsCreationToAdmin', $restrictSystemTagsCreationToAdmin);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class LoadAdditionalScriptsListener implements IEventListener {
|
|||
return;
|
||||
}
|
||||
Util::addInitScript(Application::APP_ID, 'init');
|
||||
Util::addStyle(Application::APP_ID, 'init');
|
||||
|
||||
$restrictSystemTagsCreationToAdmin = $this->appConfig->getValueBool(Application::APP_ID, 'restrict_creation_to_admin', false);
|
||||
$this->initialState->provideInitialState('restrictSystemTagsCreationToAdmin', $restrictSystemTagsCreationToAdmin);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ class Admin implements ISettings {
|
|||
$restrictSystemTagsCreationToAdmin = $this->appConfig->getValueBool(Application::APP_ID, 'restrict_creation_to_admin', false);
|
||||
$this->initialStateService->provideInitialState('restrictSystemTagsCreationToAdmin', $restrictSystemTagsCreationToAdmin);
|
||||
|
||||
Util::addScript('systemtags', 'admin');
|
||||
return new TemplateResponse('systemtags', 'admin', [], '');
|
||||
Util::addStyle(Application::APP_ID, 'admin');
|
||||
Util::addScript(Application::APP_ID, 'admin');
|
||||
return new TemplateResponse(Application::APP_ID, 'admin', [], '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { getCSPNonce } from '@nextcloud/auth'
|
||||
import Vue from 'vue'
|
||||
import { createApp } from 'vue'
|
||||
import SystemTagsSection from './views/SystemTagsSection.vue'
|
||||
|
||||
__webpack_nonce__ = getCSPNonce()
|
||||
|
||||
const SystemTagsSectionView = Vue.extend(SystemTagsSection)
|
||||
new SystemTagsSectionView().$mount('#vue-admin-systemtags')
|
||||
const app = createApp(SystemTagsSection)
|
||||
app.mount('#vue-admin-systemtags')
|
||||
|
|
|
|||
|
|
@ -3,6 +3,219 @@
|
|||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Tag, TagWithId } from '../types.ts'
|
||||
|
||||
import { showSuccess } from '@nextcloud/dialogs'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { computed, ref, useTemplateRef, watch } from 'vue'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
|
||||
import NcSelect from '@nextcloud/vue/components/NcSelect'
|
||||
import NcSelectTags from '@nextcloud/vue/components/NcSelectTags'
|
||||
import NcTextField from '@nextcloud/vue/components/NcTextField'
|
||||
import { createTag, deleteTag, updateTag } from '../services/api.ts'
|
||||
import { defaultBaseTag } from '../utils.ts'
|
||||
|
||||
const props = defineProps<{
|
||||
tags: TagWithId[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'tag:created': [tag: TagWithId]
|
||||
'tag:updated': [tag: TagWithId]
|
||||
'tag:deleted': [tag: TagWithId]
|
||||
}>()
|
||||
|
||||
enum TagLevel {
|
||||
Public = 'Public',
|
||||
Restricted = 'Restricted',
|
||||
Invisible = 'Invisible',
|
||||
}
|
||||
|
||||
interface TagLevelOption {
|
||||
id: TagLevel
|
||||
label: string
|
||||
}
|
||||
|
||||
const tagLevelOptions: TagLevelOption[] = [
|
||||
{
|
||||
id: TagLevel.Public,
|
||||
label: t('systemtags', 'Public'),
|
||||
},
|
||||
{
|
||||
id: TagLevel.Restricted,
|
||||
label: t('systemtags', 'Restricted'),
|
||||
},
|
||||
{
|
||||
id: TagLevel.Invisible,
|
||||
label: t('systemtags', 'Invisible'),
|
||||
},
|
||||
]
|
||||
|
||||
const tagNameInputElement = useTemplateRef('tagNameInput')
|
||||
|
||||
const loading = ref(false)
|
||||
const errorMessage = ref('')
|
||||
const tagName = ref('')
|
||||
const tagLevel = ref(TagLevel.Public)
|
||||
|
||||
const selectedTag = ref<null | TagWithId>(null)
|
||||
watch(selectedTag, (tag: null | TagWithId) => {
|
||||
tagName.value = tag ? tag.displayName : ''
|
||||
tagLevel.value = tag ? getTagLevel(tag.userVisible, tag.userAssignable) : TagLevel.Public
|
||||
})
|
||||
|
||||
const isCreating = computed(() => selectedTag.value === null)
|
||||
const isCreateDisabled = computed(() => tagName.value === '')
|
||||
|
||||
const isUpdateDisabled = computed(() => (
|
||||
tagName.value === ''
|
||||
|| (
|
||||
selectedTag.value?.displayName === tagName.value
|
||||
&& getTagLevel(selectedTag.value?.userVisible, selectedTag.value?.userAssignable) === tagLevel.value
|
||||
)
|
||||
))
|
||||
|
||||
const isResetDisabled = computed(() => {
|
||||
if (isCreating.value) {
|
||||
return tagName.value === '' && tagLevel.value === TagLevel.Public
|
||||
}
|
||||
return selectedTag.value === null
|
||||
})
|
||||
|
||||
const userVisible = computed((): boolean => {
|
||||
const matchLevel: Record<TagLevel, boolean> = {
|
||||
[TagLevel.Public]: true,
|
||||
[TagLevel.Restricted]: true,
|
||||
[TagLevel.Invisible]: false,
|
||||
}
|
||||
return matchLevel[tagLevel.value]
|
||||
})
|
||||
|
||||
const userAssignable = computed(() => {
|
||||
const matchLevel: Record<TagLevel, boolean> = {
|
||||
[TagLevel.Public]: true,
|
||||
[TagLevel.Restricted]: false,
|
||||
[TagLevel.Invisible]: false,
|
||||
}
|
||||
return matchLevel[tagLevel.value]
|
||||
})
|
||||
|
||||
const tagProperties = computed((): Omit<Tag, 'id' | 'canAssign'> => {
|
||||
return {
|
||||
displayName: tagName.value,
|
||||
userVisible: userVisible.value,
|
||||
userAssignable: userAssignable.value,
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Handle tag selection
|
||||
*
|
||||
* @param tagId - The selected tag ID
|
||||
*/
|
||||
function onSelectTag(tagId: number | null) {
|
||||
const tag = props.tags.find((search) => search.id === tagId) || null
|
||||
selectedTag.value = tag
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle form submission
|
||||
*/
|
||||
async function handleSubmit() {
|
||||
if (isCreating.value) {
|
||||
await create()
|
||||
return
|
||||
}
|
||||
await update()
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new tag
|
||||
*/
|
||||
async function create() {
|
||||
const tag: Tag = { ...defaultBaseTag, ...tagProperties.value }
|
||||
loading.value = true
|
||||
try {
|
||||
const id = await createTag(tag)
|
||||
const createdTag: TagWithId = { ...tag, id }
|
||||
emit('tag:created', createdTag)
|
||||
showSuccess(t('systemtags', 'Created tag'))
|
||||
reset()
|
||||
} catch {
|
||||
errorMessage.value = t('systemtags', 'Failed to create tag')
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the selected tag
|
||||
*/
|
||||
async function update() {
|
||||
if (selectedTag.value === null) {
|
||||
return
|
||||
}
|
||||
const tag: TagWithId = { ...selectedTag.value, ...tagProperties.value }
|
||||
loading.value = true
|
||||
try {
|
||||
await updateTag(tag)
|
||||
selectedTag.value = tag
|
||||
emit('tag:updated', tag)
|
||||
showSuccess(t('systemtags', 'Updated tag'))
|
||||
tagNameInputElement.value?.focus()
|
||||
} catch {
|
||||
errorMessage.value = t('systemtags', 'Failed to update tag')
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the selected tag
|
||||
*/
|
||||
async function handleDelete() {
|
||||
if (selectedTag.value === null) {
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
await deleteTag(selectedTag.value)
|
||||
emit('tag:deleted', selectedTag.value)
|
||||
showSuccess(t('systemtags', 'Deleted tag'))
|
||||
reset()
|
||||
} catch {
|
||||
errorMessage.value = t('systemtags', 'Failed to delete tag')
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the form
|
||||
*/
|
||||
function reset() {
|
||||
selectedTag.value = null
|
||||
errorMessage.value = ''
|
||||
tagName.value = ''
|
||||
tagLevel.value = TagLevel.Public
|
||||
tagNameInputElement.value?.focus()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tag level based on visibility and assignability
|
||||
*
|
||||
* @param userVisible - Whether the tag is visible to users
|
||||
* @param userAssignable - Whether the tag is assignable by users
|
||||
*/
|
||||
function getTagLevel(userVisible: boolean, userAssignable: boolean): TagLevel {
|
||||
const matchLevel: Record<string, TagLevel> = {
|
||||
[[true, true].join(',')]: TagLevel.Public,
|
||||
[[true, false].join(',')]: TagLevel.Restricted,
|
||||
[[false, false].join(',')]: TagLevel.Invisible,
|
||||
}
|
||||
return matchLevel[[userVisible, userAssignable].join(',')]!
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form
|
||||
class="system-tag-form"
|
||||
|
|
@ -17,14 +230,14 @@
|
|||
<div class="system-tag-form__group">
|
||||
<label for="system-tags-input">{{ t('systemtags', 'Search for a tag to edit') }}</label>
|
||||
<NcSelectTags
|
||||
:model-value="selectedTag"
|
||||
input-id="system-tags-input"
|
||||
:modelValue="selectedTag"
|
||||
inputId="system-tags-input"
|
||||
:placeholder="t('systemtags', 'Collaborative tags …')"
|
||||
:fetch-tags="false"
|
||||
:fetchTags="false"
|
||||
:options="tags"
|
||||
:multiple="false"
|
||||
label-outside
|
||||
@update:model-value="onSelectTag">
|
||||
labelOutside
|
||||
@update:modelValue="onSelectTag">
|
||||
<template #no-options>
|
||||
{{ t('systemtags', 'No tags to select') }}
|
||||
</template>
|
||||
|
|
@ -38,20 +251,20 @@
|
|||
ref="tagNameInput"
|
||||
v-model="tagName"
|
||||
:error="Boolean(errorMessage)"
|
||||
:helper-text="errorMessage"
|
||||
label-outside />
|
||||
:helperText="errorMessage"
|
||||
labelOutside />
|
||||
</div>
|
||||
|
||||
<div class="system-tag-form__group">
|
||||
<label for="system-tag-level">{{ t('systemtags', 'Tag level') }}</label>
|
||||
<NcSelect
|
||||
v-model="tagLevel"
|
||||
input-id="system-tag-level"
|
||||
inputId="system-tag-level"
|
||||
:options="tagLevelOptions"
|
||||
:reduce="level => level.id"
|
||||
:clearable="false"
|
||||
:disabled="loading"
|
||||
label-outside />
|
||||
labelOutside />
|
||||
</div>
|
||||
|
||||
<div class="system-tag-form__row">
|
||||
|
|
@ -86,232 +299,6 @@
|
|||
</form>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { PropType } from 'vue'
|
||||
import type { Tag, TagWithId } from '../types.js'
|
||||
|
||||
import { showSuccess } from '@nextcloud/dialogs'
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
import { defineComponent } from 'vue'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
|
||||
import NcSelect from '@nextcloud/vue/components/NcSelect'
|
||||
import NcSelectTags from '@nextcloud/vue/components/NcSelectTags'
|
||||
import NcTextField from '@nextcloud/vue/components/NcTextField'
|
||||
import { createTag, deleteTag, updateTag } from '../services/api.js'
|
||||
import { defaultBaseTag } from '../utils.js'
|
||||
|
||||
enum TagLevel {
|
||||
Public = 'Public',
|
||||
Restricted = 'Restricted',
|
||||
Invisible = 'Invisible',
|
||||
}
|
||||
|
||||
interface TagLevelOption {
|
||||
id: TagLevel
|
||||
label: string
|
||||
}
|
||||
|
||||
const tagLevelOptions: TagLevelOption[] = [
|
||||
{
|
||||
id: TagLevel.Public,
|
||||
label: t('systemtags', 'Public'),
|
||||
},
|
||||
{
|
||||
id: TagLevel.Restricted,
|
||||
label: t('systemtags', 'Restricted'),
|
||||
},
|
||||
{
|
||||
id: TagLevel.Invisible,
|
||||
label: t('systemtags', 'Invisible'),
|
||||
},
|
||||
]
|
||||
|
||||
/**
|
||||
*
|
||||
* @param userVisible
|
||||
* @param userAssignable
|
||||
*/
|
||||
function getTagLevel(userVisible: boolean, userAssignable: boolean): TagLevel {
|
||||
const matchLevel: Record<string, TagLevel> = {
|
||||
[[true, true].join(',')]: TagLevel.Public,
|
||||
[[true, false].join(',')]: TagLevel.Restricted,
|
||||
[[false, false].join(',')]: TagLevel.Invisible,
|
||||
}
|
||||
return matchLevel[[userVisible, userAssignable].join(',')]!
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SystemTagForm',
|
||||
|
||||
components: {
|
||||
NcButton,
|
||||
NcLoadingIcon,
|
||||
NcSelect,
|
||||
NcSelectTags,
|
||||
NcTextField,
|
||||
},
|
||||
|
||||
props: {
|
||||
tags: {
|
||||
type: Array as PropType<TagWithId[]>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
emits: [
|
||||
'tag:created',
|
||||
'tag:updated',
|
||||
'tag:deleted',
|
||||
],
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
tagLevelOptions,
|
||||
selectedTag: null as null | TagWithId,
|
||||
errorMessage: '',
|
||||
tagName: '',
|
||||
tagLevel: TagLevel.Public,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
isCreating(): boolean {
|
||||
return this.selectedTag === null
|
||||
},
|
||||
|
||||
isCreateDisabled(): boolean {
|
||||
return this.tagName === ''
|
||||
},
|
||||
|
||||
isUpdateDisabled(): boolean {
|
||||
return (
|
||||
this.tagName === ''
|
||||
|| (
|
||||
this.selectedTag?.displayName === this.tagName
|
||||
&& getTagLevel(this.selectedTag?.userVisible, this.selectedTag?.userAssignable) === this.tagLevel
|
||||
)
|
||||
)
|
||||
},
|
||||
|
||||
isResetDisabled(): boolean {
|
||||
if (this.isCreating) {
|
||||
return this.tagName === '' && this.tagLevel === TagLevel.Public
|
||||
}
|
||||
return this.selectedTag === null
|
||||
},
|
||||
|
||||
userVisible(): boolean {
|
||||
const matchLevel: Record<TagLevel, boolean> = {
|
||||
[TagLevel.Public]: true,
|
||||
[TagLevel.Restricted]: true,
|
||||
[TagLevel.Invisible]: false,
|
||||
}
|
||||
return matchLevel[this.tagLevel]
|
||||
},
|
||||
|
||||
userAssignable(): boolean {
|
||||
const matchLevel: Record<TagLevel, boolean> = {
|
||||
[TagLevel.Public]: true,
|
||||
[TagLevel.Restricted]: false,
|
||||
[TagLevel.Invisible]: false,
|
||||
}
|
||||
return matchLevel[this.tagLevel]
|
||||
},
|
||||
|
||||
tagProperties(): Omit<Tag, 'id' | 'canAssign'> {
|
||||
return {
|
||||
displayName: this.tagName,
|
||||
userVisible: this.userVisible,
|
||||
userAssignable: this.userAssignable,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
selectedTag(tag: null | TagWithId) {
|
||||
this.tagName = tag ? tag.displayName : ''
|
||||
this.tagLevel = tag ? getTagLevel(tag.userVisible, tag.userAssignable) : TagLevel.Public
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
t,
|
||||
|
||||
onSelectTag(tagId: number | null) {
|
||||
const tag = this.tags.find((search) => search.id === tagId) || null
|
||||
this.selectedTag = tag
|
||||
},
|
||||
|
||||
async handleSubmit() {
|
||||
if (this.isCreating) {
|
||||
await this.create()
|
||||
return
|
||||
}
|
||||
await this.update()
|
||||
},
|
||||
|
||||
async create() {
|
||||
const tag: Tag = { ...defaultBaseTag, ...this.tagProperties }
|
||||
this.loading = true
|
||||
try {
|
||||
const id = await createTag(tag)
|
||||
const createdTag: TagWithId = { ...tag, id }
|
||||
this.$emit('tag:created', createdTag)
|
||||
showSuccess(t('systemtags', 'Created tag'))
|
||||
this.reset()
|
||||
} catch {
|
||||
this.errorMessage = t('systemtags', 'Failed to create tag')
|
||||
}
|
||||
this.loading = false
|
||||
},
|
||||
|
||||
async update() {
|
||||
if (this.selectedTag === null) {
|
||||
return
|
||||
}
|
||||
const tag: TagWithId = { ...this.selectedTag, ...this.tagProperties }
|
||||
this.loading = true
|
||||
try {
|
||||
await updateTag(tag)
|
||||
this.selectedTag = tag
|
||||
this.$emit('tag:updated', tag)
|
||||
showSuccess(t('systemtags', 'Updated tag'))
|
||||
this.$refs.tagNameInput?.focus()
|
||||
} catch {
|
||||
this.errorMessage = t('systemtags', 'Failed to update tag')
|
||||
}
|
||||
this.loading = false
|
||||
},
|
||||
|
||||
async handleDelete() {
|
||||
if (this.selectedTag === null) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
try {
|
||||
await deleteTag(this.selectedTag)
|
||||
this.$emit('tag:deleted', this.selectedTag)
|
||||
showSuccess(t('systemtags', 'Deleted tag'))
|
||||
this.reset()
|
||||
} catch {
|
||||
this.errorMessage = t('systemtags', 'Failed to delete tag')
|
||||
}
|
||||
this.loading = false
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.selectedTag = null
|
||||
this.errorMessage = ''
|
||||
this.tagName = ''
|
||||
this.tagLevel = TagLevel.Public
|
||||
this.$refs.tagNameInput?.focus()
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.system-tag-form {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -6,20 +6,20 @@
|
|||
<template>
|
||||
<NcDialog
|
||||
data-cy-systemtags-picker
|
||||
:no-close="status === Status.LOADING"
|
||||
:noClose="status === Status.LOADING"
|
||||
:name="t('systemtags', 'Manage tags')"
|
||||
:open="opened"
|
||||
:class="'systemtags-picker--' + status"
|
||||
class="systemtags-picker"
|
||||
close-on-click-outside
|
||||
out-transition
|
||||
closeOnClickOutside
|
||||
outTransition
|
||||
@update:open="onCancel">
|
||||
<NcEmptyContent
|
||||
v-if="status === Status.LOADING || status === Status.DONE"
|
||||
:name="t('systemtags', 'Applying tags changes…')">
|
||||
<template #icon>
|
||||
<NcLoadingIcon v-if="status === Status.LOADING" />
|
||||
<CheckIcon v-else fill-color="var(--color-border-success)" />
|
||||
<CheckIcon v-else fillColor="var(--color-border-success)" />
|
||||
</template>
|
||||
</NcEmptyContent>
|
||||
|
||||
|
|
@ -41,11 +41,12 @@
|
|||
<li
|
||||
v-for="tag in filteredTags"
|
||||
:key="tag.id"
|
||||
ref="tags"
|
||||
:data-cy-systemtags-picker-tag="tag.id"
|
||||
:style="tagListStyle(tag)"
|
||||
class="systemtags-picker__tag">
|
||||
<NcCheckboxRadioSwitch
|
||||
:model-value="isChecked(tag)"
|
||||
:modelValue="isChecked(tag)"
|
||||
:disabled="!tag.canAssign"
|
||||
:indeterminate="isIndeterminate(tag)"
|
||||
:label="tag.displayName"
|
||||
|
|
@ -58,23 +59,22 @@
|
|||
<NcColorPicker
|
||||
v-if="canEditOrCreateTag"
|
||||
:data-cy-systemtags-picker-tag-color="tag.id"
|
||||
:model-value="`#${tag.color || '000000'}`"
|
||||
:modelValue="`#${tag.color || '000000'}`"
|
||||
:shown="openedPicker === tag.id"
|
||||
class="systemtags-picker__tag-color"
|
||||
@update:value="onColorChange(tag, $event)"
|
||||
@update:shown="openedPicker = $event ? tag.id : false"
|
||||
@submit="openedPicker = false">
|
||||
@submit="onColorChange(tag, $event)">
|
||||
<NcButton :aria-label="t('systemtags', 'Change tag color')" variant="tertiary">
|
||||
<template #icon>
|
||||
<CircleIcon
|
||||
v-if="tag.color"
|
||||
:size="24"
|
||||
fill-color="var(--color-circle-icon)"
|
||||
fillColor="var(--color-circle-icon)"
|
||||
class="button-color-circle" />
|
||||
<CircleOutlineIcon
|
||||
v-else
|
||||
:size="24"
|
||||
fill-color="var(--color-circle-icon)"
|
||||
fillColor="var(--color-circle-icon)"
|
||||
class="button-color-empty" />
|
||||
<PencilIcon class="button-color-pencil" />
|
||||
</template>
|
||||
|
|
@ -108,6 +108,7 @@
|
|||
{{ t('systemtags', 'Choose tags for the selected files') }}
|
||||
</NcNoteCard>
|
||||
<NcNoteCard v-else type="info">
|
||||
<!-- eslint-disable-next-line vue/no-v-html -- we use this to format the message with chips -->
|
||||
<span v-html="statusMessage" />
|
||||
</NcNoteCard>
|
||||
</div>
|
||||
|
|
@ -134,8 +135,8 @@
|
|||
<NcChip
|
||||
ref="chip"
|
||||
text="%s"
|
||||
variant="primary"
|
||||
no-close />
|
||||
noClose
|
||||
variant="primary" />
|
||||
</div>
|
||||
</NcDialog>
|
||||
</template>
|
||||
|
|
@ -221,7 +222,11 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
|
||||
emits: ['close'],
|
||||
emits: {
|
||||
close(status: null | boolean) {
|
||||
return status === null || typeof status === 'boolean'
|
||||
},
|
||||
},
|
||||
|
||||
setup() {
|
||||
return {
|
||||
|
|
@ -399,7 +404,7 @@ export default defineComponent({
|
|||
methods: {
|
||||
// Format & sanitize a tag chip for v-html tag rendering
|
||||
formatTagChip(tag: TagWithId): string {
|
||||
const chip = this.$refs.chip as NcChip
|
||||
const chip = this.$refs.chip as InstanceType<typeof NcChip>
|
||||
const chipCloneEl = chip.$el.cloneNode(true) as HTMLElement
|
||||
if (tag.color) {
|
||||
const style = this.tagListStyle(tag)
|
||||
|
|
@ -476,12 +481,15 @@ export default defineComponent({
|
|||
|
||||
// Scroll to the newly created tag
|
||||
await this.$nextTick()
|
||||
const newTagEl = this.$el.querySelector(`input[type="checkbox"][label="${tag.displayName}"]`)
|
||||
newTagEl?.scrollIntoView({
|
||||
behavior: 'instant',
|
||||
block: 'center',
|
||||
inline: 'center',
|
||||
})
|
||||
if (Array.isArray(this.$refs.tags)) {
|
||||
const newTagEl = this.$refs.tags
|
||||
.find((el: HTMLElement) => el.dataset.cySystemtagsPickerTag === id.toString())
|
||||
newTagEl?.scrollIntoView({
|
||||
behavior: 'instant',
|
||||
block: 'center',
|
||||
inline: 'center',
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
showError((error as Error)?.message || t('systemtags', 'Failed to create tag'))
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,235 @@
|
|||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { INode } from '@nextcloud/files'
|
||||
import type { Tag, TagWithId } from '../types.ts'
|
||||
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { emit, subscribe } from '@nextcloud/event-bus'
|
||||
import { getSidebar } from '@nextcloud/files'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { onBeforeMount, onMounted, ref, watch } from 'vue'
|
||||
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
|
||||
import NcSelectTags from '@nextcloud/vue/components/NcSelectTags'
|
||||
import logger from '../logger.ts'
|
||||
import { fetchLastUsedTagIds, fetchTags } from '../services/api.ts'
|
||||
import { fetchNode } from '../services/davClient.ts'
|
||||
import {
|
||||
createTagForFile,
|
||||
deleteTagForFile,
|
||||
fetchTagsForFile,
|
||||
setTagForFile,
|
||||
} from '../services/files.ts'
|
||||
import { defaultBaseTag } from '../utils.ts'
|
||||
|
||||
const props = defineProps<{
|
||||
fileId: number
|
||||
disabled?: boolean
|
||||
}>()
|
||||
|
||||
const sortedTags = ref<TagWithId[]>([])
|
||||
const selectedTags = ref<TagWithId[]>([])
|
||||
const loadingTags = ref(false)
|
||||
const loading = ref(false)
|
||||
|
||||
watch(() => props.fileId, async () => {
|
||||
loadingTags.value = true
|
||||
try {
|
||||
selectedTags.value = await fetchTagsForFile(props.fileId)
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to load selected tags'))
|
||||
logger.error('Failed to load selected tags', { error })
|
||||
} finally {
|
||||
loadingTags.value = false
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
onBeforeMount(async () => {
|
||||
try {
|
||||
const tags = await fetchTags()
|
||||
const lastUsedOrder = await fetchLastUsedTagIds()
|
||||
|
||||
const lastUsedTags: TagWithId[] = []
|
||||
const remainingTags: TagWithId[] = []
|
||||
|
||||
for (const tag of tags) {
|
||||
if (lastUsedOrder.includes(tag.id)) {
|
||||
lastUsedTags.push(tag)
|
||||
continue
|
||||
}
|
||||
remainingTags.push(tag)
|
||||
}
|
||||
|
||||
const sortByLastUsed = (a: TagWithId, b: TagWithId) => {
|
||||
return lastUsedOrder.indexOf(a.id) - lastUsedOrder.indexOf(b.id)
|
||||
}
|
||||
lastUsedTags.sort(sortByLastUsed)
|
||||
|
||||
sortedTags.value = [...lastUsedTags, ...remainingTags]
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to load tags'))
|
||||
logger.error('Failed to load tags', { error })
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
subscribe('systemtags:node:updated', onTagUpdated)
|
||||
})
|
||||
|
||||
/**
|
||||
* Create a new tag
|
||||
*
|
||||
* @param newDisplayName - The display name of the tag to create
|
||||
*/
|
||||
function createOption(newDisplayName: string): Tag {
|
||||
for (const tag of sortedTags.value) {
|
||||
const { displayName, ...baseTag } = tag
|
||||
if (
|
||||
displayName === newDisplayName
|
||||
&& Object.entries(baseTag)
|
||||
.every(([key, value]) => defaultBaseTag[key] === value)
|
||||
) {
|
||||
// Return existing tag to prevent vue-select from thinking the tags are different and showing duplicate options
|
||||
return tag
|
||||
}
|
||||
}
|
||||
return {
|
||||
...defaultBaseTag,
|
||||
displayName: newDisplayName,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out tags with no id to prevent duplicate selected options
|
||||
*
|
||||
* Created tags are added programmatically by `handleCreate()` with
|
||||
* their respective ids returned from the server.
|
||||
*
|
||||
* @param currentTags - The selected tags
|
||||
*/
|
||||
function handleInput(currentTags: Tag[]) {
|
||||
selectedTags.value = currentTags.filter((selectedTag) => Boolean(selectedTag.id)) as TagWithId[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle tag selection
|
||||
*
|
||||
* @param tags - The selected tags
|
||||
*/
|
||||
async function handleSelect(tags: Tag[]) {
|
||||
const lastTag = tags[tags.length - 1]!
|
||||
if (!lastTag.id) {
|
||||
// Ignore created tags handled by `handleCreate()`
|
||||
return
|
||||
}
|
||||
const selectedTag = lastTag as TagWithId
|
||||
loading.value = true
|
||||
try {
|
||||
await setTagForFile(selectedTag, props.fileId)
|
||||
const sortToFront = (a: TagWithId, b: TagWithId) => {
|
||||
if (a.id === selectedTag.id) {
|
||||
return -1
|
||||
} else if (b.id === selectedTag.id) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
sortedTags.value.sort(sortToFront)
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to select tag'))
|
||||
logger.error('Failed to select tag', { error })
|
||||
}
|
||||
loading.value = false
|
||||
|
||||
updateAndDispatchNodeTagsEvent(props.fileId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle tag creation
|
||||
*
|
||||
* @param tag - The created tag
|
||||
*/
|
||||
async function handleCreate(tag: Tag) {
|
||||
loading.value = true
|
||||
try {
|
||||
const id = await createTagForFile(tag, props.fileId)
|
||||
const createdTag = { ...tag, id }
|
||||
sortedTags.value.unshift(createdTag)
|
||||
selectedTags.value.push(createdTag)
|
||||
} catch (error) {
|
||||
const systemTagsCreationRestrictedToAdmin = loadState<true | false>('settings', 'restrictSystemTagsCreationToAdmin', false) === true
|
||||
logger.error('Failed to create tag', { error })
|
||||
if (systemTagsCreationRestrictedToAdmin) {
|
||||
showError(t('systemtags', 'System admin disabled tag creation. You can only use existing ones.'))
|
||||
return
|
||||
}
|
||||
showError(t('systemtags', 'Failed to create tag'))
|
||||
}
|
||||
loading.value = false
|
||||
|
||||
updateAndDispatchNodeTagsEvent(props.fileId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle tag deselection
|
||||
*
|
||||
* @param tag - The deselected tag
|
||||
*/
|
||||
async function handleDeselect(tag: TagWithId) {
|
||||
loading.value = true
|
||||
try {
|
||||
await deleteTagForFile(tag, props.fileId)
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to delete tag'))
|
||||
logger.error('Failed to delete tag', { error })
|
||||
}
|
||||
loading.value = false
|
||||
|
||||
updateAndDispatchNodeTagsEvent(props.fileId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle node updated event
|
||||
*
|
||||
* @param node - The updated node
|
||||
*/
|
||||
async function onTagUpdated(node: INode) {
|
||||
if (node.fileid !== props.fileId) {
|
||||
return
|
||||
}
|
||||
|
||||
loadingTags.value = true
|
||||
try {
|
||||
selectedTags.value = await fetchTagsForFile(props.fileId)
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to load selected tags'))
|
||||
logger.error('Failed to load selected tags', { error })
|
||||
}
|
||||
|
||||
loadingTags.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and dispatch system tags node updated event
|
||||
*
|
||||
* @param fileId - The file ID
|
||||
*/
|
||||
async function updateAndDispatchNodeTagsEvent(fileId: number) {
|
||||
const sidebar = getSidebar()
|
||||
const path = sidebar.node?.path ?? ''
|
||||
try {
|
||||
const node = await fetchNode(path)
|
||||
if (node) {
|
||||
emit('systemtags:node:updated', node)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to fetch node for system tags update', { error, fileId })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="system-tags">
|
||||
<NcLoadingIcon
|
||||
|
|
@ -13,15 +242,15 @@
|
|||
<NcSelectTags
|
||||
v-show="!loadingTags"
|
||||
class="system-tags__select"
|
||||
:input-label="t('systemtags', 'Search or create collaborative tags')"
|
||||
:inputLabel="t('systemtags', 'Search or create collaborative tags')"
|
||||
:placeholder="t('systemtags', 'Collaborative tags …')"
|
||||
:options="sortedTags"
|
||||
:model-value="selectedTags"
|
||||
:create-option="createOption"
|
||||
:modelValue="selectedTags"
|
||||
:createOption="createOption"
|
||||
:disabled="disabled"
|
||||
:taggable="true"
|
||||
:passthru="true"
|
||||
:fetch-tags="false"
|
||||
:fetchTags="false"
|
||||
:loading="loading"
|
||||
@input="handleInput"
|
||||
@option:selected="handleSelect"
|
||||
|
|
@ -34,231 +263,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { INode } from '@nextcloud/files'
|
||||
import type { Tag, TagWithId } from '../types.js'
|
||||
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { emit, subscribe } from '@nextcloud/event-bus'
|
||||
import { getSidebar } from '@nextcloud/files'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import Vue from 'vue'
|
||||
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
|
||||
import NcSelectTags from '@nextcloud/vue/components/NcSelectTags'
|
||||
import { fetchNode } from '../../../files/src/services/WebdavClient.js'
|
||||
import logger from '../logger.js'
|
||||
import { fetchLastUsedTagIds, fetchTags } from '../services/api.js'
|
||||
import {
|
||||
createTagForFile,
|
||||
deleteTagForFile,
|
||||
fetchTagsForFile,
|
||||
setTagForFile,
|
||||
} from '../services/files.js'
|
||||
import { defaultBaseTag } from '../utils.js'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'SystemTags',
|
||||
|
||||
components: {
|
||||
NcLoadingIcon,
|
||||
NcSelectTags,
|
||||
},
|
||||
|
||||
props: {
|
||||
fileId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
sortedTags: [] as TagWithId[],
|
||||
selectedTags: [] as TagWithId[],
|
||||
loadingTags: false,
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
fileId: {
|
||||
immediate: true,
|
||||
async handler() {
|
||||
this.loadingTags = true
|
||||
try {
|
||||
this.selectedTags = await fetchTagsForFile(this.fileId)
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to load selected tags'))
|
||||
logger.error('Failed to load selected tags', { error })
|
||||
}
|
||||
this.loadingTags = false
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
async created() {
|
||||
try {
|
||||
const tags = await fetchTags()
|
||||
const lastUsedOrder = await fetchLastUsedTagIds()
|
||||
|
||||
const lastUsedTags: TagWithId[] = []
|
||||
const remainingTags: TagWithId[] = []
|
||||
|
||||
for (const tag of tags) {
|
||||
if (lastUsedOrder.includes(tag.id)) {
|
||||
lastUsedTags.push(tag)
|
||||
continue
|
||||
}
|
||||
remainingTags.push(tag)
|
||||
}
|
||||
|
||||
const sortByLastUsed = (a: TagWithId, b: TagWithId) => {
|
||||
return lastUsedOrder.indexOf(a.id) - lastUsedOrder.indexOf(b.id)
|
||||
}
|
||||
lastUsedTags.sort(sortByLastUsed)
|
||||
|
||||
this.sortedTags = [...lastUsedTags, ...remainingTags]
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to load tags'))
|
||||
logger.error('Failed to load tags', { error })
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
subscribe('systemtags:node:updated', this.onTagUpdated)
|
||||
},
|
||||
|
||||
methods: {
|
||||
t,
|
||||
|
||||
createOption(newDisplayName: string): Tag {
|
||||
for (const tag of this.sortedTags) {
|
||||
const { displayName, ...baseTag } = tag
|
||||
if (
|
||||
displayName === newDisplayName
|
||||
&& Object.entries(baseTag)
|
||||
.every(([key, value]) => defaultBaseTag[key] === value)
|
||||
) {
|
||||
// Return existing tag to prevent vue-select from thinking the tags are different and showing duplicate options
|
||||
return tag
|
||||
}
|
||||
}
|
||||
return {
|
||||
...defaultBaseTag,
|
||||
displayName: newDisplayName,
|
||||
}
|
||||
},
|
||||
|
||||
handleInput(selectedTags: Tag[]) {
|
||||
/**
|
||||
* Filter out tags with no id to prevent duplicate selected options
|
||||
*
|
||||
* Created tags are added programmatically by `handleCreate()` with
|
||||
* their respective ids returned from the server
|
||||
*/
|
||||
this.selectedTags = selectedTags.filter((selectedTag) => Boolean(selectedTag.id)) as TagWithId[]
|
||||
},
|
||||
|
||||
async handleSelect(tags: Tag[]) {
|
||||
const lastTag = tags[tags.length - 1]
|
||||
if (!lastTag.id) {
|
||||
// Ignore created tags handled by `handleCreate()`
|
||||
return
|
||||
}
|
||||
const selectedTag = lastTag as TagWithId
|
||||
this.loading = true
|
||||
try {
|
||||
await setTagForFile(selectedTag, this.fileId)
|
||||
const sortToFront = (a: TagWithId, b: TagWithId) => {
|
||||
if (a.id === selectedTag.id) {
|
||||
return -1
|
||||
} else if (b.id === selectedTag.id) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
this.sortedTags.sort(sortToFront)
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to select tag'))
|
||||
logger.error('Failed to select tag', { error })
|
||||
}
|
||||
this.loading = false
|
||||
|
||||
this.updateAndDispatchNodeTagsEvent(this.fileId)
|
||||
},
|
||||
|
||||
async handleCreate(tag: Tag) {
|
||||
this.loading = true
|
||||
try {
|
||||
const id = await createTagForFile(tag, this.fileId)
|
||||
const createdTag = { ...tag, id }
|
||||
this.sortedTags.unshift(createdTag)
|
||||
this.selectedTags.push(createdTag)
|
||||
} catch (error) {
|
||||
const systemTagsCreationRestrictedToAdmin = loadState<true | false>('settings', 'restrictSystemTagsCreationToAdmin', false) === true
|
||||
logger.error('Failed to create tag', { error })
|
||||
if (systemTagsCreationRestrictedToAdmin) {
|
||||
showError(t('systemtags', 'System admin disabled tag creation. You can only use existing ones.'))
|
||||
return
|
||||
}
|
||||
showError(t('systemtags', 'Failed to create tag'))
|
||||
}
|
||||
this.loading = false
|
||||
|
||||
this.updateAndDispatchNodeTagsEvent(this.fileId)
|
||||
},
|
||||
|
||||
async handleDeselect(tag: TagWithId) {
|
||||
this.loading = true
|
||||
try {
|
||||
await deleteTagForFile(tag, this.fileId)
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to delete tag'))
|
||||
logger.error('Failed to delete tag', { error })
|
||||
}
|
||||
this.loading = false
|
||||
|
||||
this.updateAndDispatchNodeTagsEvent(this.fileId)
|
||||
},
|
||||
|
||||
async onTagUpdated(node: INode) {
|
||||
if (node.fileid !== this.fileId) {
|
||||
return
|
||||
}
|
||||
|
||||
this.loadingTags = true
|
||||
try {
|
||||
this.selectedTags = await fetchTagsForFile(this.fileId)
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to load selected tags'))
|
||||
logger.error('Failed to load selected tags', { error })
|
||||
}
|
||||
|
||||
this.loadingTags = false
|
||||
},
|
||||
|
||||
async updateAndDispatchNodeTagsEvent(fileId: number) {
|
||||
const sidebar = getSidebar()
|
||||
const path = sidebar.node?.path ?? ''
|
||||
try {
|
||||
const node = await fetchNode(path)
|
||||
if (node) {
|
||||
emit('systemtags:node:updated', node)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to fetch node for system tags update', { error, fileId })
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.system-tags {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,69 @@
|
|||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<script setup lang="ts">
|
||||
import { showError, showSuccess } from '@nextcloud/dialogs'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { ref } from 'vue'
|
||||
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
|
||||
import logger from '../logger.ts'
|
||||
import { updateSystemTagsAdminRestriction } from '../services/api.ts'
|
||||
|
||||
// By default, system tags creation is not restricted to admins
|
||||
const systemTagsCreationRestrictedToAdmin = ref(loadState('systemtags', 'restrictSystemTagsCreationToAdmin', false))
|
||||
|
||||
/**
|
||||
* Update system tags admin restriction setting
|
||||
*
|
||||
* @param isRestricted - True if system tags creation should be restricted to admins
|
||||
*/
|
||||
async function updateSystemTagsDefault(isRestricted: boolean) {
|
||||
try {
|
||||
const responseData = await updateSystemTagsAdminRestriction(isRestricted)
|
||||
logger.debug('updateSystemTagsDefault', { responseData })
|
||||
handleResponse({
|
||||
isRestricted,
|
||||
status: responseData.ocs?.meta?.status,
|
||||
})
|
||||
} catch (e) {
|
||||
handleResponse({
|
||||
errorMessage: t('systemtags', 'Unable to update setting'),
|
||||
error: e,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle response from updating system tags admin restriction
|
||||
*
|
||||
* @param context - The response context
|
||||
* @param context.isRestricted - Whether system tags creation is restricted to admins
|
||||
* @param context.status - The response status
|
||||
* @param context.errorMessage - The error message, if any
|
||||
* @param context.error - The error object, if any
|
||||
*/
|
||||
function handleResponse({ isRestricted, status, errorMessage, error }: {
|
||||
isRestricted?: boolean
|
||||
status?: string
|
||||
errorMessage?: string
|
||||
error?: unknown
|
||||
}) {
|
||||
if (status === 'ok') {
|
||||
systemTagsCreationRestrictedToAdmin.value = !!isRestricted
|
||||
showSuccess(isRestricted
|
||||
? t('systemtags', 'System tag creation is now restricted to administrators')
|
||||
: t('systemtags', 'System tag creation is now allowed for everybody'))
|
||||
return
|
||||
}
|
||||
|
||||
if (errorMessage) {
|
||||
showError(errorMessage)
|
||||
logger.error(errorMessage, { error })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="system-tags-creation-control">
|
||||
<h4 class="inlineblock">
|
||||
|
|
@ -21,66 +84,3 @@
|
|||
</NcCheckboxRadioSwitch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { showError, showSuccess } from '@nextcloud/dialogs'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
|
||||
import logger from '../logger.ts'
|
||||
import { updateSystemTagsAdminRestriction } from '../services/api.js'
|
||||
|
||||
export default {
|
||||
name: 'SystemTagsCreationControl',
|
||||
|
||||
components: {
|
||||
NcCheckboxRadioSwitch,
|
||||
},
|
||||
|
||||
setup() {
|
||||
return {
|
||||
t,
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
// By default, system tags creation is not restricted to admins
|
||||
systemTagsCreationRestrictedToAdmin: loadState('systemtags', 'restrictSystemTagsCreationToAdmin', false),
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async updateSystemTagsDefault(isRestricted: boolean) {
|
||||
try {
|
||||
const responseData = await updateSystemTagsAdminRestriction(isRestricted)
|
||||
logger.debug('updateSystemTagsDefault', responseData)
|
||||
this.handleResponse({
|
||||
isRestricted,
|
||||
status: responseData.ocs?.meta?.status,
|
||||
})
|
||||
} catch (e) {
|
||||
this.handleResponse({
|
||||
errorMessage: t('systemtags', 'Unable to update setting'),
|
||||
error: e,
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
handleResponse({ isRestricted, status, errorMessage, error }) {
|
||||
if (status === 'ok') {
|
||||
this.systemTagsCreationRestrictedToAdmin = isRestricted
|
||||
showSuccess(isRestricted
|
||||
? t('systemtags', 'System tag creation is now restricted to administrators')
|
||||
: t('systemtags', 'System tag creation is now allowed for everybody'))
|
||||
return
|
||||
}
|
||||
|
||||
if (errorMessage) {
|
||||
showError(errorMessage)
|
||||
logger.error(errorMessage, error)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -19,14 +19,14 @@ import { defineAsyncComponent } from 'vue'
|
|||
* @param context.nodes - Nodes to modify tags for
|
||||
*/
|
||||
async function execBatch({ nodes }: ActionContext | ActionContextSingle): Promise<(null | boolean)[]> {
|
||||
const response = await new Promise<null | boolean>((resolve) => {
|
||||
spawnDialog(defineAsyncComponent(() => import('../components/SystemTagPicker.vue')), {
|
||||
const response = await spawnDialog(
|
||||
defineAsyncComponent(() => import('../components/SystemTagPicker.vue')),
|
||||
{
|
||||
nodes,
|
||||
}, (status) => {
|
||||
resolve(status as null | boolean)
|
||||
})
|
||||
})
|
||||
return Array(nodes.length).fill(response)
|
||||
},
|
||||
)
|
||||
return Array(nodes.length)
|
||||
.fill(response)
|
||||
}
|
||||
|
||||
export const action = new FileAction({
|
||||
|
|
@ -55,7 +55,7 @@ export const action = new FileAction({
|
|||
|
||||
async exec(context: ActionContextSingle) {
|
||||
const [result] = await execBatch(context)
|
||||
return result
|
||||
return result!
|
||||
},
|
||||
|
||||
execBatch,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import svgTagMultiple from '@mdi/svg/svg/tag-multiple-outline.svg?raw'
|
||||
import { getNavigation, View } from '@nextcloud/files'
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
import { getContents } from '../services/systemtags.js'
|
||||
import { getContents } from '../services/systemtags.ts'
|
||||
|
||||
export const systemTagsViewId = 'tags'
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { OCSResponse } from '@nextcloud/typings/ocs'
|
||||
import type { FileStat, ResponseDataDetailed, WebDAVClientError } from 'webdav'
|
||||
import type { ServerTag, Tag, TagWithId } from '../types.js'
|
||||
import type { ServerTag, Tag, TagWithId } from '../types.ts'
|
||||
|
||||
import axios from '@nextcloud/axios'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
|
|
@ -13,7 +14,7 @@ import { confirmPassword } from '@nextcloud/password-confirmation'
|
|||
import { generateOcsUrl, generateUrl } from '@nextcloud/router'
|
||||
import logger from '../logger.ts'
|
||||
import { formatTag, parseIdFromLocation, parseTags } from '../utils.ts'
|
||||
import { davClient } from './davClient.js'
|
||||
import { davClient } from './davClient.ts'
|
||||
|
||||
export const fetchTagsPayload = `<?xml version="1.0"?>
|
||||
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
|
||||
|
|
@ -29,7 +30,7 @@ export const fetchTagsPayload = `<?xml version="1.0"?>
|
|||
</d:propfind>`
|
||||
|
||||
/**
|
||||
*
|
||||
* Fetch all tags.
|
||||
*/
|
||||
export async function fetchTags(): Promise<TagWithId[]> {
|
||||
const path = '/systemtags'
|
||||
|
|
@ -47,8 +48,9 @@ export async function fetchTags(): Promise<TagWithId[]> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Fetch a single tag by its ID.
|
||||
*
|
||||
* @param tagId
|
||||
* @param tagId - The ID of the tag to fetch
|
||||
*/
|
||||
export async function fetchTag(tagId: number): Promise<TagWithId> {
|
||||
const path = '/systemtags/' + tagId
|
||||
|
|
@ -57,7 +59,7 @@ export async function fetchTag(tagId: number): Promise<TagWithId> {
|
|||
data: fetchTagsPayload,
|
||||
details: true,
|
||||
}) as ResponseDataDetailed<Required<FileStat>>
|
||||
return parseTags([tag])[0]
|
||||
return parseTags([tag])[0]!
|
||||
} catch (error) {
|
||||
logger.error(t('systemtags', 'Failed to load tag'), { error })
|
||||
throw new Error(t('systemtags', 'Failed to load tag'))
|
||||
|
|
@ -65,7 +67,7 @@ export async function fetchTag(tagId: number): Promise<TagWithId> {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the last used tag IDs.
|
||||
*/
|
||||
export async function fetchLastUsedTagIds(): Promise<number[]> {
|
||||
const url = generateUrl('/apps/systemtags/lastused')
|
||||
|
|
@ -109,8 +111,9 @@ export async function createTag(tag: Tag | ServerTag): Promise<number> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Update a tag on the server.
|
||||
*
|
||||
* @param tag
|
||||
* @param tag - The tag to update
|
||||
*/
|
||||
export async function updateTag(tag: TagWithId): Promise<void> {
|
||||
const path = '/systemtags/' + tag.id
|
||||
|
|
@ -139,8 +142,9 @@ export async function updateTag(tag: TagWithId): Promise<void> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete a tag.
|
||||
*
|
||||
* @param tag
|
||||
* @param tag - The tag to delete
|
||||
*/
|
||||
export async function deleteTag(tag: TagWithId): Promise<void> {
|
||||
const path = '/systemtags/' + tag.id
|
||||
|
|
@ -164,9 +168,10 @@ type TagObjectResponse = {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the objects for a tag.
|
||||
*
|
||||
* @param tag
|
||||
* @param type
|
||||
* @param tag - The tag to get the objects for
|
||||
* @param type - The type of the objects
|
||||
*/
|
||||
export async function getTagObjects(tag: TagWithId, type: string): Promise<TagObjectResponse> {
|
||||
const path = `/systemtags/${tag.id}/${type}`
|
||||
|
|
@ -178,7 +183,7 @@ export async function getTagObjects(tag: TagWithId, type: string): Promise<TagOb
|
|||
</d:prop>
|
||||
</d:propfind>`
|
||||
|
||||
const response = await davClient.stat(path, { data, details: true })
|
||||
const response = await davClient.stat(path, { data, details: true }) as ResponseDataDetailed<FileStat>
|
||||
const etag = response?.data?.props?.getetag || '""'
|
||||
const objects = Object.values(response?.data?.props?.['object-ids'] || []).flat() as TagObject[]
|
||||
|
||||
|
|
@ -228,15 +233,12 @@ export async function setTagObjects(tag: TagWithId, type: string, objectIds: Tag
|
|||
})
|
||||
}
|
||||
|
||||
type OcsResponse = {
|
||||
ocs: NonNullable<unknown>
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the system tags admin restriction setting.
|
||||
*
|
||||
* @param isAllowed
|
||||
* @param isAllowed - True if system tags creation is allowed for non-admins
|
||||
*/
|
||||
export async function updateSystemTagsAdminRestriction(isAllowed: boolean): Promise<OcsResponse> {
|
||||
export async function updateSystemTagsAdminRestriction(isAllowed: boolean): Promise<OCSResponse> {
|
||||
// Convert to string for compatibility
|
||||
const isAllowedString = isAllowed ? '1' : '0'
|
||||
|
||||
|
|
@ -247,9 +249,9 @@ export async function updateSystemTagsAdminRestriction(isAllowed: boolean): Prom
|
|||
|
||||
await confirmPassword()
|
||||
|
||||
const res = await axios.post(url, {
|
||||
const { data } = await axios.post(url, {
|
||||
value: isAllowedString,
|
||||
})
|
||||
|
||||
return res.data
|
||||
return data
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,25 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { getRequestToken, onRequestTokenUpdate } from '@nextcloud/auth'
|
||||
import { generateRemoteUrl } from '@nextcloud/router'
|
||||
import { createClient } from 'webdav'
|
||||
import type { Node } from '@nextcloud/files'
|
||||
import type { FileStat, ResponseDataDetailed } from 'webdav'
|
||||
|
||||
// init webdav client
|
||||
const rootUrl = generateRemoteUrl('dav')
|
||||
export const davClient = createClient(rootUrl)
|
||||
import { getClient, getDefaultPropfind, getRootPath, resultToNode } from '@nextcloud/files/dav'
|
||||
|
||||
export const davClient = getClient()
|
||||
|
||||
// set CSRF token header
|
||||
/**
|
||||
* Fetches a node from the given path
|
||||
*
|
||||
* @param token
|
||||
* @param path - The path to fetch the node from
|
||||
*/
|
||||
function setHeaders(token: string | null) {
|
||||
davClient.setHeaders({
|
||||
// Add this so the server knows it is an request from the browser
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
// Inject user auth
|
||||
requesttoken: token ?? '',
|
||||
})
|
||||
export async function fetchNode(path: string): Promise<Node> {
|
||||
const propfindPayload = getDefaultPropfind()
|
||||
const result = await davClient.stat(`${getRootPath()}${path}`, {
|
||||
details: true,
|
||||
data: propfindPayload,
|
||||
}) as ResponseDataDetailed<FileStat>
|
||||
return resultToNode(result.data)
|
||||
}
|
||||
|
||||
// refresh headers when request token changes
|
||||
onRequestTokenUpdate(setHeaders)
|
||||
setHeaders(getRequestToken())
|
||||
|
|
|
|||
|
|
@ -4,17 +4,18 @@
|
|||
*/
|
||||
|
||||
import type { FileStat, ResponseDataDetailed } from 'webdav'
|
||||
import type { ServerTagWithId, Tag, TagWithId } from '../types.js'
|
||||
import type { ServerTagWithId, Tag, TagWithId } from '../types.ts'
|
||||
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import logger from '../logger.ts'
|
||||
import { formatTag, parseTags } from '../utils.js'
|
||||
import { createTag, fetchTagsPayload } from './api.js'
|
||||
import { davClient } from './davClient.js'
|
||||
import { formatTag, parseTags } from '../utils.ts'
|
||||
import { createTag, fetchTagsPayload } from './api.ts'
|
||||
import { davClient } from './davClient.ts'
|
||||
|
||||
/**
|
||||
* Fetch all tags for a given file (by id).
|
||||
*
|
||||
* @param fileId
|
||||
* @param fileId - The id of the file to fetch tags for
|
||||
*/
|
||||
export async function fetchTagsForFile(fileId: number): Promise<TagWithId[]> {
|
||||
const path = '/systemtags-relations/files/' + fileId
|
||||
|
|
@ -50,9 +51,10 @@ export async function createTagForFile(tag: Tag, fileId: number): Promise<number
|
|||
}
|
||||
|
||||
/**
|
||||
* Set a tag for a given file (by id).
|
||||
*
|
||||
* @param tag
|
||||
* @param fileId
|
||||
* @param tag - The tag to set
|
||||
* @param fileId - The id of the file to set the tag for
|
||||
*/
|
||||
export async function setTagForFile(tag: TagWithId | ServerTagWithId, fileId: number): Promise<void> {
|
||||
const path = '/systemtags-relations/files/' + fileId + '/' + tag.id
|
||||
|
|
@ -69,9 +71,10 @@ export async function setTagForFile(tag: TagWithId | ServerTagWithId, fileId: nu
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete a tag for a given file (by id).
|
||||
*
|
||||
* @param tag
|
||||
* @param fileId
|
||||
* @param tag - The tag to delete
|
||||
* @param fileId - The id of the file to delete the tag for
|
||||
*/
|
||||
export async function deleteTagForFile(tag: TagWithId, fileId: number): Promise<void> {
|
||||
const path = '/systemtags-relations/files/' + fileId + '/' + tag.id
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
/**
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { ContentsWithRoot } from '@nextcloud/files'
|
||||
import type { FileStat, ResponseDataDetailed } from 'webdav'
|
||||
import type { TagWithId } from '../types.ts'
|
||||
|
|
@ -16,8 +17,9 @@ const rootPath = '/systemtags'
|
|||
const client = getClient()
|
||||
|
||||
/**
|
||||
* Format the REPORT payload to filter files by tag
|
||||
*
|
||||
* @param tagId
|
||||
* @param tagId - The tag ID
|
||||
*/
|
||||
function formatReportPayload(tagId: number) {
|
||||
return `<?xml version="1.0"?>
|
||||
|
|
@ -32,8 +34,9 @@ function formatReportPayload(tagId: number) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Convert a tag to a Folder node
|
||||
*
|
||||
* @param tag
|
||||
* @param tag - The tag
|
||||
*/
|
||||
function tagToNode(tag: TagWithId): Folder {
|
||||
return new Folder({
|
||||
|
|
@ -51,8 +54,9 @@ function tagToNode(tag: TagWithId): Folder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the contents of a folder or tag
|
||||
*
|
||||
* @param path
|
||||
* @param path - The path to the folder or tag
|
||||
*/
|
||||
export async function getContents(path = '/'): Promise<ContentsWithRoot> {
|
||||
// List tags in the root
|
||||
|
|
@ -71,9 +75,13 @@ export async function getContents(path = '/'): Promise<ContentsWithRoot> {
|
|||
}
|
||||
}
|
||||
|
||||
const tagId = parseInt(path.split('/', 2)[1])
|
||||
const tag = tagsCache.find((tag) => tag.id === tagId)
|
||||
const tagIdStr = path.split('/', 2)[1]
|
||||
if (!tagIdStr || isNaN(parseInt(tagIdStr))) {
|
||||
throw new Error('Invalid tag ID')
|
||||
}
|
||||
|
||||
const tagId = parseInt(tagIdStr)
|
||||
const tag = tagsCache.find((tag) => tag.id === tagId)
|
||||
if (!tag) {
|
||||
throw new Error('Tag not found')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,9 @@
|
|||
|
||||
import type { INode } from '@nextcloud/files'
|
||||
import type { DAVResultResponseProps } from 'webdav'
|
||||
import type { BaseTag, ServerTag, Tag, TagWithId } from './types.js'
|
||||
import type { BaseTag, ServerTag, Tag, TagWithId } from './types.ts'
|
||||
|
||||
import camelCase from 'camelcase'
|
||||
import Vue from 'vue'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
|
||||
export const defaultBaseTag: BaseTag = {
|
||||
userVisible: true,
|
||||
|
|
@ -16,13 +15,25 @@ export const defaultBaseTag: BaseTag = {
|
|||
canAssign: true,
|
||||
}
|
||||
|
||||
const propertyMappings = Object.freeze({
|
||||
'display-name': 'displayName',
|
||||
'user-visible': 'userVisible',
|
||||
'user-assignable': 'userAssignable',
|
||||
'can-assign': 'canAssign',
|
||||
})
|
||||
|
||||
/**
|
||||
* Parse tags from WebDAV response
|
||||
*
|
||||
* @param tags
|
||||
* @param tags - Array of tags from WebDAV response
|
||||
*/
|
||||
export function parseTags(tags: { props: DAVResultResponseProps }[]): TagWithId[] {
|
||||
return tags.map(({ props }) => Object.fromEntries(Object.entries(props)
|
||||
.map(([key, value]) => [camelCase(key), camelCase(key) === 'displayName' ? String(value) : value]))) as TagWithId[]
|
||||
.map(([key, value]) => {
|
||||
key = propertyMappings[key] ?? key
|
||||
value = key === 'displayName' ? String(value) : value
|
||||
return [key, value]
|
||||
})) as unknown as TagWithId)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -49,8 +60,9 @@ export function parseIdFromLocation(url: string): number {
|
|||
}
|
||||
|
||||
/**
|
||||
* Format a tag for WebDAV operations
|
||||
*
|
||||
* @param initialTag
|
||||
* @param initialTag - Tag to format
|
||||
*/
|
||||
export function formatTag(initialTag: Tag | ServerTag): ServerTag {
|
||||
if ('name' in initialTag && !('displayName' in initialTag)) {
|
||||
|
|
@ -65,8 +77,9 @@ export function formatTag(initialTag: Tag | ServerTag): ServerTag {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get system tags from a node
|
||||
*
|
||||
* @param node
|
||||
* @param node - The node to get tags from
|
||||
*/
|
||||
export function getNodeSystemTags(node: INode): string[] {
|
||||
const attribute = node.attributes?.['system-tags']?.['system-tag']
|
||||
|
|
@ -88,12 +101,14 @@ export function getNodeSystemTags(node: INode): string[] {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set system tags on a node
|
||||
*
|
||||
* @param node
|
||||
* @param tags
|
||||
* @param node - The node to set tags on
|
||||
* @param tags - The tags to set
|
||||
*/
|
||||
export function setNodeSystemTags(node: INode, tags: string[]): void {
|
||||
Vue.set(node.attributes, 'system-tags', {
|
||||
node.attributes['system-tags'] = {
|
||||
'system-tag': tags,
|
||||
})
|
||||
}
|
||||
emit('files:node:updated', node)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import Color from 'color'
|
||||
|
||||
type hexColor = `#${string & (
|
||||
|
|
|
|||
|
|
@ -3,6 +3,64 @@
|
|||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { TagWithId } from '../types.ts'
|
||||
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { onBeforeMount, ref } from 'vue'
|
||||
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
|
||||
import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
|
||||
import SystemTagForm from '../components/SystemTagForm.vue'
|
||||
import SystemTagsCreationControl from '../components/SystemTagsCreationControl.vue'
|
||||
import logger from '../logger.ts'
|
||||
import { fetchTags } from '../services/api.ts'
|
||||
|
||||
const loadingTags = ref(false)
|
||||
const tags = ref<TagWithId[]>([])
|
||||
|
||||
onBeforeMount(async () => {
|
||||
loadingTags.value = true
|
||||
try {
|
||||
tags.value = await fetchTags()
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to load tags'))
|
||||
logger.error('Failed to load tags', { error })
|
||||
}
|
||||
loadingTags.value = false
|
||||
})
|
||||
|
||||
/**
|
||||
* Handle tag creation
|
||||
*
|
||||
* @param tag - The created tag
|
||||
*/
|
||||
function handleCreate(tag: TagWithId) {
|
||||
tags.value.unshift(tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle tag update
|
||||
*
|
||||
* @param tag - The updated tag
|
||||
*/
|
||||
function handleUpdate(tag: TagWithId) {
|
||||
const tagIndex = tags.value.findIndex((currTag) => currTag.id === tag.id)
|
||||
tags.value.splice(tagIndex, 1)
|
||||
tags.value.unshift(tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle tag deletion
|
||||
*
|
||||
* @param tag - The deleted tag
|
||||
*/
|
||||
function handleDelete(tag: TagWithId) {
|
||||
const tagIndex = tags.value.findIndex((currTag) => currTag.id === tag.id)
|
||||
tags.value.splice(tagIndex, 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NcSettingsSection
|
||||
:name="t('systemtags', 'Collaborative tags')"
|
||||
|
|
@ -20,65 +78,3 @@
|
|||
@tag:deleted="handleDelete" />
|
||||
</NcSettingsSection>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { TagWithId } from '../types.js'
|
||||
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import Vue from 'vue'
|
||||
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
|
||||
import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
|
||||
import SystemTagForm from '../components/SystemTagForm.vue'
|
||||
import SystemTagsCreationControl from '../components/SystemTagsCreationControl.vue'
|
||||
import logger from '../logger.js'
|
||||
import { fetchTags } from '../services/api.js'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'SystemTagsSection',
|
||||
|
||||
components: {
|
||||
NcLoadingIcon,
|
||||
NcSettingsSection,
|
||||
SystemTagForm,
|
||||
SystemTagsCreationControl,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loadingTags: false,
|
||||
tags: [] as TagWithId[],
|
||||
}
|
||||
},
|
||||
|
||||
async created() {
|
||||
this.loadingTags = true
|
||||
try {
|
||||
this.tags = await fetchTags()
|
||||
} catch (error) {
|
||||
showError(t('systemtags', 'Failed to load tags'))
|
||||
logger.error('Failed to load tags', { error })
|
||||
}
|
||||
this.loadingTags = false
|
||||
},
|
||||
|
||||
methods: {
|
||||
t,
|
||||
|
||||
handleCreate(tag: TagWithId) {
|
||||
this.tags.unshift(tag)
|
||||
},
|
||||
|
||||
handleUpdate(tag: TagWithId) {
|
||||
const tagIndex = this.tags.findIndex((currTag) => currTag.id === tag.id)
|
||||
this.tags.splice(tagIndex, 1)
|
||||
this.tags.unshift(tag)
|
||||
},
|
||||
|
||||
handleDelete(tag: TagWithId) {
|
||||
const tagIndex = this.tags.findIndex((currTag) => currTag.id === tag.id)
|
||||
this.tags.splice(tagIndex, 1)
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -70,10 +70,6 @@ module.exports = {
|
|||
'vue-settings-personal-webauthn': path.join(__dirname, 'apps/settings/src', 'main-personal-webauth.js'),
|
||||
'declarative-settings-forms': path.join(__dirname, 'apps/settings/src', 'main-declarative-settings-forms.ts'),
|
||||
},
|
||||
systemtags: {
|
||||
init: path.join(__dirname, 'apps/systemtags/src', 'init.ts'),
|
||||
admin: path.join(__dirname, 'apps/systemtags/src', 'admin.ts'),
|
||||
},
|
||||
updatenotification: {
|
||||
init: path.join(__dirname, 'apps/updatenotification/src', 'init.ts'),
|
||||
'view-changelog-page': path.join(__dirname, 'apps/updatenotification/src', 'view-changelog-page.ts'),
|
||||
|
|
|
|||
|
|
@ -50,6 +50,10 @@ const modules = {
|
|||
sharebymail: {
|
||||
'admin-settings': resolve(import.meta.dirname, 'apps/sharebymail/src', 'settings-admin.ts'),
|
||||
},
|
||||
systemtags: {
|
||||
init: resolve(import.meta.dirname, 'apps/systemtags/src', 'init.ts'),
|
||||
admin: resolve(import.meta.dirname, 'apps/systemtags/src', 'admin.ts'),
|
||||
},
|
||||
theming: {
|
||||
'settings-personal': resolve(import.meta.dirname, 'apps/theming/src', 'settings-personal.ts'),
|
||||
'settings-admin': resolve(import.meta.dirname, 'apps/theming/src', 'settings-admin.ts'),
|
||||
|
|
|
|||
2
dist/1142-1142.js
vendored
2
dist/1142-1142.js
vendored
File diff suppressed because one or more lines are too long
1
dist/1142-1142.js.map
vendored
1
dist/1142-1142.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/1142-1142.js.map.license
vendored
1
dist/1142-1142.js.map.license
vendored
|
|
@ -1 +0,0 @@
|
|||
1142-1142.js.license
|
||||
2
dist/1598-1598.js
vendored
Normal file
2
dist/1598-1598.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/1598-1598.js.map
vendored
Normal file
1
dist/1598-1598.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/1598-1598.js.map.license
vendored
Symbolic link
1
dist/1598-1598.js.map.license
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
1598-1598.js.license
|
||||
2
dist/2605-2605.js
vendored
2
dist/2605-2605.js
vendored
File diff suppressed because one or more lines are too long
459
dist/2605-2605.js.license
vendored
459
dist/2605-2605.js.license
vendored
|
|
@ -1,459 +0,0 @@
|
|||
SPDX-License-Identifier: MIT
|
||||
SPDX-License-Identifier: ISC
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
SPDX-License-Identifier: (MPL-2.0 OR Apache-2.0)
|
||||
SPDX-FileCopyrightText: xiaokai <kexiaokai@gmail.com>
|
||||
SPDX-FileCopyrightText: string_decoder developers
|
||||
SPDX-FileCopyrightText: readable-stream developers
|
||||
SPDX-FileCopyrightText: qs developers
|
||||
SPDX-FileCopyrightText: jden <jason@denizac.org>
|
||||
SPDX-FileCopyrightText: inherits developers
|
||||
SPDX-FileCopyrightText: escape-html developers
|
||||
SPDX-FileCopyrightText: defunctzombie
|
||||
SPDX-FileCopyrightText: debounce developers
|
||||
SPDX-FileCopyrightText: atomiks
|
||||
SPDX-FileCopyrightText: Varun A P
|
||||
SPDX-FileCopyrightText: Tobias Koppers @sokra
|
||||
SPDX-FileCopyrightText: T. Jameson Little <t.jameson.little@gmail.com>
|
||||
SPDX-FileCopyrightText: Sindre Sorhus
|
||||
SPDX-FileCopyrightText: Roman Shtylman <shtylman@gmail.com>
|
||||
SPDX-FileCopyrightText: Rob Cresswell <robcresswell@pm.me>
|
||||
SPDX-FileCopyrightText: Raynos <raynos2@gmail.com>
|
||||
SPDX-FileCopyrightText: Perry Mitchell <perry@perrymitchell.net>
|
||||
SPDX-FileCopyrightText: Paul Vorbach <paul@vorba.ch> (http://paul.vorba.ch)
|
||||
SPDX-FileCopyrightText: Paul Vorbach <paul@vorb.de> (http://vorb.de)
|
||||
SPDX-FileCopyrightText: Olivier Scherrer <pode.fr@gmail.com>
|
||||
SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
|
||||
SPDX-FileCopyrightText: Nathan Rajlich <nathan@tootallnate.net> (http://n8.io/)
|
||||
SPDX-FileCopyrightText: Matt Zabriskie
|
||||
SPDX-FileCopyrightText: Mathias Bynens
|
||||
SPDX-FileCopyrightText: Julian Gruber
|
||||
SPDX-FileCopyrightText: Joyent
|
||||
SPDX-FileCopyrightText: José F. Romaniello <jfromaniello@gmail.com> (http://joseoncode.com)
|
||||
SPDX-FileCopyrightText: Jordan Harband <ljharb@gmail.com>
|
||||
SPDX-FileCopyrightText: Jordan Harband
|
||||
SPDX-FileCopyrightText: Jordan Harbamd <ljharb@gmail.com>
|
||||
SPDX-FileCopyrightText: John Hiesey
|
||||
SPDX-FileCopyrightText: James Halliday
|
||||
SPDX-FileCopyrightText: Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)
|
||||
SPDX-FileCopyrightText: Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
|
||||
SPDX-FileCopyrightText: Guillaume Chau <guillaume.b.chau@gmail.com>
|
||||
SPDX-FileCopyrightText: Guillaume Chau
|
||||
SPDX-FileCopyrightText: GitHub Inc.
|
||||
SPDX-FileCopyrightText: Feross Aboukhadijeh
|
||||
SPDX-FileCopyrightText: Felix Boehm <me@feedic.com>
|
||||
SPDX-FileCopyrightText: Evan You
|
||||
SPDX-FileCopyrightText: Eduardo San Martin Morote
|
||||
SPDX-FileCopyrightText: Dylan Piercey <pierceydylan@gmail.com>
|
||||
SPDX-FileCopyrightText: Dr.-Ing. Mario Heiderich, Cure53 <mario@cure53.de> (https://cure53.de/)
|
||||
SPDX-FileCopyrightText: David Clark
|
||||
SPDX-FileCopyrightText: Christoph Wurst
|
||||
SPDX-FileCopyrightText: Ben Drucker
|
||||
SPDX-FileCopyrightText: Arnout Kazemier
|
||||
SPDX-FileCopyrightText: Anthony Fu <https://github.com/antfu>
|
||||
SPDX-FileCopyrightText: Anthony Fu <anthonyfu117@hotmail.com>
|
||||
SPDX-FileCopyrightText: Amit Gupta (https://solothought.com)
|
||||
SPDX-FileCopyrightText: Amit Gupta (https://amitkumargupta.work/)
|
||||
SPDX-FileCopyrightText: @nextcloud/dialogs developers
|
||||
|
||||
|
||||
This file is generated from multiple sources. Included packages:
|
||||
- @buttercup/fetch
|
||||
- version: 0.2.1
|
||||
- license: MIT
|
||||
- @floating-ui/core
|
||||
- version: 1.7.3
|
||||
- license: MIT
|
||||
- @floating-ui/utils
|
||||
- version: 0.2.10
|
||||
- license: MIT
|
||||
- @nextcloud/auth
|
||||
- version: 2.5.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/axios
|
||||
- version: 2.5.2
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/browser-storage
|
||||
- version: 0.5.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/capabilities
|
||||
- version: 1.2.1
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/vue
|
||||
- version: 9.3.3
|
||||
- license: AGPL-3.0-or-later
|
||||
- @vueuse/core
|
||||
- version: 14.1.0
|
||||
- license: MIT
|
||||
- @vueuse/shared
|
||||
- version: 14.1.0
|
||||
- license: MIT
|
||||
- focus-trap
|
||||
- version: 7.6.6
|
||||
- license: MIT
|
||||
- vue-router
|
||||
- version: 4.6.4
|
||||
- license: MIT
|
||||
- vue
|
||||
- version: 3.5.26
|
||||
- license: MIT
|
||||
- @nextcloud/dialogs
|
||||
- version: 7.2.0
|
||||
- license: AGPL-3.0-or-later
|
||||
- semver
|
||||
- version: 7.7.2
|
||||
- license: ISC
|
||||
- @nextcloud/event-bus
|
||||
- version: 3.3.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/initial-state
|
||||
- version: 3.0.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/l10n
|
||||
- version: 3.4.1
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/logger
|
||||
- version: 3.0.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/vue
|
||||
- version: 9.2.0
|
||||
- license: AGPL-3.0-or-later
|
||||
- @vue/reactivity
|
||||
- version: 3.5.24
|
||||
- license: MIT
|
||||
- @vue/runtime-core
|
||||
- version: 3.5.24
|
||||
- license: MIT
|
||||
- @vue/runtime-dom
|
||||
- version: 3.5.24
|
||||
- license: MIT
|
||||
- @vue/shared
|
||||
- version: 3.5.24
|
||||
- license: MIT
|
||||
- vue-router
|
||||
- version: 4.6.3
|
||||
- license: MIT
|
||||
- vue
|
||||
- version: 3.5.24
|
||||
- license: MIT
|
||||
- @nextcloud/password-confirmation
|
||||
- version: 6.0.2
|
||||
- license: MIT
|
||||
- @nextcloud/paths
|
||||
- version: 3.0.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/router
|
||||
- version: 3.1.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/vue
|
||||
- version: 8.35.3
|
||||
- license: AGPL-3.0-or-later
|
||||
- @vue/devtools-api
|
||||
- version: 6.6.4
|
||||
- license: MIT
|
||||
- @vue/reactivity
|
||||
- version: 3.5.26
|
||||
- license: MIT
|
||||
- @vue/runtime-core
|
||||
- version: 3.5.26
|
||||
- license: MIT
|
||||
- @vue/runtime-dom
|
||||
- version: 3.5.26
|
||||
- license: MIT
|
||||
- @vue/shared
|
||||
- version: 3.5.26
|
||||
- license: MIT
|
||||
- @vueuse/core
|
||||
- version: 11.3.0
|
||||
- license: MIT
|
||||
- @vueuse/shared
|
||||
- version: 11.3.0
|
||||
- license: MIT
|
||||
- available-typed-arrays
|
||||
- version: 1.0.7
|
||||
- license: MIT
|
||||
- axios
|
||||
- version: 1.12.2
|
||||
- license: MIT
|
||||
- balanced-match
|
||||
- version: 1.0.2
|
||||
- license: MIT
|
||||
- base-64
|
||||
- version: 1.0.0
|
||||
- license: MIT
|
||||
- base64-js
|
||||
- version: 1.5.1
|
||||
- license: MIT
|
||||
- brace-expansion
|
||||
- version: 2.0.2
|
||||
- license: MIT
|
||||
- builtin-status-codes
|
||||
- version: 3.0.0
|
||||
- license: MIT
|
||||
- byte-length
|
||||
- version: 1.0.2
|
||||
- license: MIT
|
||||
- call-bind-apply-helpers
|
||||
- version: 1.0.2
|
||||
- license: MIT
|
||||
- call-bind
|
||||
- version: 1.0.8
|
||||
- license: MIT
|
||||
- call-bound
|
||||
- version: 1.0.4
|
||||
- license: MIT
|
||||
- camelcase
|
||||
- version: 9.0.0
|
||||
- license: MIT
|
||||
- charenc
|
||||
- version: 0.0.2
|
||||
- license: BSD-3-Clause
|
||||
- crypt
|
||||
- version: 0.0.2
|
||||
- license: BSD-3-Clause
|
||||
- css-loader
|
||||
- version: 7.1.2
|
||||
- license: MIT
|
||||
- debounce
|
||||
- version: 3.0.0
|
||||
- license: MIT
|
||||
- define-data-property
|
||||
- version: 1.1.4
|
||||
- license: MIT
|
||||
- dompurify
|
||||
- version: 3.3.1
|
||||
- license: (MPL-2.0 OR Apache-2.0)
|
||||
- dunder-proto
|
||||
- version: 1.0.1
|
||||
- license: MIT
|
||||
- es-define-property
|
||||
- version: 1.0.1
|
||||
- license: MIT
|
||||
- es-errors
|
||||
- version: 1.3.0
|
||||
- license: MIT
|
||||
- es-object-atoms
|
||||
- version: 1.1.1
|
||||
- license: MIT
|
||||
- escape-html
|
||||
- version: 1.0.3
|
||||
- license: MIT
|
||||
- events
|
||||
- version: 3.3.0
|
||||
- license: MIT
|
||||
- floating-vue
|
||||
- version: 1.0.0-beta.19
|
||||
- license: MIT
|
||||
- focus-trap
|
||||
- version: 7.8.0
|
||||
- license: MIT
|
||||
- for-each
|
||||
- version: 0.3.5
|
||||
- license: MIT
|
||||
- function-bind
|
||||
- version: 1.1.2
|
||||
- license: MIT
|
||||
- generator-function
|
||||
- version: 2.0.1
|
||||
- license: MIT
|
||||
- get-intrinsic
|
||||
- version: 1.3.0
|
||||
- license: MIT
|
||||
- get-proto
|
||||
- version: 1.0.1
|
||||
- license: MIT
|
||||
- gopd
|
||||
- version: 1.2.0
|
||||
- license: MIT
|
||||
- has-property-descriptors
|
||||
- version: 1.0.2
|
||||
- license: MIT
|
||||
- has-symbols
|
||||
- version: 1.1.0
|
||||
- license: MIT
|
||||
- has-tostringtag
|
||||
- version: 1.0.2
|
||||
- license: MIT
|
||||
- hasown
|
||||
- version: 2.0.2
|
||||
- license: MIT
|
||||
- hot-patcher
|
||||
- version: 2.0.1
|
||||
- license: MIT
|
||||
- https-browserify
|
||||
- version: 1.0.0
|
||||
- license: MIT
|
||||
- ieee754
|
||||
- version: 1.2.1
|
||||
- license: BSD-3-Clause
|
||||
- inherits
|
||||
- version: 2.0.4
|
||||
- license: ISC
|
||||
- is-arguments
|
||||
- version: 1.2.0
|
||||
- license: MIT
|
||||
- is-buffer
|
||||
- version: 1.1.6
|
||||
- license: MIT
|
||||
- is-callable
|
||||
- version: 1.2.7
|
||||
- license: MIT
|
||||
- is-generator-function
|
||||
- version: 1.1.2
|
||||
- license: MIT
|
||||
- is-regex
|
||||
- version: 1.2.1
|
||||
- license: MIT
|
||||
- is-typed-array
|
||||
- version: 1.1.15
|
||||
- license: MIT
|
||||
- layerr
|
||||
- version: 3.0.0
|
||||
- license: MIT
|
||||
- math-intrinsics
|
||||
- version: 1.1.0
|
||||
- license: MIT
|
||||
- md5
|
||||
- version: 2.3.0
|
||||
- license: BSD-3-Clause
|
||||
- nested-property
|
||||
- version: 4.0.0
|
||||
- license: MIT
|
||||
- buffer
|
||||
- version: 6.0.3
|
||||
- license: MIT
|
||||
- object-inspect
|
||||
- version: 1.13.4
|
||||
- license: MIT
|
||||
- path-posix
|
||||
- version: 1.0.0
|
||||
- license: ISC
|
||||
- possible-typed-array-names
|
||||
- version: 1.1.0
|
||||
- license: MIT
|
||||
- process
|
||||
- version: 0.11.10
|
||||
- license: MIT
|
||||
- punycode
|
||||
- version: 1.4.1
|
||||
- license: MIT
|
||||
- qs
|
||||
- version: 6.14.1
|
||||
- license: BSD-3-Clause
|
||||
- querystringify
|
||||
- version: 2.2.0
|
||||
- license: MIT
|
||||
- requires-port
|
||||
- version: 1.0.0
|
||||
- license: MIT
|
||||
- safe-buffer
|
||||
- version: 5.2.1
|
||||
- license: MIT
|
||||
- safe-regex-test
|
||||
- version: 1.1.0
|
||||
- license: MIT
|
||||
- set-function-length
|
||||
- version: 1.2.2
|
||||
- license: MIT
|
||||
- side-channel-list
|
||||
- version: 1.0.0
|
||||
- license: MIT
|
||||
- side-channel-map
|
||||
- version: 1.0.1
|
||||
- license: MIT
|
||||
- side-channel-weakmap
|
||||
- version: 1.0.2
|
||||
- license: MIT
|
||||
- side-channel
|
||||
- version: 1.1.0
|
||||
- license: MIT
|
||||
- readable-stream
|
||||
- version: 3.6.2
|
||||
- license: MIT
|
||||
- stream-browserify
|
||||
- version: 3.0.0
|
||||
- license: MIT
|
||||
- readable-stream
|
||||
- version: 3.6.2
|
||||
- license: MIT
|
||||
- stream-http
|
||||
- version: 3.2.0
|
||||
- license: MIT
|
||||
- string_decoder
|
||||
- version: 1.3.0
|
||||
- license: MIT
|
||||
- style-loader
|
||||
- version: 4.0.0
|
||||
- license: MIT
|
||||
- tabbable
|
||||
- version: 6.4.0
|
||||
- license: MIT
|
||||
- toastify-js
|
||||
- version: 1.12.0
|
||||
- license: MIT
|
||||
- url-join
|
||||
- version: 5.0.0
|
||||
- license: MIT
|
||||
- url-parse
|
||||
- version: 1.5.10
|
||||
- license: MIT
|
||||
- url
|
||||
- version: 0.11.4
|
||||
- license: MIT
|
||||
- util-deprecate
|
||||
- version: 1.0.2
|
||||
- license: MIT
|
||||
- util
|
||||
- version: 0.12.5
|
||||
- license: MIT
|
||||
- vue-color
|
||||
- version: 2.8.2
|
||||
- license: MIT
|
||||
- vue-demi
|
||||
- version: 0.14.10
|
||||
- license: MIT
|
||||
- vue-loader
|
||||
- version: 15.11.1
|
||||
- license: MIT
|
||||
- vue-material-design-icons
|
||||
- version: 5.3.1
|
||||
- license: MIT
|
||||
- vue
|
||||
- version: 2.7.16
|
||||
- license: MIT
|
||||
- entities
|
||||
- version: 6.0.1
|
||||
- license: BSD-2-Clause
|
||||
- fast-xml-parser
|
||||
- version: 4.5.3
|
||||
- license: MIT
|
||||
- minimatch
|
||||
- version: 9.0.5
|
||||
- license: ISC
|
||||
- strnum
|
||||
- version: 1.1.2
|
||||
- license: MIT
|
||||
- webdav
|
||||
- version: 5.8.0
|
||||
- license: MIT
|
||||
- which-typed-array
|
||||
- version: 1.1.19
|
||||
- license: MIT
|
||||
- xtend
|
||||
- version: 4.0.2
|
||||
- license: MIT
|
||||
- base64-js
|
||||
- version: 1.5.1
|
||||
- license: MIT
|
||||
- buffer
|
||||
- version: 5.7.1
|
||||
- license: MIT
|
||||
- ieee754
|
||||
- version: 1.2.1
|
||||
- license: BSD-3-Clause
|
||||
- nextcloud
|
||||
- version: 1.0.0
|
||||
- license: AGPL-3.0-or-later
|
||||
1
dist/2605-2605.js.map
vendored
1
dist/2605-2605.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/2605-2605.js.map.license
vendored
1
dist/2605-2605.js.map.license
vendored
|
|
@ -1 +0,0 @@
|
|||
2605-2605.js.license
|
||||
2
dist/6692-6692.js
vendored
2
dist/6692-6692.js
vendored
File diff suppressed because one or more lines are too long
1
dist/6692-6692.js.map
vendored
1
dist/6692-6692.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/6692-6692.js.map.license
vendored
1
dist/6692-6692.js.map.license
vendored
|
|
@ -1 +0,0 @@
|
|||
6692-6692.js.license
|
||||
2
dist/9429-9429.js
vendored
Normal file
2
dist/9429-9429.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/9429-9429.js.map
vendored
Normal file
1
dist/9429-9429.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/9429-9429.js.map.license
vendored
Symbolic link
1
dist/9429-9429.js.map.license
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
9429-9429.js.license
|
||||
2
dist/AuthMechanismRsa-CpHwZ9ay.chunk.mjs
vendored
Normal file
2
dist/AuthMechanismRsa-CpHwZ9ay.chunk.mjs
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
import{b as g,q as y,s as v,c as p,u as o,o as n,J as h,w as _,g as V,t as b,v as x,r as M,j as d,e as f,F as q,C as w,E as K,G as U}from"./runtime-dom.esm-bundler-Bpt0bWgp.chunk.mjs";import{c as j}from"./index-DNyFZ0q1.chunk.mjs";import{a as C}from"./index-JpgrUA2Z-Btt9G24P.chunk.mjs";import{t as s}from"./translation-DoG5ZELJ-Bni_xMHF.chunk.mjs";import{g as E}from"./createElementId-DhjFt1I9-COdYgGCC.chunk.mjs";import{N}from"./logger-D3RVzcfQ-DhmPs7Vh.chunk.mjs";import{N as S}from"./NcSelect-rH_0zphV-RrpfdNvw.chunk.mjs";import{N as A}from"./NcCheckboxRadioSwitch-ChNSuhe6-D-zzyccP.chunk.mjs";import{N as L}from"./NcPasswordField-DYF18Cdo-BbpNSGg_.chunk.mjs";import{_ as z}from"./TrashCanOutline-BwjpsJlQ.chunk.mjs";import{C as c,a as k}from"./types-C3MFFrct.chunk.mjs";import{l as B}from"./logger-resIultJ.chunk.mjs";const P=g({__name:"ConfigurationEntry",props:y({configKey:{},configOption:{}},{modelValue:{type:[String,Boolean],default:""},modelModifiers:{}}),emits:["update:modelValue"],setup(e){const a=v(e,"modelValue");return(t,i)=>e.configOption.type!==o(c).Boolean?(n(),p(h(e.configOption.type===o(c).Password?o(L):o(z)),{key:0,modelValue:a.value,"onUpdate:modelValue":i[0]||(i[0]=l=>a.value=l),name:e.configKey,required:!(e.configOption.flags&o(k).Optional),label:e.configOption.value,title:e.configOption.tooltip},null,8,["modelValue","name","required","label","title"])):(n(),p(o(A),{key:1,modelValue:a.value,"onUpdate:modelValue":i[1]||(i[1]=l=>a.value=l),type:"switch",title:e.configOption.tooltip},{default:_(()=>[V(b(e.configOption.value),1)]),_:1},8,["modelValue","title"]))}}),R=g({__name:"AuthMechanismRsa",props:y({authMechanism:{}},{modelValue:{required:!0},modelModifiers:{}}),emits:["update:modelValue"],setup(e){const a=v(e,"modelValue"),t=M();x(t,()=>{t.value&&(a.value.private_key="",a.value.public_key="")});async function i(){try{const{data:l}=await j.post(E("/apps/files_external/ajax/public_key.php"),{keyLength:t.value});a.value.private_key=l.data.private_key,a.value.public_key=l.data.public_key}catch(l){B.error("Error generating RSA key pair",{error:l}),C(s("files_external","Error generating key pair"))}}return(l,m)=>(n(),d("div",null,[(n(!0),d(q,null,w(e.authMechanism.configuration,(r,u)=>K((n(),p(P,{key:r.value,modelValue:a.value[u],"onUpdate:modelValue":O=>a.value[u]=O,configKey:u,configOption:r},null,8,["modelValue","onUpdate:modelValue","configKey","configOption"])),[[U,!(r.flags&o(k).Hidden)]])),128)),f(o(S),{modelValue:t.value,"onUpdate:modelValue":m[0]||(m[0]=r=>t.value=r),clearable:!1,inputLabel:o(s)("files_external","Key size"),options:[1024,2048,4096],required:""},null,8,["modelValue","inputLabel"]),f(o(N),{disabled:!t.value,wide:"",onClick:i},{default:_(()=>[V(b(o(s)("files_external","Generate keys")),1)]),_:1},8,["disabled"])]))}}),$=Object.freeze(Object.defineProperty({__proto__:null,default:R},Symbol.toStringTag,{value:"Module"}));export{$ as A,P as _};
|
||||
//# sourceMappingURL=AuthMechanismRsa-CpHwZ9ay.chunk.mjs.map
|
||||
File diff suppressed because one or more lines are too long
2
dist/AuthMechanismRsa-mz_2_HLA.chunk.mjs
vendored
2
dist/AuthMechanismRsa-mz_2_HLA.chunk.mjs
vendored
|
|
@ -1,2 +0,0 @@
|
|||
import{b as g,p as y,q as v,c as p,u as o,o as n,K as h,w as _,g as V,t as b,s as x,r as K,j as d,e as f,F as M,C as q,E as w,G as U}from"./runtime-dom.esm-bundler-CBTFVsZ1.chunk.mjs";import{c as j}from"./index-CeZOua3E.chunk.mjs";import{a as C}from"./index-JpgrUA2Z-Cg8qxgsw.chunk.mjs";import{t as s}from"./translation-DoG5ZELJ-DRDc35uB.chunk.mjs";import{g as E}from"./createElementId-DhjFt1I9-CbtAsEAv.chunk.mjs";import{b as S}from"./NcNoteCard-Cok_4Fld-CEiA7MRo.chunk.mjs";import{N as A}from"./NcSelect-rH_0zphV-DIrEVY9H.chunk.mjs";import{N as L}from"./NcCheckboxRadioSwitch-ChNSuhe6-J_hhfCys.chunk.mjs";import{N}from"./NcPasswordField-DYF18Cdo-CDrhVNCN.chunk.mjs";import{_ as z}from"./TrashCanOutline-t5kbV5NX.chunk.mjs";import{C as c,a as k}from"./types-CxkvAyaz.chunk.mjs";import{l as B}from"./logger-resIultJ.chunk.mjs";const P=g({__name:"ConfigurationEntry",props:y({configKey:{},configOption:{}},{modelValue:{type:[String,Boolean],default:""},modelModifiers:{}}),emits:["update:modelValue"],setup(e){const a=v(e,"modelValue");return(t,i)=>e.configOption.type!==o(c).Boolean?(n(),p(h(e.configOption.type===o(c).Password?o(N):o(z)),{key:0,modelValue:a.value,"onUpdate:modelValue":i[0]||(i[0]=l=>a.value=l),name:e.configKey,required:!(e.configOption.flags&o(k).Optional),label:e.configOption.value,title:e.configOption.tooltip},null,8,["modelValue","name","required","label","title"])):(n(),p(o(L),{key:1,modelValue:a.value,"onUpdate:modelValue":i[1]||(i[1]=l=>a.value=l),type:"switch",title:e.configOption.tooltip},{default:_(()=>[V(b(e.configOption.value),1)]),_:1},8,["modelValue","title"]))}}),R=g({__name:"AuthMechanismRsa",props:y({authMechanism:{}},{modelValue:{required:!0},modelModifiers:{}}),emits:["update:modelValue"],setup(e){const a=v(e,"modelValue"),t=K();x(t,()=>{t.value&&(a.value.private_key="",a.value.public_key="")});async function i(){try{const{data:l}=await j.post(E("/apps/files_external/ajax/public_key.php"),{keyLength:t.value});a.value.private_key=l.data.private_key,a.value.public_key=l.data.public_key}catch(l){B.error("Error generating RSA key pair",{error:l}),C(s("files_external","Error generating key pair"))}}return(l,m)=>(n(),d("div",null,[(n(!0),d(M,null,q(e.authMechanism.configuration,(r,u)=>w((n(),p(P,{key:r.value,modelValue:a.value[u],"onUpdate:modelValue":O=>a.value[u]=O,configKey:u,configOption:r},null,8,["modelValue","onUpdate:modelValue","configKey","configOption"])),[[U,!(r.flags&o(k).Hidden)]])),128)),f(o(A),{modelValue:t.value,"onUpdate:modelValue":m[0]||(m[0]=r=>t.value=r),clearable:!1,inputLabel:o(s)("files_external","Key size"),options:[1024,2048,4096],required:""},null,8,["modelValue","inputLabel"]),f(o(S),{disabled:!t.value,wide:"",onClick:i},{default:_(()=>[V(b(o(s)("files_external","Generate keys")),1)]),_:1},8,["disabled"])]))}}),$=Object.freeze(Object.defineProperty({__proto__:null,default:R},Symbol.toStringTag,{value:"Module"}));export{$ as A,P as _};
|
||||
//# sourceMappingURL=AuthMechanismRsa-mz_2_HLA.chunk.mjs.map
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
import{r as g,u as h,_ as p,b as C}from"./createElementId-DhjFt1I9-CbtAsEAv.chunk.mjs";import{b as _,j as i,o as e,k as o,l as s,m as y,g as b,t as r,u as d,e as k,y as u}from"./runtime-dom.esm-bundler-CBTFVsZ1.chunk.mjs";import{a as H}from"./index-xFugdZPW.chunk.mjs";const A={name:"HelpCircleIcon",emits:["click"],props:{title:{type:String},fillColor:{type:String,default:"currentColor"},size:{type:Number,default:24}}},v=["aria-hidden","aria-label"],V=["fill","width","height"],w={d:"M15.07,11.25L14.17,12.17C13.45,12.89 13,13.5 13,15H11V14.5C11,13.39 11.45,12.39 12.17,11.67L13.41,10.41C13.78,10.05 14,9.55 14,9C14,7.89 13.1,7 12,7A2,2 0 0,0 10,9H8A4,4 0 0,1 12,5A4,4 0 0,1 16,9C16,9.88 15.64,10.67 15.07,11.25M13,19H11V17H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z"},z={key:0};function M(a,l,t,c,f,m){return e(),i("span",u(a.$attrs,{"aria-hidden":t.title?null:"true","aria-label":t.title,class:"material-design-icon help-circle-icon",role:"img",onClick:l[0]||(l[0]=n=>a.$emit("click",n))}),[(e(),i("svg",{fill:t.fillColor,class:"material-design-icon__svg",width:t.size,height:t.size,viewBox:"0 0 24 24"},[o("path",w,[t.title?(e(),i("title",z,r(t.title),1)):s("",!0)])],8,V))],16,v)}const S=p(A,[["render",M]]);g(h);const x={class:"settings-section"},$={class:"settings-section__name"},I=["aria-label","href","title"],N={key:0,class:"settings-section__desc"},U=_({__name:"NcSettingsSection",props:{name:{},description:{default:""},docUrl:{default:""}},setup(a){const l=C("External documentation");return(t,c)=>(e(),i("div",x,[o("h2",$,[b(r(t.name)+" ",1),t.docUrl?(e(),i("a",{key:0,"aria-label":d(l),class:"settings-section__info",href:t.docUrl,rel:"noreferrer nofollow",target:"_blank",title:d(l)},[k(S,{size:20})],8,I)):s("",!0)]),t.description?(e(),i("p",N,r(t.description),1)):s("",!0),y(t.$slots,"default",{},void 0,!0)]))}}),T=p(U,[["__scopeId","data-v-9cedb949"]]),B={name:"ContentCopyIcon",emits:["click"],props:{title:{type:String},fillColor:{type:String,default:"currentColor"},size:{type:Number,default:24}}},L=["aria-hidden","aria-label"],Z=["fill","width","height"],j={d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"},E={key:0};function q(a,l,t,c,f,m){return e(),i("span",u(a.$attrs,{"aria-hidden":t.title?null:"true","aria-label":t.title,class:"material-design-icon content-copy-icon",role:"img",onClick:l[0]||(l[0]=n=>a.$emit("click",n))}),[(e(),i("svg",{fill:t.fillColor,class:"material-design-icon__svg",width:t.size,height:t.size,viewBox:"0 0 24 24"},[o("path",j,[t.title?(e(),i("title",E,r(t.title),1)):s("",!0)])],8,Z))],16,L)}const G=H(B,[["render",q]]);export{G as I,T as N};
|
||||
//# sourceMappingURL=ContentCopy-2LIQisfo.chunk.mjs.map
|
||||
import{r as g,z as h,_ as p,a as C}from"./createElementId-DhjFt1I9-COdYgGCC.chunk.mjs";import{b as _,j as i,o as e,k as o,l as s,m as k,g as y,t as r,u as d,e as H,z as f}from"./runtime-dom.esm-bundler-Bpt0bWgp.chunk.mjs";import{a as b}from"./index-xFugdZPW.chunk.mjs";const A={name:"HelpCircleIcon",emits:["click"],props:{title:{type:String},fillColor:{type:String,default:"currentColor"},size:{type:Number,default:24}}},v=["aria-hidden","aria-label"],z=["fill","width","height"],V={d:"M15.07,11.25L14.17,12.17C13.45,12.89 13,13.5 13,15H11V14.5C11,13.39 11.45,12.39 12.17,11.67L13.41,10.41C13.78,10.05 14,9.55 14,9C14,7.89 13.1,7 12,7A2,2 0 0,0 10,9H8A4,4 0 0,1 12,5A4,4 0 0,1 16,9C16,9.88 15.64,10.67 15.07,11.25M13,19H11V17H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z"},w={key:0};function M(a,l,t,c,m,u){return e(),i("span",f(a.$attrs,{"aria-hidden":t.title?null:"true","aria-label":t.title,class:"material-design-icon help-circle-icon",role:"img",onClick:l[0]||(l[0]=n=>a.$emit("click",n))}),[(e(),i("svg",{fill:t.fillColor,class:"material-design-icon__svg",width:t.size,height:t.size,viewBox:"0 0 24 24"},[o("path",V,[t.title?(e(),i("title",w,r(t.title),1)):s("",!0)])],8,z))],16,v)}const S=p(A,[["render",M]]);g(h);const x={class:"settings-section"},$={class:"settings-section__name"},I=["aria-label","href","title"],N={key:0,class:"settings-section__desc"},U=_({__name:"NcSettingsSection",props:{name:{},description:{default:""},docUrl:{default:""}},setup(a){const l=C("External documentation");return(t,c)=>(e(),i("div",x,[o("h2",$,[y(r(t.name)+" ",1),t.docUrl?(e(),i("a",{key:0,"aria-label":d(l),class:"settings-section__info",href:t.docUrl,rel:"noreferrer nofollow",target:"_blank",title:d(l)},[H(S,{size:20})],8,I)):s("",!0)]),t.description?(e(),i("p",N,r(t.description),1)):s("",!0),k(t.$slots,"default",{},void 0,!0)]))}}),T=p(U,[["__scopeId","data-v-9cedb949"]]),B={name:"ContentCopyIcon",emits:["click"],props:{title:{type:String},fillColor:{type:String,default:"currentColor"},size:{type:Number,default:24}}},L=["aria-hidden","aria-label"],Z=["fill","width","height"],j={d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"},E={key:0};function q(a,l,t,c,m,u){return e(),i("span",f(a.$attrs,{"aria-hidden":t.title?null:"true","aria-label":t.title,class:"material-design-icon content-copy-icon",role:"img",onClick:l[0]||(l[0]=n=>a.$emit("click",n))}),[(e(),i("svg",{fill:t.fillColor,class:"material-design-icon__svg",width:t.size,height:t.size,viewBox:"0 0 24 24"},[o("path",j,[t.title?(e(),i("title",E,r(t.title),1)):s("",!0)])],8,Z))],16,L)}const G=b(B,[["render",q]]);export{G as I,T as N};
|
||||
//# sourceMappingURL=ContentCopy-B8R56AYC.chunk.mjs.map
|
||||
File diff suppressed because one or more lines are too long
2
dist/CredentialsDialog-BP3tMLcO.chunk.mjs
vendored
2
dist/CredentialsDialog-BP3tMLcO.chunk.mjs
vendored
|
|
@ -1,2 +0,0 @@
|
|||
import{t}from"./translation-DoG5ZELJ-DRDc35uB.chunk.mjs";import{N as m}from"./index-JpgrUA2Z-Cg8qxgsw.chunk.mjs";import{N as d}from"./NcNoteCard-Cok_4Fld-CEiA7MRo.chunk.mjs";import{N as p}from"./NcPasswordField-DYF18Cdo-CDrhVNCN.chunk.mjs";import{_ as c}from"./TrashCanOutline-t5kbV5NX.chunk.mjs";import{b as g,c as f,o as h,w as x,e as s,u as e,r as n}from"./runtime-dom.esm-bundler-CBTFVsZ1.chunk.mjs";import"./index-Bndk0DrU.chunk.mjs";import"./index-xFugdZPW.chunk.mjs";import"./createElementId-DhjFt1I9-CbtAsEAv.chunk.mjs";import"./mdi-BiMJjngH.chunk.mjs";import"./index-CeZOua3E.chunk.mjs";import"./string_decoder-BO00msnV.chunk.mjs";import"./NcInputField-tt_Gi9ja-Cs0S2GF6.chunk.mjs";const $=g({__name:"CredentialsDialog",emits:["close"],setup(_){const o=n(""),r=n(""),u=[{label:t("files_external","Confirm"),type:"submit",variant:"primary"}];return(i,a)=>(h(),f(e(m),{buttons:u,class:"external-storage-auth",closeOnClickOutside:"","data-cy-external-storage-auth":"",isForm:"",name:e(t)("files_external","Storage credentials"),outTransition:"",onSubmit:a[2]||(a[2]=l=>i.$emit("close",{login:o.value,password:r.value})),"onUpdate:open":a[3]||(a[3]=l=>i.$emit("close"))},{default:x(()=>[s(e(d),{class:"external-storage-auth__header",text:e(t)("files_external","To access the storage, you need to provide the authentication credentials."),type:"info"},null,8,["text"]),s(e(c),{modelValue:o.value,"onUpdate:modelValue":a[0]||(a[0]=l=>o.value=l),autofocus:"",class:"external-storage-auth__login","data-cy-external-storage-auth-dialog-login":"",label:e(t)("files_external","Login"),placeholder:e(t)("files_external","Enter the storage login"),minlength:"2",name:"login",required:""},null,8,["modelValue","label","placeholder"]),s(e(p),{modelValue:r.value,"onUpdate:modelValue":a[1]||(a[1]=l=>r.value=l),class:"external-storage-auth__password","data-cy-external-storage-auth-dialog-password":"",label:e(t)("files_external","Password"),placeholder:e(t)("files_external","Enter the storage password"),name:"password",required:""},null,8,["modelValue","label","placeholder"])]),_:1},8,["name"]))}});export{$ as default};
|
||||
//# sourceMappingURL=CredentialsDialog-BP3tMLcO.chunk.mjs.map
|
||||
2
dist/CredentialsDialog-CbO2pMBh.chunk.mjs
vendored
Normal file
2
dist/CredentialsDialog-CbO2pMBh.chunk.mjs
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
import{t}from"./translation-DoG5ZELJ-Bni_xMHF.chunk.mjs";import{N as u}from"./index-CezD717V.chunk.mjs";import{N as d}from"./NcNoteCard-Cok_4Fld-Df11KHe2.chunk.mjs";import{N as p}from"./NcPasswordField-DYF18Cdo-BbpNSGg_.chunk.mjs";import{_ as c}from"./TrashCanOutline-BwjpsJlQ.chunk.mjs";import{b as g,c as f,o as h,w as x,e as s,u as e,r as n}from"./runtime-dom.esm-bundler-Bpt0bWgp.chunk.mjs";import"./index-Bndk0DrU.chunk.mjs";import"./createElementId-DhjFt1I9-COdYgGCC.chunk.mjs";import"./logger-D3RVzcfQ-DhmPs7Vh.chunk.mjs";import"./mdi-0dI0vmBh.chunk.mjs";import"./index-DNyFZ0q1.chunk.mjs";import"./string_decoder-BO00msnV.chunk.mjs";import"./index-xFugdZPW.chunk.mjs";import"./NcInputField-tt_Gi9ja-81wMHLk1.chunk.mjs";const k=g({__name:"CredentialsDialog",emits:["close"],setup(_){const o=n(""),r=n(""),m=[{label:t("files_external","Confirm"),type:"submit",variant:"primary"}];return(i,a)=>(h(),f(e(u),{buttons:m,class:"external-storage-auth",closeOnClickOutside:"","data-cy-external-storage-auth":"",isForm:"",name:e(t)("files_external","Storage credentials"),outTransition:"",onSubmit:a[2]||(a[2]=l=>i.$emit("close",{login:o.value,password:r.value})),"onUpdate:open":a[3]||(a[3]=l=>i.$emit("close"))},{default:x(()=>[s(e(d),{class:"external-storage-auth__header",text:e(t)("files_external","To access the storage, you need to provide the authentication credentials."),type:"info"},null,8,["text"]),s(e(c),{modelValue:o.value,"onUpdate:modelValue":a[0]||(a[0]=l=>o.value=l),autofocus:"",class:"external-storage-auth__login","data-cy-external-storage-auth-dialog-login":"",label:e(t)("files_external","Login"),placeholder:e(t)("files_external","Enter the storage login"),minlength:"2",name:"login",required:""},null,8,["modelValue","label","placeholder"]),s(e(p),{modelValue:r.value,"onUpdate:modelValue":a[1]||(a[1]=l=>r.value=l),class:"external-storage-auth__password","data-cy-external-storage-auth-dialog-password":"",label:e(t)("files_external","Password"),placeholder:e(t)("files_external","Enter the storage password"),name:"password",required:""},null,8,["modelValue","label","placeholder"])]),_:1},8,["name"]))}});export{k as default};
|
||||
//# sourceMappingURL=CredentialsDialog-CbO2pMBh.chunk.mjs.map
|
||||
|
|
@ -1 +1 @@
|
|||
{"version":3,"file":"CredentialsDialog-BP3tMLcO.chunk.mjs","sources":["../build/frontend/apps/files_external/src/views/CredentialsDialog.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport { t } from '@nextcloud/l10n'\nimport { ref } from 'vue'\nimport NcDialog from '@nextcloud/vue/components/NcDialog'\nimport NcNoteCard from '@nextcloud/vue/components/NcNoteCard'\nimport NcPasswordField from '@nextcloud/vue/components/NcPasswordField'\nimport NcTextField from '@nextcloud/vue/components/NcTextField'\n\ndefineEmits<{\n\tclose: [payload?: { login: string, password: string }]\n}>()\n\nconst login = ref('')\nconst password = ref('')\n\nconst dialogButtons: InstanceType<typeof NcDialog>['buttons'] = [{\n\tlabel: t('files_external', 'Confirm'),\n\ttype: 'submit',\n\tvariant: 'primary',\n}]\n</script>\n\n<template>\n\t<NcDialog\n\t\t:buttons=\"dialogButtons\"\n\t\tclass=\"external-storage-auth\"\n\t\tcloseOnClickOutside\n\t\tdata-cy-external-storage-auth\n\t\tisForm\n\t\t:name=\"t('files_external', 'Storage credentials')\"\n\t\toutTransition\n\t\t@submit=\"$emit('close', { login, password })\"\n\t\t@update:open=\"$emit('close')\">\n\t\t<!-- Header -->\n\t\t<NcNoteCard\n\t\t\tclass=\"external-storage-auth__header\"\n\t\t\t:text=\"t('files_external', 'To access the storage, you need to provide the authentication credentials.')\"\n\t\t\ttype=\"info\" />\n\n\t\t<!-- Login -->\n\t\t<NcTextField\n\t\t\tv-model=\"login\"\n\t\t\tautofocus\n\t\t\tclass=\"external-storage-auth__login\"\n\t\t\tdata-cy-external-storage-auth-dialog-login\n\t\t\t:label=\"t('files_external', 'Login')\"\n\t\t\t:placeholder=\"t('files_external', 'Enter the storage login')\"\n\t\t\tminlength=\"2\"\n\t\t\tname=\"login\"\n\t\t\trequired />\n\n\t\t<!-- Password -->\n\t\t<NcPasswordField\n\t\t\tv-model=\"password\"\n\t\t\tclass=\"external-storage-auth__password\"\n\t\t\tdata-cy-external-storage-auth-dialog-password\n\t\t\t:label=\"t('files_external', 'Password')\"\n\t\t\t:placeholder=\"t('files_external', 'Enter the storage password')\"\n\t\t\tname=\"password\"\n\t\t\trequired />\n\t</NcDialog>\n</template>\n"],"names":["login","ref","password","dialogButtons","t","_createBlock","_unref","NcDialog","_cache","$event","$emit","_createVNode","NcNoteCard","NcTextField","NcPasswordField"],"mappings":"kvBAiBA,MAAMA,EAAQC,EAAI,EAAE,EACdC,EAAWD,EAAI,EAAE,EAEjBE,EAA0D,CAAC,CAChE,MAAOC,EAAE,iBAAkB,SAAS,EACpC,KAAM,SACN,QAAS,SAAA,CACT,oBAIAC,EAqCWC,EAAAC,CAAA,EAAA,CApCT,QAASJ,EACV,MAAM,wBACN,oBAAA,GACA,gCAAA,GACA,OAAA,GACC,KAAMG,EAAAF,CAAA,EAAC,iBAAA,qBAAA,EACR,cAAA,GACC,SAAMI,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAC,GAAEC,EAAAA,MAAK,QAAA,CAAA,MAAYV,EAAA,eAAOE,EAAA,MAAQ,GACxC,+BAAaQ,EAAAA,MAAK,OAAA,EAAA,aAEnB,IAGe,CAHfC,EAGeL,EAAAM,CAAA,EAAA,CAFd,MAAM,gCACL,KAAMN,EAAAF,CAAA,EAAC,iBAAA,4EAAA,EACR,KAAK,MAAA,mBAGNO,EASYL,EAAAO,CAAA,EAAA,YARFb,EAAA,2CAAAA,EAAK,MAAAS,GACd,UAAA,GACA,MAAM,+BACN,6CAAA,GACC,MAAOH,EAAAF,CAAA,EAAC,iBAAA,OAAA,EACR,YAAaE,EAAAF,CAAA,EAAC,iBAAA,yBAAA,EACf,UAAU,IACV,KAAK,QACL,SAAA,EAAA,+CAGDO,EAOYL,EAAAQ,CAAA,EAAA,YANFZ,EAAA,2CAAAA,EAAQ,MAAAO,GACjB,MAAM,kCACN,gDAAA,GACC,MAAOH,EAAAF,CAAA,EAAC,iBAAA,UAAA,EACR,YAAaE,EAAAF,CAAA,EAAC,iBAAA,4BAAA,EACf,KAAK,WACL,SAAA,EAAA"}
|
||||
{"version":3,"file":"CredentialsDialog-CbO2pMBh.chunk.mjs","sources":["../build/frontend/apps/files_external/src/views/CredentialsDialog.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport { t } from '@nextcloud/l10n'\nimport { ref } from 'vue'\nimport NcDialog from '@nextcloud/vue/components/NcDialog'\nimport NcNoteCard from '@nextcloud/vue/components/NcNoteCard'\nimport NcPasswordField from '@nextcloud/vue/components/NcPasswordField'\nimport NcTextField from '@nextcloud/vue/components/NcTextField'\n\ndefineEmits<{\n\tclose: [payload?: { login: string, password: string }]\n}>()\n\nconst login = ref('')\nconst password = ref('')\n\nconst dialogButtons: InstanceType<typeof NcDialog>['buttons'] = [{\n\tlabel: t('files_external', 'Confirm'),\n\ttype: 'submit',\n\tvariant: 'primary',\n}]\n</script>\n\n<template>\n\t<NcDialog\n\t\t:buttons=\"dialogButtons\"\n\t\tclass=\"external-storage-auth\"\n\t\tcloseOnClickOutside\n\t\tdata-cy-external-storage-auth\n\t\tisForm\n\t\t:name=\"t('files_external', 'Storage credentials')\"\n\t\toutTransition\n\t\t@submit=\"$emit('close', { login, password })\"\n\t\t@update:open=\"$emit('close')\">\n\t\t<!-- Header -->\n\t\t<NcNoteCard\n\t\t\tclass=\"external-storage-auth__header\"\n\t\t\t:text=\"t('files_external', 'To access the storage, you need to provide the authentication credentials.')\"\n\t\t\ttype=\"info\" />\n\n\t\t<!-- Login -->\n\t\t<NcTextField\n\t\t\tv-model=\"login\"\n\t\t\tautofocus\n\t\t\tclass=\"external-storage-auth__login\"\n\t\t\tdata-cy-external-storage-auth-dialog-login\n\t\t\t:label=\"t('files_external', 'Login')\"\n\t\t\t:placeholder=\"t('files_external', 'Enter the storage login')\"\n\t\t\tminlength=\"2\"\n\t\t\tname=\"login\"\n\t\t\trequired />\n\n\t\t<!-- Password -->\n\t\t<NcPasswordField\n\t\t\tv-model=\"password\"\n\t\t\tclass=\"external-storage-auth__password\"\n\t\t\tdata-cy-external-storage-auth-dialog-password\n\t\t\t:label=\"t('files_external', 'Password')\"\n\t\t\t:placeholder=\"t('files_external', 'Enter the storage password')\"\n\t\t\tname=\"password\"\n\t\t\trequired />\n\t</NcDialog>\n</template>\n"],"names":["login","ref","password","dialogButtons","t","_createBlock","_unref","NcDialog","_cache","$event","$emit","_createVNode","NcNoteCard","NcTextField","NcPasswordField"],"mappings":"sxBAiBA,MAAMA,EAAQC,EAAI,EAAE,EACdC,EAAWD,EAAI,EAAE,EAEjBE,EAA0D,CAAC,CAChE,MAAOC,EAAE,iBAAkB,SAAS,EACpC,KAAM,SACN,QAAS,SAAA,CACT,oBAIAC,EAqCWC,EAAAC,CAAA,EAAA,CApCT,QAASJ,EACV,MAAM,wBACN,oBAAA,GACA,gCAAA,GACA,OAAA,GACC,KAAMG,EAAAF,CAAA,EAAC,iBAAA,qBAAA,EACR,cAAA,GACC,SAAMI,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAC,GAAEC,EAAAA,MAAK,QAAA,CAAA,MAAYV,EAAA,eAAOE,EAAA,MAAQ,GACxC,+BAAaQ,EAAAA,MAAK,OAAA,EAAA,aAEnB,IAGe,CAHfC,EAGeL,EAAAM,CAAA,EAAA,CAFd,MAAM,gCACL,KAAMN,EAAAF,CAAA,EAAC,iBAAA,4EAAA,EACR,KAAK,MAAA,mBAGNO,EASYL,EAAAO,CAAA,EAAA,YARFb,EAAA,2CAAAA,EAAK,MAAAS,GACd,UAAA,GACA,MAAM,+BACN,6CAAA,GACC,MAAOH,EAAAF,CAAA,EAAC,iBAAA,OAAA,EACR,YAAaE,EAAAF,CAAA,EAAC,iBAAA,yBAAA,EACf,UAAU,IACV,KAAK,QACL,SAAA,EAAA,+CAGDO,EAOYL,EAAAQ,CAAA,EAAA,YANFZ,EAAA,2CAAAA,EAAQ,MAAAO,GACjB,MAAM,kCACN,gDAAA,GACC,MAAOH,EAAAF,CAAA,EAAC,iBAAA,UAAA,EACR,YAAaE,EAAAF,CAAA,EAAC,iBAAA,4BAAA,EACf,KAAK,WACL,SAAA,EAAA"}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
26
dist/FilesVersionsSidebarTab-6vfFjTWW.chunk.mjs
vendored
Normal file
26
dist/FilesVersionsSidebarTab-6vfFjTWW.chunk.mjs
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
26
dist/FilesVersionsSidebarTab-B6IVqJWe.chunk.mjs
vendored
26
dist/FilesVersionsSidebarTab-B6IVqJWe.chunk.mjs
vendored
File diff suppressed because one or more lines are too long
5
dist/NcAvatar-xQb0quUq-C71Wo6rS.chunk.mjs
vendored
5
dist/NcAvatar-xQb0quUq-C71Wo6rS.chunk.mjs
vendored
File diff suppressed because one or more lines are too long
5
dist/NcAvatar-xQb0quUq-CiFKy_FB.chunk.mjs
vendored
Normal file
5
dist/NcAvatar-xQb0quUq-CiFKy_FB.chunk.mjs
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
3
dist/NcBreadcrumbs-5gl8Syfa-jFw0V8RF.chunk.mjs
vendored
Normal file
3
dist/NcBreadcrumbs-5gl8Syfa-jFw0V8RF.chunk.mjs
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
dist/NcChip-CaOkERH3-AC49UWxN.chunk.mjs
vendored
Normal file
2
dist/NcChip-CaOkERH3-AC49UWxN.chunk.mjs
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
import{m as g}from"./logger-D3RVzcfQ-DhmPs7Vh.chunk.mjs";import{N as k}from"./PencilOutline-BAj10Ume.chunk.mjs";import{a as y}from"./index-CezD717V.chunk.mjs";import{r as b,d as P,a as x,N as u,_ as N}from"./createElementId-DhjFt1I9-COdYgGCC.chunk.mjs";import{b as S,i as $,j as f,o as s,l as n,k as z,c as i,m as c,g as h,t as v,p as L,w as e,e as M,u as j,n as w}from"./runtime-dom.esm-bundler-Bpt0bWgp.chunk.mjs";b(P);const A={key:0,class:"nc-chip__icon"},B={class:"nc-chip__text"},I=S({__name:"NcChip",props:{ariaLabelClose:{default:x("Close")},actionsContainer:{default:"body"},text:{default:""},iconPath:{default:void 0},iconSvg:{default:void 0},noClose:{type:Boolean},variant:{default:"secondary"}},emits:["close"],setup(m,{emit:_}){const t=m,C=_,l=$(),o=L(()=>!t.noClose),r=()=>!!l.actions,p=()=>!!(t.iconPath||t.iconSvg||l.icon);return(a,d)=>(s(),f("div",{class:w(["nc-chip",{[`nc-chip--${a.variant}`]:!0,"nc-chip--no-actions":a.noClose&&!r(),"nc-chip--no-icon":!p()}])},[p()?(s(),f("span",A,[c(a.$slots,"icon",{},()=>[a.iconPath||a.iconSvg?(s(),i(u,{key:0,inline:"",path:a.iconPath,svg:a.iconPath?void 0:a.iconSvg,size:18},null,8,["path","svg"])):n("",!0)],!0)])):n("",!0),z("span",B,[c(a.$slots,"default",{},()=>[h(v(a.text),1)],!0)]),o.value||r()?(s(),i(y,{key:1,class:"nc-chip__actions",container:a.actionsContainer,forceMenu:!o.value,variant:"tertiary-no-background"},{default:e(()=>[o.value?(s(),i(k,{key:0,closeAfterClick:"",onClick:d[0]||(d[0]=D=>C("close"))},{icon:e(()=>[M(u,{path:j(g),size:20},null,8,["path"])]),default:e(()=>[h(" "+v(a.ariaLabelClose),1)]),_:1})):n("",!0),c(a.$slots,"actions",{},void 0,!0)]),_:3},8,["container","forceMenu"])):n("",!0)],2))}}),F=N(I,[["__scopeId","data-v-8f5d3c40"]]);export{F as N};
|
||||
//# sourceMappingURL=NcChip-CaOkERH3-AC49UWxN.chunk.mjs.map
|
||||
1
dist/NcChip-CaOkERH3-AC49UWxN.chunk.mjs.map
vendored
Normal file
1
dist/NcChip-CaOkERH3-AC49UWxN.chunk.mjs.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/NcChip-CaOkERH3-Som-mR4B.chunk.css
vendored
Normal file
1
dist/NcChip-CaOkERH3-Som-mR4B.chunk.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.material-design-icon[data-v-8f5d3c40]{display:flex;align-self:center;justify-self:center;align-items:center;justify-content:center}.nc-chip[data-v-8f5d3c40]{--chip-size: 24px;--chip-radius: calc(var(--chip-size) / 2);height:var(--chip-size);max-width:fit-content;display:flex;flex-direction:row;align-items:center;border-radius:var(--chip-radius);background-color:var(--color-background-hover)}.nc-chip--primary[data-v-8f5d3c40]{background-color:var(--color-primary-element);color:var(--color-primary-element-text)}.nc-chip--secondary[data-v-8f5d3c40]{background-color:var(--color-primary-element-light);color:var(--color-primary-element-light-text)}.nc-chip--error[data-v-8f5d3c40]{background-color:var(--color-error);color:var(--color-error-text)}.nc-chip--warning[data-v-8f5d3c40]{background-color:var(--color-warning);color:var(--color-warning-text)}.nc-chip--success[data-v-8f5d3c40]{background-color:var(--color-success);color:var(--color-success-text)}.nc-chip--no-actions .nc-chip__text[data-v-8f5d3c40]{padding-inline-end:calc(2 * var(--default-grid-baseline))}.nc-chip--no-icon .nc-chip__text[data-v-8f5d3c40]{padding-inline-start:calc(2 * var(--default-grid-baseline))}.nc-chip__text[data-v-8f5d3c40]{flex:1 auto;overflow:hidden;text-overflow:ellipsis;text-wrap:nowrap}.nc-chip__icon[data-v-8f5d3c40]{flex:0 0 var(--chip-size);margin-inline-end:var(--default-grid-baseline);line-height:1;display:flex;align-items:center;justify-content:center;overflow:hidden;height:var(--chip-size);width:var(--chip-size)}.nc-chip__actions[data-v-8f5d3c40]{flex:0 0 var(--chip-size);--default-clickable-area: var(--chip-size);--border-radius-element: var(--chip-radius)}
|
||||
File diff suppressed because one or more lines are too long
2
dist/NcColorPicker-5Pw0z8WG-pIntf2EI.chunk.mjs
vendored
Normal file
2
dist/NcColorPicker-5Pw0z8WG-pIntf2EI.chunk.mjs
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
dist/NcDateTime-DS-ziNw6.chunk.css
vendored
Normal file
1
dist/NcDateTime-DS-ziNw6.chunk.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.material-design-icon[data-v-32f01b7a]{display:flex;align-self:center;justify-self:center;align-items:center;justify-content:center}li.action[data-v-32f01b7a]:hover,li.action.active[data-v-32f01b7a]{border-radius:6px;padding:0}li.action[data-v-32f01b7a]:hover{background-color:var(--color-background-hover)}.action-link[data-v-32f01b7a]{display:flex;align-items:flex-start;width:100%;height:auto;margin:0;padding:0;padding-inline-end:calc((var(--default-clickable-area) - 16px) / 2);box-sizing:border-box;cursor:pointer;white-space:nowrap;color:var(--color-main-text);border:0;border-radius:0;background-color:transparent;box-shadow:none;font-weight:400;font-size:var(--default-font-size);line-height:var(--default-clickable-area)}.action-link>span[data-v-32f01b7a]{cursor:pointer;white-space:nowrap}.action-link__icon[data-v-32f01b7a]{width:var(--default-clickable-area);height:var(--default-clickable-area);opacity:1;background-position:calc((var(--default-clickable-area) - 16px) / 2) center;background-size:16px;background-repeat:no-repeat}.action-link[data-v-32f01b7a] .material-design-icon{width:var(--default-clickable-area);height:var(--default-clickable-area);opacity:1}.action-link[data-v-32f01b7a] .material-design-icon .material-design-icon__svg{vertical-align:middle}.action-link__longtext-wrapper[data-v-32f01b7a],.action-link__longtext[data-v-32f01b7a]{max-width:220px;line-height:1.6em;padding:calc((var(--default-clickable-area) - 1.6em) / 2) 0;cursor:pointer;text-align:start;overflow:hidden;text-overflow:ellipsis}.action-link__longtext[data-v-32f01b7a]{cursor:pointer;white-space:pre-wrap!important}.action-link__name[data-v-32f01b7a]{font-weight:700;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:100%;display:block}.action-link__description[data-v-32f01b7a]{display:block;white-space:pre-wrap;font-size:var(--font-size-small);line-height:var(--default-line-height);color:var(--color-text-maxcontrast);cursor:pointer}.action-link__menu-icon[data-v-32f01b7a]{margin-inline:auto calc((var(--default-clickable-area) - 16px) / 2 * -1)}.material-design-icon[data-v-87267750]{display:flex;align-self:center;justify-self:center;align-items:center;justify-content:center}li.action[data-v-87267750]:hover,li.action.active[data-v-87267750]{border-radius:6px;padding:0}li.action[data-v-87267750]:hover{background-color:var(--color-background-hover)}.action-router[data-v-87267750]{display:flex;align-items:flex-start;width:100%;height:auto;margin:0;padding:0;padding-inline-end:calc((var(--default-clickable-area) - 16px) / 2);box-sizing:border-box;cursor:pointer;white-space:nowrap;color:var(--color-main-text);border:0;border-radius:0;background-color:transparent;box-shadow:none;font-weight:400;font-size:var(--default-font-size);line-height:var(--default-clickable-area)}.action-router>span[data-v-87267750]{cursor:pointer;white-space:nowrap}.action-router__icon[data-v-87267750]{width:var(--default-clickable-area);height:var(--default-clickable-area);opacity:1;background-position:calc((var(--default-clickable-area) - 16px) / 2) center;background-size:16px;background-repeat:no-repeat}.action-router[data-v-87267750] .material-design-icon{width:var(--default-clickable-area);height:var(--default-clickable-area);opacity:1}.action-router[data-v-87267750] .material-design-icon .material-design-icon__svg{vertical-align:middle}.action-router__longtext-wrapper[data-v-87267750],.action-router__longtext[data-v-87267750]{max-width:220px;line-height:1.6em;padding:calc((var(--default-clickable-area) - 1.6em) / 2) 0;cursor:pointer;text-align:start;overflow:hidden;text-overflow:ellipsis}.action-router__longtext[data-v-87267750]{cursor:pointer;white-space:pre-wrap!important}.action-router__name[data-v-87267750]{font-weight:700;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:100%;display:block}.action-router__description[data-v-87267750]{display:block;white-space:pre-wrap;font-size:var(--font-size-small);line-height:var(--default-line-height);color:var(--color-text-maxcontrast);cursor:pointer}.action-router__menu-icon[data-v-87267750]{margin-inline:auto calc((var(--default-clickable-area) - 16px) / 2 * -1)}.action--disabled[data-v-87267750]{pointer-events:none;opacity:.5}.action--disabled[data-v-87267750]:hover,.action--disabled[data-v-87267750]:focus{cursor:default;opacity:.5}.action--disabled[data-v-87267750] *{opacity:1!important}
|
||||
1
dist/NcDateTime-DXOHXnuu.chunk.css
vendored
1
dist/NcDateTime-DXOHXnuu.chunk.css
vendored
File diff suppressed because one or more lines are too long
2
dist/NcDateTime.vue_vue_type_script_setup_true_lang-BhB8yA4U-BmrwzOAy.chunk.mjs
vendored
Normal file
2
dist/NcDateTime.vue_vue_type_script_setup_true_lang-BhB8yA4U-BmrwzOAy.chunk.mjs
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
import{A as d}from"./PencilOutline-BAj10Ume.chunk.mjs";import{d as _,z as C,A as S}from"./index-CezD717V.chunk.mjs";import{_ as f}from"./createElementId-DhjFt1I9-COdYgGCC.chunk.mjs";import{j as a,o,k as n,m as x,l as g,M as k,n as y,t as l,f as I,e as v,w as h,b as w,u as T,p as m,Y as p}from"./runtime-dom.esm-bundler-Bpt0bWgp.chunk.mjs";const L={name:"NcActionLink",mixins:[d],inject:{isInSemanticMenu:{from:_,default:!1}},props:{href:{type:String,required:!0,validator:e=>{try{return new URL(e)}catch{return e.startsWith("#")||e.startsWith("/")}}},download:{type:String,default:null},target:{type:String,default:"_self",validator:e=>e&&(!e.startsWith("_")||["_blank","_self","_parent","_top"].indexOf(e)>-1)},title:{type:String,default:null}}},M=["role"],U=["download","href","aria-label","target","title","role"],j={key:0,class:"action-link__longtext-wrapper"},A={class:"action-link__name"},N=["textContent"],$=["textContent"],R={key:2,class:"action-link__text"};function W(e,t,i,u,c,r){return o(),a("li",{class:"action",role:r.isInSemanticMenu&&"presentation"},[n("a",{download:i.download,href:i.href,"aria-label":e.ariaLabel,target:i.target,title:i.title,class:"action-link focusable",rel:"nofollow noreferrer noopener",role:r.isInSemanticMenu&&"menuitem",onClick:t[0]||(t[0]=(...s)=>e.onClick&&e.onClick(...s))},[x(e.$slots,"icon",{},()=>[n("span",{"aria-hidden":"true",class:y(["action-link__icon",[e.isIconUrl?"action-link__icon--url":e.icon]]),style:k({backgroundImage:e.isIconUrl?`url(${e.icon})`:null})},null,6)],!0),e.name?(o(),a("span",j,[n("strong",A,l(e.name),1),t[1]||(t[1]=n("br",null,null,-1)),n("span",{class:"action-link__longtext",textContent:l(e.text)},null,8,N)])):e.isLongText?(o(),a("span",{key:1,class:"action-link__longtext",textContent:l(e.text)},null,8,$)):(o(),a("span",R,l(e.text),1)),g("",!0)],8,U)],8,M)}const V=f(L,[["render",W],["__scopeId","data-v-32f01b7a"]]),q={name:"NcActionRouter",mixins:[d],inject:{isInSemanticMenu:{from:_,default:!1}},props:{to:{type:[String,Object],required:!0}}},B=["role"],O={key:0,class:"action-router__longtext-wrapper"},z={class:"action-router__name"},D=["textContent"],Y=["textContent"],E={key:2,class:"action-router__text"};function F(e,t,i,u,c,r){const s=I("RouterLink");return o(),a("li",{class:"action",role:r.isInSemanticMenu&&"presentation"},[v(s,{"aria-label":e.ariaLabel,class:"action-router focusable",rel:"nofollow noreferrer noopener",role:r.isInSemanticMenu&&"menuitem",title:e.title,to:i.to,onClick:e.onClick},{default:h(()=>[x(e.$slots,"icon",{},()=>[n("span",{"aria-hidden":"true",class:y(["action-router__icon",[e.isIconUrl?"action-router__icon--url":e.icon]]),style:k({backgroundImage:e.isIconUrl?`url(${e.icon})`:null})},null,6)],!0),e.name?(o(),a("span",O,[n("strong",z,l(e.name),1),t[0]||(t[0]=n("br",null,null,-1)),n("span",{class:"action-router__longtext",textContent:l(e.text)},null,8,D)])):e.isLongText?(o(),a("span",{key:1,class:"action-router__longtext",textContent:l(e.text)},null,8,Y)):(o(),a("span",E,l(e.text),1)),g("",!0)]),_:3},8,["aria-label","role","title","to","onClick"])],8,B)}const X=f(q,[["render",F],["__scopeId","data-v-87267750"]]),G=["data-timestamp","title","textContent"],Z=w({__name:"NcDateTime",props:{timestamp:{},format:{default:()=>({timeStyle:"medium",dateStyle:"short"})},relativeTime:{type:[Boolean,String],default:"long"},ignoreSeconds:{type:Boolean}},setup(e){const t=e,i=m(()=>({format:t.format})),u=m(()=>({ignoreSeconds:t.ignoreSeconds,relativeTime:t.relativeTime||"long",update:t.relativeTime!==!1})),c=S(p(()=>t.timestamp),i),r=C(p(()=>t.timestamp),u),s=m(()=>t.relativeTime?r.value:c.value);return(b,H)=>(o(),a("span",{class:"nc-datetime",dir:"auto","data-timestamp":b.timestamp,title:T(c),textContent:l(s.value)},null,8,G))}});export{V as N,Z as _,X as a};
|
||||
//# sourceMappingURL=NcDateTime.vue_vue_type_script_setup_true_lang-BhB8yA4U-BmrwzOAy.chunk.mjs.map
|
||||
1
dist/NcDateTime.vue_vue_type_script_setup_true_lang-BhB8yA4U-BmrwzOAy.chunk.mjs.map
vendored
Normal file
1
dist/NcDateTime.vue_vue_type_script_setup_true_lang-BhB8yA4U-BmrwzOAy.chunk.mjs.map
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6
dist/NcEmojiPicker-DpA4_bLX-BU-HM5Wl.chunk.mjs
vendored
Normal file
6
dist/NcEmojiPicker-DpA4_bLX-BU-HM5Wl.chunk.mjs
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue