From 212481ff07e631b66d258bb8a76143a3a8688e06 Mon Sep 17 00:00:00 2001 From: Jonathan Schneider Date: Mon, 12 Sep 2022 22:30:43 +0200 Subject: [PATCH] Add missing download and token parameter in File interface (#14871) * add missing download and token parameter * add download name * update all file download links (:download and :href), update icon, add single file drawer download * add filename_download to adjustFieldsForDisplays * add new computed use asset url logic * switch composable to utility function * switch to new URL and add tests * add getAssetUrl to file-image * Update app/src/interfaces/files/files.vue Co-authored-by: Nitwel * update code style error * add download to drawer of file-image, fix wrong css selector and update preview download icon * Remove debugging database Co-authored-by: Rijk van Zanten Co-authored-by: Brainslug Co-authored-by: ian Co-authored-by: Nitwel --- app/src/interfaces/file-image/file-image.vue | 141 ++++++++++--------- app/src/interfaces/file/file.vue | 18 +-- app/src/interfaces/files/files.vue | 36 +++-- app/src/modules/files/routes/item.vue | 21 +-- app/src/utils/get-asset-url.test.ts | 31 ++++ app/src/utils/get-asset-url.ts | 12 ++ 6 files changed, 161 insertions(+), 98 deletions(-) create mode 100644 app/src/utils/get-asset-url.test.ts create mode 100644 app/src/utils/get-asset-url.ts diff --git a/app/src/interfaces/file-image/file-image.vue b/app/src/interfaces/file-image/file-image.vue index 4730518136..4a0557eb4a 100644 --- a/app/src/interfaces/file-image/file-image.vue +++ b/app/src/interfaces/file-image/file-image.vue @@ -35,8 +35,14 @@ - - + + @@ -61,7 +67,13 @@ :primary-key="image.id" :edits="edits" @input="update" - /> + > + + @@ -76,7 +88,7 @@ import api, { addTokenToURL } from '@/api'; import { useRelationM2O } from '@/composables/use-relation-m2o'; import { RelationQuerySingle, useRelationSingle } from '@/composables/use-relation-single'; import { formatFilesize } from '@/utils/format-filesize'; -import { getRootPath } from '@/utils/get-root-path'; +import { getAssetUrl } from '@/utils/get-asset-url'; import { readableMimeType } from '@/utils/readable-mime-type'; import DrawerItem from '@/views/private/components/drawer-item.vue'; import FileLightbox from '@/views/private/components/file-lightbox.vue'; @@ -142,11 +154,6 @@ const src = computed(() => { const ext = computed(() => (image.value ? readableMimeType(image.value.type, true) : 'unknown')); -const downloadSrc = computed(() => { - if (!image.value) return null; - return addTokenToURL(getRootPath() + 'assets/' + image.value.id); -}); - const meta = computed(() => { if (!image.value) return null; const { filesize, width, height, type } = image.value; @@ -238,74 +245,76 @@ img { } } -.shadow { - position: absolute; - bottom: 0; - left: 0; - z-index: 2; - width: 100%; - height: 40px; - overflow: hidden; - line-height: 1; - white-space: nowrap; - text-overflow: ellipsis; - background: linear-gradient(180deg, rgb(38 50 56 / 0) 0%, rgb(38 50 56 / 0.25) 100%); - transition: height var(--fast) var(--transition); -} +.image-preview { + .shadow { + position: absolute; + bottom: 0; + left: 0; + z-index: 2; + width: 100%; + height: 40px; + overflow: hidden; + line-height: 1; + white-space: nowrap; + text-overflow: ellipsis; + background: linear-gradient(180deg, rgb(38 50 56 / 0) 0%, rgb(38 50 56 / 0.25) 100%); + transition: height var(--fast) var(--transition); + } -.actions { - --v-button-color: var(--foreground-subdued); - --v-button-background-color: var(--white); - --v-button-color-hover: var(--foreground-normal); - --v-button-background-color-hover: var(--white); + .actions { + --v-button-color: var(--foreground-subdued); + --v-button-background-color: var(--white); + --v-button-color-hover: var(--foreground-normal); + --v-button-background-color-hover: var(--white); - position: absolute; - top: calc(50% - 32px); - left: 0; - z-index: 3; - display: flex; - justify-content: center; - width: 100%; + position: absolute; + top: calc(50% - 32px); + left: 0; + z-index: 3; + display: flex; + justify-content: center; + width: 100%; - .v-button { - margin-right: 12px; - transform: translateY(10px); - opacity: 0; - transition: var(--medium) var(--transition); - transition-property: opacity transform; + .v-button { + margin-right: 12px; + transform: translateY(10px); + opacity: 0; + transition: var(--medium) var(--transition); + transition-property: opacity transform; - @for $i from 0 through 4 { - &:nth-of-type(#{$i + 1}) { - transition-delay: $i * 25ms; + @for $i from 0 through 4 { + &:nth-of-type(#{$i + 1}) { + transition-delay: $i * 25ms; + } } } + + .v-button:last-child { + margin-right: 0px; + } } - .v-button:last-child { - margin-right: 0px; + .info { + position: absolute; + bottom: 0; + left: 0; + z-index: 3; + width: 100%; + padding: 8px 12px; + line-height: 1.2; } -} -.info { - position: absolute; - bottom: 0; - left: 0; - z-index: 3; - width: 100%; - padding: 8px 12px; - line-height: 1.2; -} + .title { + color: var(--white); + } -.title { - color: var(--white); -} - -.meta { - height: 17px; - max-height: 0; - overflow: hidden; - color: rgb(255 255 255 / 0.75); - transition: max-height var(--fast) var(--transition); + .meta { + height: 17px; + max-height: 0; + overflow: hidden; + color: rgb(255 255 255 / 0.75); + transition: max-height var(--fast) var(--transition); + } } .image-preview:focus-within, diff --git a/app/src/interfaces/file/file.vue b/app/src/interfaces/file/file.vue index ad9b096311..fea17a7c4c 100644 --- a/app/src/interfaces/file/file.vue +++ b/app/src/interfaces/file/file.vue @@ -46,7 +46,7 @@ - + {{ t('open_file_in_tab') }} - + {{ t('download_file') }} @@ -89,7 +93,7 @@ secondary rounded icon - download + :download="downloadName" :href="downloadUrl" > @@ -129,12 +133,11 @@ import { useI18n } from 'vue-i18n'; import DrawerItem from '@/views/private/components/drawer-item.vue'; import DrawerCollection from '@/views/private/components/drawer-collection.vue'; import Draggable from 'vuedraggable'; +import { getAssetUrl } from '@/utils/get-asset-url'; import { adjustFieldsForDisplays } from '@/utils/adjust-fields-for-displays'; import { get, clamp, isEmpty } from 'lodash'; import { usePermissionsStore } from '@/stores/permissions'; import { useUserStore } from '@/stores/user'; -import { addTokenToURL } from '@/api'; -import { getRootPath } from '@/utils/get-root-path'; import { getFieldsFromTemplate } from '@directus/shared/utils'; import { Filter } from '@directus/shared/types'; @@ -202,7 +205,7 @@ const templateWithDefaults = computed(() => { const fields = computed(() => adjustFieldsForDisplays( - getFieldsFromTemplate(templateWithDefaults.value), + [...getFieldsFromTemplate(templateWithDefaults.value), `${relationInfo.value?.relation.field}.filename_download`], relationInfo.value?.junctionCollection.collection ?? '' ) ); @@ -317,23 +320,28 @@ function onSelect(selected: string[]) { select(selected.filter((id) => selectedPrimaryKeys.value.includes(id) === false)); } -const downloadUrl = computed(() => { +const downloadName = computed(() => { if (relatedPrimaryKey.value === null || relationInfo.value?.relatedCollection.collection !== 'directus_files') return; - return addTokenToURL(getRootPath() + `assets/${relatedPrimaryKey.value}?download`); + const junctionField = relationInfo.value.junctionField.field; + const relationPkField = relationInfo.value.relatedPrimaryKeyField.field; + + return displayItems.value.find((item) => get(item, [junctionField, relationPkField]))?.directus_files_id + ?.filename_download; }); -function getUrl(junctionRow: Record, addDownload?: boolean) { +const downloadUrl = computed(() => { + if (relatedPrimaryKey.value === null || relationInfo.value?.relatedCollection.collection !== 'directus_files') return; + return getAssetUrl(String(relatedPrimaryKey.value), true); +}); + +function getFilename(junctionRow: Record) { const junctionField = relationInfo.value?.junctionField.field; if (!junctionField) return; const key = junctionRow[junctionField]?.id ?? junctionRow[junctionField] ?? null; if (!key) return null; - if (addDownload) { - return addTokenToURL(getRootPath() + `assets/${key}?download`); - } - - return addTokenToURL(getRootPath() + `assets/${key}`); + return key; } const customFilter = computed(() => { diff --git a/app/src/modules/files/routes/item.vue b/app/src/modules/files/routes/item.vue index 9e4a20773c..ed88307685 100644 --- a/app/src/modules/files/routes/item.vue +++ b/app/src/modules/files/routes/item.vue @@ -65,9 +65,15 @@ - - - + +