mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
script[setup]: file components (#18455)
This commit is contained in:
@@ -23,9 +23,9 @@
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
<script lang="ts" setup>
|
||||
import api from '@/api';
|
||||
import { computed, defineComponent, ref, watch } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import FilePreview from '@/views/private/components/file-preview.vue';
|
||||
import { nanoid } from 'nanoid';
|
||||
@@ -40,73 +40,64 @@ type File = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
components: { FilePreview },
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: undefined,
|
||||
},
|
||||
const props = defineProps<{
|
||||
id: string;
|
||||
modelValue?: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: boolean): void;
|
||||
}>();
|
||||
|
||||
const localActive = ref(false);
|
||||
|
||||
const internalActive = computed({
|
||||
get() {
|
||||
return props.modelValue === undefined ? localActive.value : props.modelValue;
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props, { emit }) {
|
||||
const localActive = ref(false);
|
||||
|
||||
const internalActive = computed({
|
||||
get() {
|
||||
return props.modelValue === undefined ? localActive.value : props.modelValue;
|
||||
},
|
||||
set(newActive: boolean) {
|
||||
localActive.value = newActive;
|
||||
emit('update:modelValue', newActive);
|
||||
},
|
||||
});
|
||||
|
||||
const loading = ref(false);
|
||||
const file = ref<File | null>(null);
|
||||
const cacheBuster = ref(nanoid());
|
||||
|
||||
const fileSrc = computed(() => {
|
||||
return getRootPath() + `assets/${props.id}?cache-buster=${cacheBuster.value}`;
|
||||
});
|
||||
|
||||
watch(
|
||||
[() => props.id, internalActive],
|
||||
([newID, newActive]) => {
|
||||
if (newActive && newID) {
|
||||
fetchFile();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
return { internalActive, cacheBuster, loading, file, fileSrc };
|
||||
|
||||
async function fetchFile() {
|
||||
cacheBuster.value = nanoid();
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await api.get(`/files/${props.id}`, {
|
||||
params: {
|
||||
fields: ['type', 'width', 'height', 'title'],
|
||||
},
|
||||
});
|
||||
|
||||
file.value = response.data.data;
|
||||
} catch (err: any) {
|
||||
unexpectedError(err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
set(newActive: boolean) {
|
||||
localActive.value = newActive;
|
||||
emit('update:modelValue', newActive);
|
||||
},
|
||||
});
|
||||
|
||||
const loading = ref(false);
|
||||
const file = ref<File | null>(null);
|
||||
const cacheBuster = ref(nanoid());
|
||||
|
||||
const fileSrc = computed(() => {
|
||||
return getRootPath() + `assets/${props.id}?cache-buster=${cacheBuster.value}`;
|
||||
});
|
||||
|
||||
watch(
|
||||
[() => props.id, internalActive],
|
||||
([newID, newActive]) => {
|
||||
if (newActive && newID) {
|
||||
fetchFile();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
async function fetchFile() {
|
||||
cacheBuster.value = nanoid();
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await api.get(`/files/${props.id}`, {
|
||||
params: {
|
||||
fields: ['type', 'width', 'height', 'title'],
|
||||
},
|
||||
});
|
||||
|
||||
file.value = response.data.data;
|
||||
} catch (err: any) {
|
||||
unexpectedError(err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
clickable
|
||||
:active="currentFolder === folder.id"
|
||||
:disabled="disabled"
|
||||
@click="clickHandler(folder.id)"
|
||||
@click="clickHandler?.(folder.id)"
|
||||
>
|
||||
<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>
|
||||
@@ -15,7 +15,7 @@
|
||||
clickable
|
||||
:active="currentFolder === folder.id"
|
||||
:disabled="disabled"
|
||||
@click="clickHandler(folder.id)"
|
||||
@click="clickHandler?.(folder.id)"
|
||||
>
|
||||
<template #activator>
|
||||
<v-list-item-icon>
|
||||
@@ -29,45 +29,25 @@
|
||||
:folder="childFolder"
|
||||
:current-folder="currentFolder"
|
||||
:click-handler="clickHandler"
|
||||
:disabled="disabledFolders.includes(childFolder.id)"
|
||||
:disabled="disabledFolders?.includes(childFolder.id)"
|
||||
:disabled-folders="disabledFolders"
|
||||
/>
|
||||
</v-list-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
|
||||
<script lang="ts" setup>
|
||||
type Folder = {
|
||||
id: string;
|
||||
name: string;
|
||||
children: Folder[];
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FolderPickerListItem',
|
||||
props: {
|
||||
folder: {
|
||||
type: Object as PropType<Folder>,
|
||||
required: true,
|
||||
},
|
||||
currentFolder: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
clickHandler: {
|
||||
type: Function,
|
||||
default: () => undefined,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disabledFolders: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
});
|
||||
defineProps<{
|
||||
folder: Folder;
|
||||
currentFolder: string | null;
|
||||
clickHandler?: (folderId: string) => void;
|
||||
disabled?: boolean;
|
||||
disabledFolders?: string[];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
:folder="folder"
|
||||
:current-folder="modelValue"
|
||||
:click-handler="(id) => $emit('update:modelValue', id)"
|
||||
:disabled="disabledFolders.includes(folder.id)"
|
||||
:disabled="disabledFolders?.includes(folder.id)"
|
||||
:disabled-folders="disabledFolders"
|
||||
/>
|
||||
</v-list-group>
|
||||
@@ -33,9 +33,9 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { defineComponent, ref, computed, PropType } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import api from '@/api';
|
||||
import FolderPickerListItem from './folder-picker-list-item.vue';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
@@ -52,104 +52,91 @@ type Folder = {
|
||||
children: Folder[];
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
components: { FolderPickerListItem },
|
||||
props: {
|
||||
disabledFolders: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props) {
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
disabledFolders?: string[];
|
||||
modelValue: string | null;
|
||||
}>();
|
||||
|
||||
const loading = ref(false);
|
||||
const folders = ref<FolderRaw[]>([]);
|
||||
defineEmits<{
|
||||
(e: 'update:modelValue', value: string | null): void;
|
||||
}>();
|
||||
|
||||
const tree = computed<Folder[]>(() => {
|
||||
return folders.value
|
||||
.filter((folder) => folder.parent === null)
|
||||
.map((folder) => {
|
||||
return {
|
||||
...folder,
|
||||
children: getChildFolders(folder),
|
||||
};
|
||||
});
|
||||
const { t } = useI18n();
|
||||
|
||||
function getChildFolders(folder: FolderRaw): Folder[] {
|
||||
return folders.value
|
||||
.filter((childFolder) => {
|
||||
return childFolder.parent === folder.id;
|
||||
})
|
||||
.map((childFolder) => {
|
||||
return {
|
||||
...childFolder,
|
||||
children: getChildFolders(childFolder),
|
||||
};
|
||||
});
|
||||
}
|
||||
const loading = ref(false);
|
||||
const folders = ref<FolderRaw[]>([]);
|
||||
|
||||
const tree = computed<Folder[]>(() => {
|
||||
return folders.value
|
||||
.filter((folder) => folder.parent === null)
|
||||
.map((folder) => {
|
||||
return {
|
||||
...folder,
|
||||
children: getChildFolders(folder),
|
||||
};
|
||||
});
|
||||
|
||||
const shouldBeOpen: string[] = [];
|
||||
const folder = folders.value.find((folder) => folder.id === props.modelValue);
|
||||
|
||||
if (folder && folder.parent) parseFolder(folder.parent);
|
||||
|
||||
const startOpenFolders = ['root'];
|
||||
|
||||
for (const folderID of shouldBeOpen) {
|
||||
if (startOpenFolders.includes(folderID) === false) {
|
||||
startOpenFolders.push(folderID);
|
||||
}
|
||||
}
|
||||
|
||||
const selectedFolder = computed(() => {
|
||||
return folders.value.find((folder) => folder.id === props.modelValue) || {};
|
||||
});
|
||||
|
||||
const openFolders = ref(startOpenFolders);
|
||||
|
||||
fetchFolders();
|
||||
|
||||
return { t, loading, folders, tree, selectedFolder, openFolders };
|
||||
|
||||
async function fetchFolders() {
|
||||
if (folders.value.length > 0) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await api.get(`/folders`, {
|
||||
params: {
|
||||
limit: -1,
|
||||
sort: 'name',
|
||||
},
|
||||
});
|
||||
|
||||
folders.value = response.data.data;
|
||||
} catch (err: any) {
|
||||
unexpectedError(err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function parseFolder(id: string) {
|
||||
if (!folders.value) return;
|
||||
shouldBeOpen.push(id);
|
||||
|
||||
const folder = folders.value.find((folder) => folder.id === id);
|
||||
|
||||
if (folder && folder.parent) {
|
||||
parseFolder(folder.parent);
|
||||
}
|
||||
}
|
||||
},
|
||||
function getChildFolders(folder: FolderRaw): Folder[] {
|
||||
return folders.value
|
||||
.filter((childFolder) => {
|
||||
return childFolder.parent === folder.id;
|
||||
})
|
||||
.map((childFolder) => {
|
||||
return {
|
||||
...childFolder,
|
||||
children: getChildFolders(childFolder),
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const shouldBeOpen: string[] = [];
|
||||
const selectedFolder = folders.value.find((folder) => folder.id === props.modelValue);
|
||||
|
||||
if (selectedFolder && selectedFolder.parent) parseFolder(selectedFolder.parent);
|
||||
|
||||
const startOpenFolders = ['root'];
|
||||
|
||||
for (const folderID of shouldBeOpen) {
|
||||
if (startOpenFolders.includes(folderID) === false) {
|
||||
startOpenFolders.push(folderID);
|
||||
}
|
||||
}
|
||||
|
||||
const openFolders = ref(startOpenFolders);
|
||||
|
||||
fetchFolders();
|
||||
|
||||
async function fetchFolders() {
|
||||
if (folders.value.length > 0) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await api.get(`/folders`, {
|
||||
params: {
|
||||
limit: -1,
|
||||
sort: 'name',
|
||||
},
|
||||
});
|
||||
|
||||
folders.value = response.data.data;
|
||||
} catch (err: any) {
|
||||
unexpectedError(err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function parseFolder(id: string) {
|
||||
if (!folders.value) return;
|
||||
shouldBeOpen.push(id);
|
||||
|
||||
const folder = folders.value.find((folder) => folder.id === id);
|
||||
|
||||
if (folder && folder.parent) {
|
||||
parseFolder(folder.parent);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Reference in New Issue
Block a user