From e6fca0e75d6714f8fb399208735d1d0cb68e71fa Mon Sep 17 00:00:00 2001 From: Nicolas KEMPF Date: Mon, 11 Dec 2023 16:00:03 +0100 Subject: [PATCH 1/2] feat: :necktie: show resources based on their type (#250) * feat: :necktie: show resources based on their type * feat: :sparkles: add loader * fix: :adhesive_bandage: remove duplicated `/` * fix: :adhesive_bandage: remove duplicated `/` * fix: :bug: fix type not always defined * refactor: :recycle: use const instead of let * refactor: :recycle: save resource types to store * fix: :adhesive_bandage: fix missing margin between resources without pagination --- package-lock.json | 8 -- package.json | 3 +- src/store/DatasetStore.js | 43 ++++--- src/store/ReuseStore.js | 2 +- src/views/datasets/DatasetDetailView.vue | 140 +++++++++++------------ 5 files changed, 96 insertions(+), 100 deletions(-) diff --git a/package-lock.json b/package-lock.json index b99dda4e9..4475c8a79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "@vueform/multiselect": "^2.6.2", "axios": "^1.6.2", "chart.js": "^4.4.0", - "filesize": "^10.0.7", "lodash": "^4.17.21", "markdown-it": "^13.0.2", "marked": "^5.1.0", @@ -4319,13 +4318,6 @@ "node": ">=10" } }, - "node_modules/filesize": { - "version": "10.1.0", - "license": "BSD-3-Clause", - "engines": { - "node": ">= 10.4.0" - } - }, "node_modules/fill-range": { "version": "7.0.1", "license": "MIT", diff --git a/package.json b/package.json index cb3d172a2..f8d37e92f 100644 --- a/package.json +++ b/package.json @@ -18,12 +18,11 @@ "prepare": "husky install" }, "dependencies": { - "@gouvminint/vue-dsfr": "^5.3.1", "@etalab/data.gouv.fr-components": "^1.11.1", + "@gouvminint/vue-dsfr": "^5.3.1", "@vueform/multiselect": "^2.6.2", "axios": "^1.6.2", "chart.js": "^4.4.0", - "filesize": "^10.0.7", "lodash": "^4.17.21", "markdown-it": "^13.0.2", "marked": "^5.1.0", diff --git a/src/store/DatasetStore.js b/src/store/DatasetStore.js index 3522bf547..8dd3bab00 100644 --- a/src/store/DatasetStore.js +++ b/src/store/DatasetStore.js @@ -21,6 +21,7 @@ const datasetsApiv2 = new DatasetsAPI({ version: 2 }) export const useDatasetStore = defineStore('dataset', { state: () => ({ data: {}, + resourceTypes: [], sort: null }), actions: { @@ -149,32 +150,46 @@ export const useDatasetStore = defineStore('dataset', { /** * Load resources from the API via a HATEOAS rel * - * @param {String} dataset_id * @param {Object} rel - HATEOAS rel for datasets - * @returns {Array} + * @param {string} pageSize - page size + * @returns {Promise, total: number}>>} */ async loadResources(rel, pageSize) { - let url = new URL(rel.href) - url.searchParams.set('page_size', pageSize) - let updatedUrl = url.toString() - - let response = await datasetsApiv2.request(updatedUrl) - return response + if (this.resourceTypes.length === 0) { + this.resourceTypes = await datasetsApi.get('resource_types') + } + const resources = [] + for (const type of this.resourceTypes) { + const url = new URL(rel.href) + url.searchParams.set('page_size', pageSize) + url.searchParams.set('type', type.id) + const updatedUrl = url.toString() + const response = await datasetsApiv2.request(updatedUrl) + resources.push({ + currentPage: 1, + resources: response.data, + total: response.total, + typeId: type.id, + typeLabel: type.label + }) + } + return resources }, - async fetchDatasetResources(datasetId, page, pageSize) { + async fetchDatasetResources(datasetId, type, page, pageSize) { const response = await datasetsApiv2.get(`${datasetId}/resources/`, { params: { - page: page, - page_size: pageSize + page, + page_size: pageSize, + type } }) return response.data }, - + async getLicense(license) { - let response = await datasetsApi.get('/licenses/') + const response = await datasetsApi.get('licenses') return response.find((l) => l.id == license) - }, + } } }) diff --git a/src/store/ReuseStore.js b/src/store/ReuseStore.js index f158b447c..49f36fb78 100644 --- a/src/store/ReuseStore.js +++ b/src/store/ReuseStore.js @@ -44,7 +44,7 @@ export const useReuseStore = defineStore('reuse', { }, async getTypes() { - return await reusesAPI.get('/types') + return await reusesAPI.get('types') } } }) diff --git a/src/views/datasets/DatasetDetailView.vue b/src/views/datasets/DatasetDetailView.vue index 53cb9b689..fa1eb5701 100644 --- a/src/views/datasets/DatasetDetailView.vue +++ b/src/views/datasets/DatasetDetailView.vue @@ -7,8 +7,8 @@ import { ReadMore, Well } from '@etalab/data.gouv.fr-components' -import { filesize } from 'filesize' -import { computed, onMounted, ref, watchEffect } from 'vue' +import { computed, onMounted, ref, watch } from 'vue' +import { useLoading } from 'vue-loading-overlay' import { useRoute } from 'vue-router' import config from '@/config' @@ -29,7 +29,7 @@ const discussionStore = useDiscussionStore() const dataset = computed(() => datasetStore.get(datasetId) || {}) const discussionsPages = ref([]) const reuses = ref([]) -const resources = ref([]) +const resources = ref({}) const discussions = ref({}) const discussionsPage = ref(1) const expandedDiscussion = ref(null) @@ -37,7 +37,6 @@ const selectedTabIndex = ref(0) const license = ref({}) const types = ref([]) const currentPage = ref(1) -const totalResults = ref(0) const pageSize = config.website.pagination_sizes.files_list const showDiscussions = config.website.show_dataset_discussions @@ -56,26 +55,6 @@ const links = computed(() => [ { text: dataset.value.title } ]) -const formatFileSize = (fileSize) => { - if (!fileSize) return 'Taille inconnue' - return filesize(fileSize) -} - -const files = computed(() => { - return resources.value?.map((resource) => { - return { - title: resource.title || 'Fichier sans nom', - format: resource.format, - size: formatFileSize( - resource.filesize || - resource.extras['check:headers:content-length'] || - resource.extras['analysis:content-length'] - ), - href: resource.url - } - }) -}) - const tabs = computed(() => { const _tabs = [ { title: 'Fichiers', tabId: 'tab-0', panelId: 'tab-content-0' }, @@ -102,12 +81,12 @@ const tabs = computed(() => { const description = computed(() => descriptionFromMarkdown(dataset)) -const changePage = (page = 1) => { - currentPage.value = page +const changePage = (type, page = 1) => { + resources.value[type].currentPage = page return datasetStore - .fetchDatasetResources(dataset.value.id, page, pageSize) + .fetchDatasetResources(dataset.value.id, type, page, pageSize) .then((data) => { - resources.value = data + resources.value[type].resources = data }) } @@ -158,7 +137,7 @@ const reuseDescription = (r) => { const getType = (id) => { let type = types.value.find((t) => t.id == id) - return type.label + return type?.label || '' } const discussionWellTitle = showDiscussions @@ -172,36 +151,43 @@ const openDataGouvDiscussions = () => window.open(`${dataset.value.page}#/discussions`, 'datagouv-discussion') // launch reuses and discussions fetch as soon as we have the technical id -watchEffect(async () => { - if (!dataset.value.id) return - // fetch reuses - reuseStore - .loadReusesForDataset(dataset.value.id) - .then((r) => (reuses.value = r)) - // fetch discussions - discussionStore - .loadDiscussionsForDataset(dataset.value.id, discussionsPage.value) - .then((d) => { - discussions.value = d - if (!discussionsPage.value.length) { - discussionsPages.value = - discussionStore.getDiscussionsPaginationForDataset(dataset.value.id) +watch( + dataset, + async () => { + if (!dataset.value.id) return + // fetch reuses + reuseStore + .loadReusesForDataset(dataset.value.id) + .then((r) => (reuses.value = r)) + // fetch discussions + discussionStore + .loadDiscussionsForDataset(dataset.value.id, discussionsPage.value) + .then((d) => { + discussions.value = d + if (!discussionsPage.value.length) { + discussionsPages.value = + discussionStore.getDiscussionsPaginationForDataset(dataset.value.id) + } + }) + // fetch ressources if need be + if (dataset.value.resources.rel) { + const resourceLoader = useLoading().show() + const allResources = await datasetStore.loadResources( + dataset.value.resources, + pageSize + ) + for (let typedResources of allResources) { + resources.value[typedResources.typeId] = typedResources } - }) - // fetch ressources if need be - if (dataset.value.resources.rel) { - const { data, total } = await datasetStore.loadResources( - dataset.value.resources, - pageSize - ) - resources.value = data - totalResults.value = total - } else { - resources.value = dataset.value.resources - } - license.value = await datasetStore.getLicense(dataset.value.license) - types.value = await reuseStore.getTypes() -}) + resourceLoader.hide() + } else { + resources.value = dataset.value.resources + } + license.value = await datasetStore.getLicense(dataset.value.license) + types.value = await reuseStore.getTypes() + }, + { immediate: true } +)