mirror of
https://github.com/directus/directus.git
synced 2026-01-28 00:57:55 -05:00
Open current folder in library / detail
This commit is contained in:
@@ -126,7 +126,11 @@ export default defineComponent({
|
||||
if (notEmpty(props.to)) return 'router-link';
|
||||
return 'button';
|
||||
});
|
||||
const { active, toggle } = useGroupable(props.value, 'button-group');
|
||||
|
||||
const { active, toggle } = useGroupable({
|
||||
value: props.value,
|
||||
group: 'button-group',
|
||||
});
|
||||
|
||||
return { sizeClass, onClick, component, active, toggle };
|
||||
|
||||
|
||||
@@ -20,7 +20,11 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { active, toggle } = useGroupable(props.value, props.scope);
|
||||
const { active, toggle } = useGroupable({
|
||||
value: props.value,
|
||||
group: props.scope,
|
||||
});
|
||||
|
||||
return { active, toggle };
|
||||
},
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, toRefs } from '@vue/composition-api';
|
||||
import { defineComponent, toRefs, watch } from '@vue/composition-api';
|
||||
import { useGroupableParent, useGroupable } from '@/composables/groupable';
|
||||
|
||||
export default defineComponent({
|
||||
@@ -42,9 +42,17 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
open: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props, { listeners, emit }) {
|
||||
const { active: groupActive, toggle } = useGroupable();
|
||||
const { active: groupActive, toggle, activate, deactivate } = useGroupable({
|
||||
active: toRefs(props).open,
|
||||
});
|
||||
|
||||
// watch(() => props.open, () => props.open ? activate() : deactivate(), { immediate: true });
|
||||
|
||||
useGroupableParent(
|
||||
{},
|
||||
|
||||
@@ -16,7 +16,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { active, toggle } = useGroupable(props.value);
|
||||
const { active, toggle } = useGroupable({ value: props.value });
|
||||
return { active, toggle };
|
||||
},
|
||||
});
|
||||
|
||||
@@ -23,7 +23,11 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { active, toggle } = useGroupable(props.value, 'v-tabs');
|
||||
const { active, toggle } = useGroupable({
|
||||
value: props.value,
|
||||
group: 'v-tabs',
|
||||
});
|
||||
|
||||
const vertical = inject('v-tabs-vertical', ref(false));
|
||||
|
||||
return { active, toggle, onClick, vertical };
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('Groupable', () => {
|
||||
|
||||
mountComposable(() => {
|
||||
provide('item-group', { register, unregister, toggle });
|
||||
useGroupable('custom-value');
|
||||
useGroupable({ value: 'custom-value' });
|
||||
});
|
||||
|
||||
expect(register).toHaveBeenCalledWith({
|
||||
@@ -56,7 +56,7 @@ describe('Groupable', () => {
|
||||
|
||||
mountComposable(() => {
|
||||
provide('item-group', { register, unregister, toggle });
|
||||
const result = useGroupable('custom-value');
|
||||
const result = useGroupable({ value: 'custom-value' });
|
||||
expect(result!.active).toEqual({ value: false });
|
||||
expect(result!.toggle).toBeInstanceOf(Function);
|
||||
});
|
||||
@@ -69,7 +69,7 @@ describe('Groupable', () => {
|
||||
|
||||
mountComposable(() => {
|
||||
provide('item-group', { register, unregister, toggle });
|
||||
const result = useGroupable('custom-value');
|
||||
const result = useGroupable({ value: 'custom-value' });
|
||||
result!.toggle();
|
||||
expect(toggle).toHaveBeenCalled();
|
||||
});
|
||||
@@ -82,7 +82,7 @@ describe('Groupable', () => {
|
||||
|
||||
mountComposable(() => {
|
||||
provide('item-group', { register, unregister, toggle });
|
||||
const result = useGroupable('custom-value');
|
||||
const result = useGroupable({ value: 'custom-value' });
|
||||
result!.toggle();
|
||||
expect(result!.active).toEqual({ value: true });
|
||||
});
|
||||
|
||||
@@ -11,15 +11,25 @@ type GroupableInstance = {
|
||||
* Used to make child item part of the group context. Needs to be used in a component that is a child
|
||||
* of a component that has the `useGroupableParent` composition enabled
|
||||
*/
|
||||
export function useGroupable(value?: string | number, group = 'item-group') {
|
||||
type GroupableOptions = {
|
||||
value?: string | number;
|
||||
group?: string;
|
||||
active?: Ref<boolean>;
|
||||
};
|
||||
|
||||
export function useGroupable(options?: GroupableOptions) {
|
||||
// Injects the registration / toggle functions from the parent scope
|
||||
const parentFunctions = inject(group, null);
|
||||
const parentFunctions = inject(options?.group || 'item-group', null);
|
||||
|
||||
if (isEmpty(parentFunctions)) {
|
||||
return {
|
||||
active: ref(false),
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
toggle: () => {},
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
activate: () => {},
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
deactivate: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,9 +44,28 @@ export function useGroupable(value?: string | number, group = 'item-group') {
|
||||
} = parentFunctions;
|
||||
|
||||
const active = ref(false);
|
||||
const item = { active, value };
|
||||
const item = { active, value: options?.value };
|
||||
|
||||
register(item);
|
||||
|
||||
if (options?.active) {
|
||||
if (options.active.value === true) toggle(item);
|
||||
|
||||
watch(options.active, () => {
|
||||
if (options.active === undefined) return;
|
||||
|
||||
if (options.active.value === true) {
|
||||
if (active.value === false) toggle(item);
|
||||
active.value = true;
|
||||
}
|
||||
|
||||
if (options.active.value === false) {
|
||||
if (active.value === true) toggle(item);
|
||||
active.value = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => unregister(item));
|
||||
|
||||
return {
|
||||
@@ -45,6 +74,14 @@ export function useGroupable(value?: string | number, group = 'item-group') {
|
||||
active.value = !active.value;
|
||||
toggle(item);
|
||||
},
|
||||
activate: () => {
|
||||
if (active.value === false) toggle(item);
|
||||
active.value = true;
|
||||
},
|
||||
deactivate: () => {
|
||||
if (active.value === true) toggle(item);
|
||||
active.value = false;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
:active="currentFolder === folder.id"
|
||||
exact
|
||||
@contextmenu.native.prevent="$refs.contextMenu.activate"
|
||||
:open="isOpen"
|
||||
>
|
||||
<template #activator="{ active }">
|
||||
<template #activator>
|
||||
<v-list-item-icon>
|
||||
<v-icon :name="active ? 'folder_open' : 'folder'" />
|
||||
<v-icon name="folder" />
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>{{ folder.name }}</v-list-item-content>
|
||||
</template>
|
||||
@@ -30,6 +31,7 @@
|
||||
:folder="childFolder"
|
||||
:current-folder="currentFolder"
|
||||
:click-handler="clickHandler"
|
||||
:start-open-folders="startOpenFolders"
|
||||
/>
|
||||
</v-list-group>
|
||||
|
||||
@@ -106,7 +108,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref } from '@vue/composition-api';
|
||||
import { defineComponent, PropType, ref, watch, computed } from '@vue/composition-api';
|
||||
import useFolders, { Folder } from '../../composables/use-folders';
|
||||
import notify from '@/utils/notify';
|
||||
import api from '@/api';
|
||||
@@ -129,6 +131,10 @@ export default defineComponent({
|
||||
type: Function,
|
||||
default: () => undefined,
|
||||
},
|
||||
startOpenFolders: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { renameActive, renameValue, renameSave, renameSaving } = useRenameFolder();
|
||||
@@ -137,6 +143,10 @@ export default defineComponent({
|
||||
|
||||
const { fetchFolders } = useFolders();
|
||||
|
||||
const isOpen = computed(() => {
|
||||
return props.startOpenFolders.includes(props.folder.id);
|
||||
});
|
||||
|
||||
return {
|
||||
renameActive,
|
||||
renameValue,
|
||||
@@ -149,6 +159,7 @@ export default defineComponent({
|
||||
deleteActive,
|
||||
deleteSave,
|
||||
deleteSaving,
|
||||
isOpen,
|
||||
};
|
||||
|
||||
function useRenameFolder() {
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<v-list-item-content>{{ $t('all_files') }}</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider v-if="loading || folders.length > 0" />
|
||||
<v-divider v-if="loading || nestedFolders.length > 0" />
|
||||
|
||||
<template v-if="loading && (folders === null || folders.length === 0)">
|
||||
<template v-if="loading && (nestedFolders === null || nestedFolders.length === 0)">
|
||||
<v-list-item v-for="n in 4" :key="n">
|
||||
<v-skeleton-loader type="list-item-icon" />
|
||||
</v-list-item>
|
||||
@@ -15,17 +15,18 @@
|
||||
|
||||
<div class="folders">
|
||||
<navigation-folder
|
||||
v-for="folder in folders"
|
||||
v-for="folder in nestedFolders"
|
||||
:key="folder.id"
|
||||
:folder="folder"
|
||||
:current-folder="currentFolder"
|
||||
:start-open-folders="startOpenFolders"
|
||||
/>
|
||||
</div>
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '@vue/composition-api';
|
||||
import { defineComponent, computed } from '@vue/composition-api';
|
||||
import useFolders from '../../composables/use-folders';
|
||||
import NavigationFolder from './navigation-folder.vue';
|
||||
|
||||
@@ -41,10 +42,31 @@ export default defineComponent({
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const { folders, error, loading } = useFolders();
|
||||
setup(props) {
|
||||
const { nestedFolders, folders, error, loading } = useFolders();
|
||||
|
||||
return { folders, error, loading };
|
||||
const startOpenFolders = computed(() => {
|
||||
if (!folders.value) return [];
|
||||
|
||||
const openFolders: string[] = [];
|
||||
|
||||
parseFolder(props.currentFolder);
|
||||
|
||||
return openFolders;
|
||||
|
||||
function parseFolder(id: string) {
|
||||
if (!folders.value) return;
|
||||
openFolders.push(id);
|
||||
|
||||
const folder = folders.value.find((folder) => folder.id === id);
|
||||
|
||||
if (folder && folder.parent_folder) {
|
||||
parseFolder(folder.parent_folder);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return { folders, nestedFolders, error, loading, startOpenFolders };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -16,23 +16,26 @@ export type Folder = {
|
||||
|
||||
let loading: Ref<boolean> | null = null;
|
||||
let folders: Ref<Folder[] | null> | null = null;
|
||||
let nestedFolders: Ref<Folder[] | null> | null = null;
|
||||
|
||||
let error: Ref<any> | null = null;
|
||||
|
||||
export default function useFolders() {
|
||||
if (loading === null) loading = ref(false);
|
||||
if (folders === null) folders = ref<Folder[] | null>(null);
|
||||
if (nestedFolders === null) nestedFolders = ref<Folder[] | null>(null);
|
||||
if (error === null) error = ref(null);
|
||||
|
||||
if (folders.value === null && loading.value === false) {
|
||||
fetchFolders();
|
||||
}
|
||||
|
||||
return { loading, folders, error, fetchFolders };
|
||||
return { loading, folders, nestedFolders, error, fetchFolders };
|
||||
|
||||
async function fetchFolders() {
|
||||
if (loading === null) return;
|
||||
if (folders === null) return;
|
||||
if (nestedFolders === null) return;
|
||||
if (error === null) return;
|
||||
|
||||
loading.value = true;
|
||||
@@ -45,7 +48,8 @@ export default function useFolders() {
|
||||
},
|
||||
});
|
||||
|
||||
folders.value = nestFolders(response.data.data);
|
||||
folders.value = response.data.data;
|
||||
nestedFolders.value = nestFolders(response.data.data);
|
||||
} catch (err) {
|
||||
error.value = err;
|
||||
} finally {
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
</template>
|
||||
|
||||
<template #navigation>
|
||||
<files-navigation />
|
||||
<files-navigation :current-folder="queryFilters && queryFilters.folder" />
|
||||
</template>
|
||||
|
||||
<component
|
||||
@@ -130,6 +130,7 @@ import marked from 'marked';
|
||||
import FolderPicker from '../../components/folder-picker';
|
||||
import emitter, { Events } from '@/events';
|
||||
import router from '@/router';
|
||||
import Vue from 'vue';
|
||||
|
||||
type Item = {
|
||||
[field: string]: any;
|
||||
@@ -287,11 +288,13 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
selection.value = [];
|
||||
await layout.value?.refresh();
|
||||
|
||||
if (selectedFolder.value) {
|
||||
router.push(`/files?folder=${selectedFolder.value}`);
|
||||
}
|
||||
|
||||
await Vue.nextTick();
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
|
||||
@@ -48,7 +48,10 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { active, toggle } = useGroupable(props.title, 'drawer-detail');
|
||||
const { active, toggle } = useGroupable({
|
||||
value: props.title,
|
||||
group: 'drawer-detail',
|
||||
});
|
||||
const appStore = useAppStore();
|
||||
const { drawerOpen } = toRefs(appStore.state);
|
||||
return { active, toggle, drawerOpen };
|
||||
|
||||
Reference in New Issue
Block a user