mirror of
https://github.com/directus/directus.git
synced 2026-01-27 22:57:56 -05:00
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="v-dialog">
|
||||
<slot name="activator" v-bind="{ on: () => $emit('toggle', true) }" />
|
||||
<slot name="activator" v-bind="{ on: () => (_active = true) }" />
|
||||
|
||||
<portal to="dialog-outlet">
|
||||
<div v-if="active" class="container" :class="[className]" :key="id">
|
||||
<div v-if="_active" class="container" :class="[className]" :key="id">
|
||||
<v-overlay active absolute @click="emitToggle" />
|
||||
<slot />
|
||||
</div>
|
||||
@@ -23,7 +23,7 @@ export default defineComponent({
|
||||
props: {
|
||||
active: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
default: undefined,
|
||||
},
|
||||
persistent: {
|
||||
type: Boolean,
|
||||
@@ -31,10 +31,22 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const localActive = ref(false);
|
||||
|
||||
const className = ref<string | null>(null);
|
||||
const id = computed(() => nanoid());
|
||||
|
||||
return { emitToggle, className, nudge, id };
|
||||
const _active = computed({
|
||||
get() {
|
||||
return props.active !== undefined ? props.active : localActive.value;
|
||||
},
|
||||
set(newActive: boolean) {
|
||||
localActive.value = newActive;
|
||||
emit('toggle', newActive);
|
||||
},
|
||||
});
|
||||
|
||||
return { emitToggle, className, nudge, id, _active };
|
||||
|
||||
function emitToggle() {
|
||||
if (props.persistent === false) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<v-menu attached close-on-content-click v-model="menuActive">
|
||||
<v-menu attached v-model="menuActive">
|
||||
<template #activator="{ toggle }">
|
||||
<v-input>
|
||||
<template #input>
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
<template>
|
||||
<div class="field" :key="field.field" :class="field.meta.width">
|
||||
<v-menu
|
||||
v-if="field.hideLabel !== true"
|
||||
placement="bottom-start"
|
||||
show-arrow
|
||||
close-on-content-click
|
||||
:disabled="isDisabled"
|
||||
>
|
||||
<v-menu v-if="field.hideLabel !== true" placement="bottom-start" show-arrow :disabled="isDisabled">
|
||||
<template #activator="{ toggle, active }">
|
||||
<form-field-label
|
||||
:field="field"
|
||||
|
||||
@@ -123,7 +123,7 @@ export const withMenu = () =>
|
||||
components: { VMenu },
|
||||
template: `
|
||||
<div>
|
||||
<v-menu placement="bottom-start" close-on-content-click attached>
|
||||
<v-menu placement="bottom-start" attached>
|
||||
<template #activator="{ toggle, active }">
|
||||
<v-input placeholder="Enter value...">
|
||||
<template #append><v-icon @click="toggle" name="public" :style="{
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="v-list-group">
|
||||
<v-list-item :active="active" class="activator" :to="to" @click="onClick">
|
||||
<v-list-item :active="active" class="activator" :to="to" :exact="exact" @click="onClick" :disabled="disabled">
|
||||
<slot name="activator" :active="groupActive" />
|
||||
|
||||
<v-list-item-icon class="activator-icon" :class="{ active: groupActive }">
|
||||
<v-icon name="chevron_right" @click.stop.prevent="toggle" />
|
||||
<v-icon name="chevron_right" @click.stop.prevent="toggle" :disabled="disabled" />
|
||||
</v-list-item-icon>
|
||||
</v-list-item>
|
||||
|
||||
@@ -34,6 +34,14 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
exact: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props, { listeners, emit }) {
|
||||
const { active: groupActive, toggle } = useGroupable();
|
||||
|
||||
@@ -55,7 +55,7 @@ body {
|
||||
--v-list-padding: 4px 0;
|
||||
--v-list-max-height: none;
|
||||
--v-list-max-width: none;
|
||||
--v-list-min-width: none;
|
||||
--v-list-min-width: 220px;
|
||||
--v-list-min-height: none;
|
||||
--v-list-color: var(--foreground-normal);
|
||||
--v-list-color-hover: var(--foreground-normal);
|
||||
|
||||
@@ -14,7 +14,7 @@ within a menu. If you ever find yourself doing this:
|
||||
| `placement` | Where to position the popper. | `bottom` |
|
||||
| `value` | Value to control menu active state | `undefined` |
|
||||
| `close-on-click` | Close the menu when clicking outside of the menu | `true` |
|
||||
| `close-on-content-click` | Close the menu when clicking the content of the menu | `false` |
|
||||
| `close-on-content-click` | Close the menu when clicking the content of the menu | `true` |
|
||||
| `attached` | Attach the menu to an input | `false` |
|
||||
| `show-arrow` | Show an arrow pointer | `false` |
|
||||
| `disabled` | Menu does not appear | `false` |
|
||||
|
||||
@@ -82,6 +82,12 @@ export function usePopper(
|
||||
padding: 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'arrow',
|
||||
options: {
|
||||
padding: 6,
|
||||
},
|
||||
},
|
||||
computeStyles,
|
||||
flip,
|
||||
eventListeners,
|
||||
|
||||
@@ -34,12 +34,7 @@
|
||||
events: ['click'],
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="arrow"
|
||||
:class="{ active: showArrow && isActive }"
|
||||
:style="arrowStyles"
|
||||
data-popper-arrow
|
||||
/>
|
||||
<div class="arrow" :class="{ active: showArrow && isActive }" :style="arrowStyles" data-popper-arrow />
|
||||
<div class="v-menu-content" @click.stop="onContentClick">
|
||||
<slot :active="isActive" />
|
||||
</div>
|
||||
@@ -55,18 +50,6 @@ import { Placement } from '@popperjs/core';
|
||||
import { nanoid } from 'nanoid';
|
||||
import Vue from 'vue';
|
||||
|
||||
/**
|
||||
* @NOTE
|
||||
*
|
||||
* The framerate takes a little hit when opening menus, as we're rendering the content of it while
|
||||
* we're opening it. We could potentially optimize this by rendering the menu content ahead of time,
|
||||
* so all the processing power is freed up for the popper calculations and transition logic.
|
||||
*
|
||||
* However, we _can not_ render all menu content at all times, as that greatly decreases perf in the
|
||||
* app. I'm thinking we might be able to pre-render the menu content on hover of the activator, so
|
||||
* the actual act of opening the menu is quicker.
|
||||
*/
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
placement: {
|
||||
@@ -83,7 +66,7 @@ export default defineComponent({
|
||||
},
|
||||
closeOnContentClick: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
default: true,
|
||||
},
|
||||
attached: {
|
||||
type: Boolean,
|
||||
@@ -109,9 +92,19 @@ export default defineComponent({
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const activator = ref<HTMLElement | null>(null);
|
||||
const reference = ref<HTMLElement | null>(null);
|
||||
|
||||
const reference = computed<HTMLElement | null>(() => {
|
||||
return (activator.value as HTMLElement)?.childNodes[0] as HTMLElement;
|
||||
const virtualReference = ref({
|
||||
getBoundingClientRect() {
|
||||
return {
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const id = computed(() => nanoid());
|
||||
@@ -175,6 +168,8 @@ export default defineComponent({
|
||||
return localIsActive.value;
|
||||
},
|
||||
async set(newActive) {
|
||||
reference.value =
|
||||
((activator.value as HTMLElement)?.childNodes[0] as HTMLElement) || virtualReference.value;
|
||||
localIsActive.value = newActive;
|
||||
emit('input', newActive);
|
||||
},
|
||||
@@ -194,7 +189,21 @@ export default defineComponent({
|
||||
|
||||
return { isActive, activate, deactivate, toggle };
|
||||
|
||||
function activate() {
|
||||
function activate(event?: MouseEvent) {
|
||||
if (event) {
|
||||
virtualReference.value = {
|
||||
getBoundingClientRect() {
|
||||
return {
|
||||
top: event.clientY,
|
||||
left: event.clientX,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
isActive.value = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="file">
|
||||
<v-menu attached close-on-content-click :disabled="disabled || loading">
|
||||
<v-menu attached :disabled="disabled || loading">
|
||||
<template #activator="{ toggle }">
|
||||
<div>
|
||||
<v-skeleton-loader type="input" v-if="loading" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<v-menu attached :disabled="disabled" close-on-content-click>
|
||||
<template #activator="{ toggle, active, activate }">
|
||||
<v-menu attached :disabled="disabled">
|
||||
<template #activator="{ active, activate }">
|
||||
<v-input
|
||||
:disabled="disabled"
|
||||
:placeholder="value ? formatTitle(value) : $t('search_for_icon')"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{{ $t('display_template_not_setup') }}
|
||||
</v-notice>
|
||||
<div class="many-to-one" v-else>
|
||||
<v-menu v-model="menuActive" attached close-on-content-click :disabled="disabled">
|
||||
<v-menu v-model="menuActive" attached :disabled="disabled">
|
||||
<template #activator="{ active }">
|
||||
<v-skeleton-loader type="input" v-if="loadingCurrent" />
|
||||
<v-input
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<v-notice v-if="!statuses">
|
||||
{{ $t('statuses_not_configured') }}
|
||||
</v-notice>
|
||||
<v-menu v-else attached :disabled="disabled" close-on-content-click>
|
||||
<v-menu v-else attached :disabled="disabled">
|
||||
<template #activator="{ toggle, active }">
|
||||
<v-input
|
||||
readonly
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="user">
|
||||
<v-menu v-model="menuActive" attached close-on-content-click :disabled="disabled">
|
||||
<v-menu v-model="menuActive" attached :disabled="disabled">
|
||||
<template #activator="{ active }">
|
||||
<v-skeleton-loader type="input" v-if="loadingCurrent" />
|
||||
<v-input
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
"add_role": "Add Role",
|
||||
"add_user": "Add User",
|
||||
|
||||
"rename_folder": "Rename Folder",
|
||||
|
||||
"nested_files_folders_will_be_moved": "Nested files and folders will be moved one level up.",
|
||||
|
||||
"uploaded_by": "Uploaded By",
|
||||
"hide_field_on_detail": "Hide Field on Detail",
|
||||
"show_field_on_detail": "Show Field on Detail",
|
||||
@@ -206,6 +210,7 @@
|
||||
"submit": "Submit",
|
||||
|
||||
"move_to_folder": "Move to Folder",
|
||||
"delete_folder": "Delete Folder",
|
||||
"select_folder": "Select Folder",
|
||||
"move": "Move",
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
v-if="folder.children.length === 0"
|
||||
@click="clickHandler(folder.id)"
|
||||
:active="currentFolder === folder.id"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<v-list-item-icon><v-icon :name="currentFolder === folder.id ? 'folder_open' : 'folder'" /></v-list-item-icon>
|
||||
<v-list-item-content>{{ folder.name }}</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-group v-else @click="clickHandler(folder.id)" :active="currentFolder === folder.id">
|
||||
<v-list-group v-else @click="clickHandler(folder.id)" :active="currentFolder === folder.id" :disabled="disabled">
|
||||
<template #activator>
|
||||
<v-list-item-icon>
|
||||
<v-icon :name="currentFolder === folder.id ? 'folder_open' : 'folder'" />
|
||||
@@ -20,6 +21,8 @@
|
||||
:folder="childFolder"
|
||||
:current-folder="currentFolder"
|
||||
:click-handler="clickHandler"
|
||||
:disabled="disabledFolders.includes(childFolder.id)"
|
||||
:disabled-folders="disabledFolders"
|
||||
/>
|
||||
</v-list-group>
|
||||
</template>
|
||||
@@ -48,6 +51,14 @@ export default defineComponent({
|
||||
type: Function,
|
||||
default: () => undefined,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disabledFolders: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
:folder="folder"
|
||||
:current-folder="value"
|
||||
:click-handler="(id) => $emit('input', id)"
|
||||
:disabled="disabledFolders.includes(folder.id)"
|
||||
:disabled-folders="disabledFolders"
|
||||
/>
|
||||
</v-list-group>
|
||||
</v-list>
|
||||
@@ -23,7 +25,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, computed } from '@vue/composition-api';
|
||||
import { defineComponent, ref, computed, PropType } from '@vue/composition-api';
|
||||
import api from '@/api';
|
||||
import FolderPickerListItem from './folder-picker-list-item.vue';
|
||||
|
||||
@@ -42,6 +44,10 @@ type Folder = {
|
||||
export default defineComponent({
|
||||
components: { FolderPickerListItem },
|
||||
props: {
|
||||
disabledFolders: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: null,
|
||||
@@ -91,6 +97,7 @@ export default defineComponent({
|
||||
const response = await api.get(`/folders`, {
|
||||
params: {
|
||||
limit: -1,
|
||||
sort: 'name',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,35 +1,118 @@
|
||||
<template>
|
||||
<v-list-item
|
||||
v-if="folder.children === undefined"
|
||||
:to="`/files?folder=${folder.id}`"
|
||||
exact
|
||||
>
|
||||
<v-list-item-icon><v-icon name="folder" /></v-list-item-icon>
|
||||
<v-list-item-content>{{ folder.name }}</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-group v-else @click="clickHandler(folder.id)" :active="currentFolder === folder.id">
|
||||
<template #activator="{ active }">
|
||||
<v-list-item-icon>
|
||||
<v-icon :name="active ? 'folder_open' : 'folder'" />
|
||||
</v-list-item-icon>
|
||||
<div>
|
||||
<v-list-item
|
||||
v-if="folder.children === undefined"
|
||||
:to="`/files?folder=${folder.id}`"
|
||||
exact
|
||||
@contextmenu.native.prevent.stop="$refs.contextMenu.activate"
|
||||
>
|
||||
<v-list-item-icon><v-icon name="folder" /></v-list-item-icon>
|
||||
<v-list-item-content>{{ folder.name }}</v-list-item-content>
|
||||
</template>
|
||||
<navigation-folder
|
||||
v-for="childFolder in folder.children"
|
||||
:key="childFolder.id"
|
||||
:folder="childFolder"
|
||||
:current-folder="currentFolder"
|
||||
:click-handler="clickHandler"
|
||||
/>
|
||||
</v-list-group>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-group
|
||||
v-else
|
||||
:to="`/files?folder=${folder.id}`"
|
||||
exact
|
||||
@contextmenu.native.prevent="$refs.contextMenu.activate"
|
||||
>
|
||||
<template #activator="{ active }">
|
||||
<v-list-item-icon>
|
||||
<v-icon :name="active ? 'folder_open' : 'folder'" />
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>{{ folder.name }}</v-list-item-content>
|
||||
</template>
|
||||
<navigation-folder
|
||||
v-for="childFolder in folder.children"
|
||||
:key="childFolder.id"
|
||||
:folder="childFolder"
|
||||
:current-folder="currentFolder"
|
||||
:click-handler="clickHandler"
|
||||
/>
|
||||
</v-list-group>
|
||||
|
||||
<v-menu ref="contextMenu" show-arrow placement="bottom-start">
|
||||
<v-list dense>
|
||||
<v-list-item @click="renameActive = true">
|
||||
<v-list-item-icon>
|
||||
<v-icon name="edit" />
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
{{ $t('rename_folder') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item @click="moveActive = true">
|
||||
<v-list-item-icon>
|
||||
<v-icon name="folder_move" />
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
{{ $t('move_to_folder') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item @click="deleteActive = true">
|
||||
<v-list-item-icon>
|
||||
<v-icon name="delete" />
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
{{ $t('delete_folder') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
<v-dialog v-model="renameActive" persistent>
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('rename_folder') }}</v-card-title>
|
||||
<v-card-text>
|
||||
<v-input v-model="renameValue" />
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-button secondary @click="renameActive = false">{{ $t('cancel') }}</v-button>
|
||||
<v-button @click="renameSave" :loading="renameSaving">{{ $t('save') }}</v-button>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<v-dialog v-model="moveActive" persistent>
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('move_to_folder') }}</v-card-title>
|
||||
<v-card-text>
|
||||
<folder-picker v-model="moveValue" :disabled-folders="[folder.id]" />
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-button secondary @click="moveActive = false">{{ $t('cancel') }}</v-button>
|
||||
<v-button @click="moveSave" :loading="moveSaving">{{ $t('save') }}</v-button>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<v-dialog v-model="deleteActive" persistent>
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('delete_folder') }}</v-card-title>
|
||||
<v-card-text>
|
||||
<v-notice>
|
||||
{{ $t('nested_files_folders_will_be_moved') }}
|
||||
</v-notice>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-button secondary @click="deleteActive = false">{{ $t('cancel') }}</v-button>
|
||||
<v-button @click="deleteSave" :loading="deleteSaving">{{ $t('delete') }}</v-button>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from '@vue/composition-api';
|
||||
import { Folder } from '../../composables/use-folders';
|
||||
import { defineComponent, PropType, ref } from '@vue/composition-api';
|
||||
import useFolders, { Folder } from '../../composables/use-folders';
|
||||
import notify from '@/utils/notify';
|
||||
import api from '@/api';
|
||||
import FolderPicker from '../folder-picker';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'navigation-folder',
|
||||
components: { FolderPicker },
|
||||
props: {
|
||||
folder: {
|
||||
type: Object as PropType<Folder>,
|
||||
@@ -44,5 +127,129 @@ export default defineComponent({
|
||||
default: () => undefined,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { renameActive, renameValue, renameSave, renameSaving } = useRenameFolder();
|
||||
const { moveActive, moveValue, moveSave, moveSaving } = useMoveFolder();
|
||||
const { deleteActive, deleteSave, deleteSaving } = useDeleteFolder();
|
||||
|
||||
const { fetchFolders } = useFolders();
|
||||
|
||||
return {
|
||||
renameActive,
|
||||
renameValue,
|
||||
renameSave,
|
||||
renameSaving,
|
||||
moveActive,
|
||||
moveValue,
|
||||
moveSave,
|
||||
moveSaving,
|
||||
deleteActive,
|
||||
deleteSave,
|
||||
deleteSaving,
|
||||
};
|
||||
|
||||
function useRenameFolder() {
|
||||
const renameActive = ref(false);
|
||||
const renameValue = ref(props.folder.name);
|
||||
const renameSaving = ref(false);
|
||||
|
||||
return { renameActive, renameValue, renameSave, renameSaving };
|
||||
|
||||
async function renameSave() {
|
||||
renameSaving.value = true;
|
||||
|
||||
try {
|
||||
await api.patch(`/folders/${props.folder.id}`, {
|
||||
name: renameValue.value,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
renameSaving.value = false;
|
||||
await fetchFolders();
|
||||
renameActive.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function useMoveFolder() {
|
||||
const moveActive = ref(false);
|
||||
const moveValue = ref(props.folder.parent_folder);
|
||||
const moveSaving = ref(false);
|
||||
|
||||
return { moveActive, moveValue, moveSave, moveSaving };
|
||||
|
||||
async function moveSave() {
|
||||
moveSaving.value = true;
|
||||
|
||||
try {
|
||||
await api.patch(`/folders/${props.folder.id}`, {
|
||||
parent_folder: moveValue.value,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
moveSaving.value = false;
|
||||
await fetchFolders();
|
||||
moveActive.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function useDeleteFolder() {
|
||||
const deleteActive = ref(false);
|
||||
const deleteSaving = ref(false);
|
||||
|
||||
return { deleteActive, deleteSave, deleteSaving };
|
||||
|
||||
async function deleteSave() {
|
||||
deleteSaving.value = true;
|
||||
|
||||
try {
|
||||
const foldersToUpdate = await api.get('/folders', {
|
||||
params: {
|
||||
filter: {
|
||||
parent_folder: {
|
||||
_eq: props.folder.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const filesToUpdate = await api.get('/files', {
|
||||
params: {
|
||||
filter: {
|
||||
folder: {
|
||||
_eq: props.folder.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const newParent = props.folder.parent_folder || null;
|
||||
|
||||
const folderKeys = foldersToUpdate.data.data.map((folder: { id: string }) => folder.id);
|
||||
const fileKeys = filesToUpdate.data.data.map((file: { id: string }) => file.id);
|
||||
|
||||
if (folderKeys.length > 0) {
|
||||
await api.patch(`/folders/${folderKeys.join(',')}`, { parent_folder: newParent });
|
||||
}
|
||||
|
||||
if (fileKeys.length > 0) {
|
||||
await api.patch(`/files/${fileKeys.join(',')}`, { folder: newParent });
|
||||
}
|
||||
|
||||
await api.delete(`/folders/${props.folder.id}`);
|
||||
|
||||
deleteActive.value = false;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
await fetchFolders();
|
||||
deleteSaving.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -2,14 +2,15 @@ import api from '@/api';
|
||||
import { ref, Ref } from '@vue/composition-api';
|
||||
|
||||
type FolderRaw = {
|
||||
id: number;
|
||||
id: string;
|
||||
name: string;
|
||||
parent_folder: number;
|
||||
parent_folder: string;
|
||||
};
|
||||
|
||||
export type Folder = {
|
||||
id: number;
|
||||
id: string;
|
||||
name: string;
|
||||
parent_folder: string;
|
||||
children?: Folder[];
|
||||
};
|
||||
|
||||
@@ -63,7 +64,7 @@ export function nestChildren(rawFolder: FolderRaw, rawFolders: FolderRaw[]) {
|
||||
const folder: FolderRaw & Folder = { ...rawFolder };
|
||||
|
||||
const children = rawFolders
|
||||
.filter((childFolder) => childFolder.parent_folder === rawFolder.id)
|
||||
.filter((childFolder) => childFolder.parent_folder === rawFolder.id && childFolder.id !== rawFolder.id)
|
||||
.map((childRawFolder) => nestChildren(childRawFolder, rawFolders));
|
||||
|
||||
if (children.length > 0) {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</v-button>
|
||||
|
||||
<div v-else-if="collection.collection.startsWith('directus_') === false">
|
||||
<v-menu placement="left-start" show-arrow close-on-content-click :disabled="savingManaged">
|
||||
<v-menu placement="left-start" show-arrow :disabled="savingManaged">
|
||||
<template #activator="{ toggle }">
|
||||
<v-progress-circular small v-if="savingManaged" indeterminate />
|
||||
<v-icon v-else name="more_vert" @click="toggle" class="ctx-toggle" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div :class="field.meta.width || 'full'">
|
||||
<v-menu attached close-on-content-click>
|
||||
<v-menu attached>
|
||||
<template #activator="{ toggle, active }">
|
||||
<v-input class="field" :class="{ hidden, active }" readonly @click="toggle">
|
||||
<template #prepend>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
/>
|
||||
</draggable>
|
||||
|
||||
<v-menu attached close-on-content-click>
|
||||
<v-menu attached>
|
||||
<template #activator="{ toggle, active }">
|
||||
<v-button
|
||||
@click="toggle"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</div>
|
||||
|
||||
<div class="header-right">
|
||||
<v-menu show-arrow placement="bottom-end" close-on-content-click>
|
||||
<v-menu show-arrow placement="bottom-end">
|
||||
<template #activator="{ toggle, active }">
|
||||
<v-icon class="more" :class="{ active }" name="more_horiz" @click="toggle" />
|
||||
<div class="time">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<span v-if="filter.field.includes('.')" class="relational-indicator">•</span>
|
||||
{{ name }}
|
||||
</div>
|
||||
<v-menu show-arrow :disabled="disabled" close-on-content-click>
|
||||
<v-menu show-arrow :disabled="disabled">
|
||||
<template #activator="{ toggle }">
|
||||
<div class="operator" @click="toggle">
|
||||
<span>{{ $t(`operators.${activeOperator}`) }}</span>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<v-divider v-if="filters.length" />
|
||||
|
||||
<v-menu attached close-on-content-click :disabled="loading">
|
||||
<v-menu attached :disabled="loading">
|
||||
<template #activator="{ toggle, active }">
|
||||
<v-input @click="toggle" :class="{ active }" readonly :value="$t('add_filter')" :disabled="loading">
|
||||
<template #prepend><v-icon name="add" /></template>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
v-tooltip.bottom.inverted="$t('flip_vertical')"
|
||||
/>
|
||||
|
||||
<v-menu placement="top" show-arrow close-on-content-click>
|
||||
<v-menu placement="top" show-arrow>
|
||||
<template #activator="{ toggle }">
|
||||
<v-icon
|
||||
:name="aspectRatioIcon"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<v-menu close-on-content-click show-arrow>
|
||||
<v-menu show-arrow>
|
||||
<template #activator="{ toggle }">
|
||||
<span @click="toggle" class="picker">
|
||||
{{ selectedOption && selectedOption.text }}
|
||||
|
||||
Reference in New Issue
Block a user