diff --git a/src/landscape/components/LandscapeSharedDataUpload.js b/src/landscape/components/LandscapeSharedDataUpload.js index 243032a0ac..f1f949230a 100644 --- a/src/landscape/components/LandscapeSharedDataUpload.js +++ b/src/landscape/components/LandscapeSharedDataUpload.js @@ -90,6 +90,10 @@ const LandscapeSharedDataUpload = () => { groupSlug={_.get('defaultGroup.slug', landscape)} onCancel={onCancel} onCompleteSuccess={onCompleteSuccess} + targetInput={{ + targetType: 'landscape', + targetSlug: slug, + }} /> diff --git a/src/landscape/components/LandscapeSharedDataUploadLinks.test.js b/src/landscape/components/LandscapeSharedDataUploadLinks.test.js index bdb6f8c6b0..9f20b87d86 100644 --- a/src/landscape/components/LandscapeSharedDataUploadLinks.test.js +++ b/src/landscape/components/LandscapeSharedDataUploadLinks.test.js @@ -255,4 +255,17 @@ test('LandscapeSharedDataUpload: Complete Success', async () => { search: 'scrollTo=shared-data-card-title', }, ]); + expect(terrasoApi.requestGraphQL).toHaveBeenCalledTimes(3); + const saveCall = terrasoApi.requestGraphQL.mock.calls[2]; + expect(saveCall[1]).toStrictEqual({ + input: { + description: '', + entryType: 'link', + targetType: 'landscape', + targetSlug: 'slug-1', + name: 'name 1', + resourceType: 'link', + url: 'https://test1.com', + }, + }); }); diff --git a/src/landscape/components/LandscapeView.test.js b/src/landscape/components/LandscapeView.test.js index a1434ad394..0ca7feef03 100644 --- a/src/landscape/components/LandscapeView.test.js +++ b/src/landscape/components/LandscapeView.test.js @@ -108,19 +108,21 @@ const baseViewTest = async (userRole = 'MEMBER') => { membershipStatus: 'APPROVED', }; - const dataEntries = { + const sharedResources = { edges: Array(6) .fill(0) .map((item, index) => ({ node: { - id: `de-${index}`, - createdAt: '2022-05-20T16:25:21.536679+00:00', - name: `Data Entry ${index}`, - createdBy: { id: 'user-id', firstName: 'First', lastName: 'Last' }, - description: `Description ${index}`, - size: 3456, - entryType: 'FILE', - visualizations: { edges: [] }, + source: { + id: `de-${index}`, + createdAt: '2022-05-20T16:25:21.536679+00:00', + name: `Data Entry ${index}`, + createdBy: { id: 'user-id', firstName: 'First', lastName: 'Last' }, + description: `Description ${index}`, + size: 3456, + entryType: 'FILE', + visualizations: { edges: [] }, + }, }, })), }; @@ -141,6 +143,7 @@ const baseViewTest = async (userRole = 'MEMBER') => { accountMembership, membershipsCount: 6, }, + sharedResources, }, }, ], @@ -161,17 +164,7 @@ const baseViewTest = async (userRole = 'MEMBER') => { memberships, accountMembership, }, - }, - }, - ], - }, - }) - .mockResolvedValueOnce({ - groups: { - edges: [ - { - node: { - dataEntries, + sharedResources, }, }, ], @@ -310,7 +303,7 @@ test('LandscapeView: Update Shared Data', async () => { }) ) ); - const saveCall = terrasoApi.requestGraphQL.mock.calls[3]; + const saveCall = terrasoApi.requestGraphQL.mock.calls[2]; expect(saveCall[1].input).toEqual({ id: 'de-3', diff --git a/src/landscape/landscapeFragments.js b/src/landscape/landscapeFragments.js index c9d292f574..6b50b7f2b5 100644 --- a/src/landscape/landscapeFragments.js +++ b/src/landscape/landscapeFragments.js @@ -116,3 +116,20 @@ export const defaultGroupWithMembersSample = /* GraphQL */ ` } } `; + +export const landscapeDataEntries = /* GraphQL */ ` + fragment landscapeDataEntries on LandscapeNode { + sharedResources(source_DataEntry_ResourceType_In: $resourceTypes) { + edges { + node { + source { + ... on DataEntryNode { + ...dataEntry + ...dataEntryVisualizations + } + } + } + } + } + } +`; diff --git a/src/landscape/landscapeService.js b/src/landscape/landscapeService.js index f797842273..c69f7c4ad6 100644 --- a/src/landscape/landscapeService.js +++ b/src/landscape/landscapeService.js @@ -24,6 +24,7 @@ import { graphql } from 'terrasoApi/shared/graphqlSchema'; import { countryNameForCode } from 'common/countries'; import * as gisService from 'gis/gisService'; +import { extractDataEntries } from 'sharedData/sharedDataUtils'; import { extractTerms } from 'taxonomies/taxonomiesUtils'; import { ALL_PARTNERSHIP_STATUS } from './landscapeConstants'; @@ -170,6 +171,7 @@ export const fetchLandscapeToView = slug => { : null, partnershipStatus: ALL_PARTNERSHIP_STATUS[landscape.partnershipStatus], partnership: extractPartnership(landscape), + dataEntries: extractDataEntries(landscape), })) .then(landscape => { if (landscape.areaPolygon || !landscape.location) { diff --git a/src/landscape/landscapeSlice.js b/src/landscape/landscapeSlice.js index f8450a9581..8240d04c6e 100644 --- a/src/landscape/landscapeSlice.js +++ b/src/landscape/landscapeSlice.js @@ -21,6 +21,7 @@ import * as membershipsUtils from 'terraso-client-shared/memberships/memberships import { createAsyncThunk } from 'terraso-client-shared/store/utils'; import * as landscapeService from 'landscape/landscapeService'; +import { setList } from 'sharedData/sharedDataSlice'; const initialState = { list: { @@ -82,6 +83,7 @@ export const fetchLandscapeView = createAsyncThunk( currentUser ); dispatch(setMemberships(getMemberships([landscape]))); + dispatch(setList(landscape.dataEntries)); return landscape; } ); diff --git a/src/sharedData/components/SharedDataCard.js b/src/sharedData/components/SharedDataCard.js index 865db59f63..9161a34018 100644 --- a/src/sharedData/components/SharedDataCard.js +++ b/src/sharedData/components/SharedDataCard.js @@ -14,12 +14,11 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see https://www.gnu.org/licenses/. */ -import React, { useCallback } from 'react'; +import React from 'react'; import _ from 'lodash/fp'; import { usePermission } from 'permissions'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; -import { useFetchData } from 'terraso-client-shared/store/utils'; import { Button, Card, @@ -33,7 +32,6 @@ import { import List from 'common/components/List'; import { ScrollTo } from 'navigation/scrollTo'; import { useGroupContext } from 'group/groupContext'; -import { fetchGroupSharedData } from 'sharedData/sharedDataSlice'; import SharedDataEntryFile from './SharedDataEntryFile'; import SharedDataEntryLink from './SharedDataEntryLink'; @@ -48,13 +46,6 @@ const SharedFilesCard = props => { const { data: sharedFiles, fetching } = useSelector(_.get('sharedData.list')); const hasFiles = !_.isEmpty(sharedFiles); - useFetchData( - useCallback( - () => (allowed ? fetchGroupSharedData({ slug: group.slug }) : null), - [group.slug, allowed] - ) - ); - if (!allowed) { return null; } diff --git a/src/sharedData/components/SharedDataUpload/index.js b/src/sharedData/components/SharedDataUpload/index.js index e98b74b644..94de342e74 100644 --- a/src/sharedData/components/SharedDataUpload/index.js +++ b/src/sharedData/components/SharedDataUpload/index.js @@ -51,7 +51,7 @@ const SharedDataUpload = props => { const { trackEvent } = useAnalytics(); const { owner, entityType } = useGroupContext(); - const { groupSlug, onCancel, onCompleteSuccess } = props; + const { targetInput, onCancel, onCompleteSuccess } = props; const [section, setSection] = useState('files'); @@ -103,10 +103,10 @@ const SharedDataUpload = props => { const onSave = useCallback(() => { setShowSummary(false); const linksPromises = toUpload.links.map(link => - dispatch(addSharedDataLink({ groupSlug, link })) + dispatch(addSharedDataLink({ ...targetInput, link })) ); const filesPromises = toUpload.files.map(file => - dispatch(uploadSharedDataFile({ groupSlug, file })) + dispatch(uploadSharedDataFile({ ...targetInput, file })) ); const allPromises = [...filesPromises, ...linksPromises]; @@ -134,7 +134,7 @@ const SharedDataUpload = props => { }); setShowSummary(true); }); - }, [entityType, owner.slug, toUpload, groupSlug, dispatch, trackEvent]); + }, [entityType, owner.slug, toUpload, targetInput, dispatch, trackEvent]); const hasBlockingErrors = useMemo( () => diff --git a/src/sharedData/sharedDataService.js b/src/sharedData/sharedDataService.js index 5de08bca0c..28c2134cd4 100644 --- a/src/sharedData/sharedDataService.js +++ b/src/sharedData/sharedDataService.js @@ -18,18 +18,27 @@ import _ from 'lodash/fp'; import * as terrasoApi from 'terraso-client-shared/terrasoApi/api'; import { graphql } from 'terrasoApi/shared/graphqlSchema'; -import { extractDataEntry, extractGroupDataEntries } from 'group/groupUtils'; +import { extractDataEntries, extractDataEntry } from './sharedDataUtils'; import { SHARED_DATA_ACCEPTED_EXTENSIONS } from 'config'; const ALL_RESOURCE_TYPES = [...SHARED_DATA_ACCEPTED_EXTENSIONS, 'link']; -export const uploadSharedDataFile = async ({ groupSlug, file }) => { +export const uploadSharedDataFile = async ({ + groupSlug, + landscapeSlug, + file, +}) => { const path = '/shared-data/upload/'; const body = new FormData(); const filename = `${file.name}${file.resourceType}`; - body.append('groups', groupSlug); + if (groupSlug) { + body.append('groups', groupSlug); + } + if (landscapeSlug) { + body.append('landscapes', landscapeSlug); + } body.append('name', file.name); if (file.description) { body.append('description', file.description); @@ -61,7 +70,7 @@ export const deleteSharedData = ({ dataEntry }) => { }); }; -export const addSharedDataLink = ({ groupSlug, link }) => { +export const addSharedDataLink = ({ targetType, targetSlug, link }) => { const query = graphql(` mutation addDataEntry($input: DataEntryAddMutationInput!) { addDataEntry(input: $input) { @@ -80,7 +89,8 @@ export const addSharedDataLink = ({ groupSlug, link }) => { ..._.pick(['name', 'url', 'description'], link), entryType: 'link', resourceType: 'link', - groupSlug, + targetType, + targetSlug, }, }) .then(_.get('addDataEntry.dataEntry')); @@ -131,7 +141,7 @@ export const fetchGroupSharedData = ({ .requestGraphQL(query, { slug, resourceTypes }) .then(_.get('groups.edges[0].node')) .then(group => group || Promise.reject('not_found')) - .then(group => extractGroupDataEntries(group)); + .then(group => extractDataEntries(group)); }; export const addVisualizationConfig = ({ @@ -189,7 +199,7 @@ export const fetchVisualizationConfig = ({ groupSlug, configSlug }) => { const query = graphql(` query fetchVisualizationConfig($groupSlug: String!, $configSlug: String!) { visualizationConfigs( - dataEntry_Groups_Slug: $groupSlug + dataEntry_SharedResources_Target_Slug: $groupSlug slug: $configSlug ) { edges { diff --git a/src/sharedData/sharedDataSlice.js b/src/sharedData/sharedDataSlice.js index 3c18701460..1e58b4fb58 100644 --- a/src/sharedData/sharedDataSlice.js +++ b/src/sharedData/sharedDataSlice.js @@ -124,6 +124,13 @@ const sharedDataSlice = createSlice({ ...state, processing: _.omit(action.payload, state.processing), }), + setList: (state, action) => ({ + ...state, + list: { + data: action.payload, + fetching: false, + }, + }), }, extraReducers: builder => { @@ -278,6 +285,7 @@ const sharedDataSlice = createSlice({ }, }); -export const { resetUploads, resetProcessing } = sharedDataSlice.actions; +export const { resetUploads, resetProcessing, setList } = + sharedDataSlice.actions; export default sharedDataSlice.reducer; diff --git a/src/group/groupUtils.ts b/src/sharedData/sharedDataUtils.js similarity index 61% rename from src/group/groupUtils.ts rename to src/sharedData/sharedDataUtils.js index d533b627a5..0cd316907c 100644 --- a/src/group/groupUtils.ts +++ b/src/sharedData/sharedDataUtils.js @@ -14,18 +14,13 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see https://www.gnu.org/licenses/. */ -import { - DataEntriesFragment, - DataEntryFragment, - DataEntryVisualizationsFragment, -} from 'terrasoApi/shared/graphqlSchema/graphql'; -export const extractDataEntry = ( - dataEntry: DataEntryFragment & DataEntryVisualizationsFragment -) => ({ +export const extractDataEntry = dataEntry => ({ ...dataEntry, - visualizations: dataEntry.visualizations?.edges?.map(edge => edge.node), + visualizations: dataEntry?.visualizations?.edges?.map(edge => edge.node), }); -export const extractGroupDataEntries = (group: DataEntriesFragment) => - group.dataEntries.edges.map(edge => extractDataEntry(edge.node)); +export const extractDataEntries = parent => + parent.sharedResources?.edges + .map(edge => edge.node.source) + .map(dataEntry => extractDataEntry(dataEntry));