-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
task/DES-2685: Add API endpoint and frontend view for project listing (…
…#1167) * Add API endpoint and frontend view for project listing * style/linting fixes * Working form fields for base project metadata * proof of concept populating form with data * fix cases where setting form values would break the input * Add project detail endpoint and confirm compatibility with form * file listings and details in project workdir * curation tree renders * Add dropdown to select entities to add to the tree * Add project header with form modal * Add curation UI for project tree and file associations * add curation and publication preview layouts
- Loading branch information
Showing
72 changed files
with
3,939 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
export * from './types'; | ||
export { useProjectListing } from './useProjectListing'; | ||
export { | ||
useProjectDetail, | ||
useFileAssociations, | ||
useFileTags, | ||
} from './useProjectDetail'; | ||
export { useProjectPreview } from './useProjectPreview'; | ||
export { useProjectEntityReorder } from './useProjectEntityReorder'; | ||
export { useAddEntityToTree } from './useAddEntityToTree'; | ||
export { useRemoveEntityFromTree } from './useRemoveEntityFromTree'; | ||
export { useAddFileAssociation } from './useAddFileAssociation'; | ||
export { useRemoveFileAssociation } from './useRemoveFileAssociation'; | ||
export { useSetFileTags } from './useSetFileTags'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
export type TProjectUser = { | ||
fname: string; | ||
lname: string; | ||
email: string; | ||
inst: string; | ||
role: 'pi' | 'co_pi' | 'team_member' | 'guest'; | ||
username?: string; | ||
}; | ||
|
||
export type TProjectAward = { | ||
name: string; | ||
number: string; | ||
fundingSource: string; | ||
}; | ||
|
||
export type TReferencedWork = { | ||
title: string; | ||
doi: string; | ||
hrefType: 'doi' | 'url'; | ||
}; | ||
|
||
export type TAssociatedProject = { | ||
type: 'Context' | 'Linked Dataset' | 'Cited By'; | ||
title: string; | ||
href: string; | ||
hrefType: 'doi' | 'url'; | ||
}; | ||
|
||
export type TFileTag = { | ||
tagName: string; | ||
path: string; | ||
}; | ||
|
||
export type TFileObj = { | ||
system: string; | ||
name: string; | ||
path: string; | ||
type: 'file' | 'dir'; | ||
length?: number; | ||
lastModified?: string; | ||
}; | ||
|
||
export type THazmapperMap = { | ||
name: string; | ||
uuid: string; | ||
path: string; | ||
deployment: string; | ||
href?: string; | ||
}; | ||
|
||
export type TDropdownValue = { | ||
id: string; | ||
name: string; | ||
}; | ||
|
||
export type TNHEvent = { | ||
eventName: string; | ||
eventStart: string; | ||
eventEnd: string; | ||
location: string; | ||
latitude: string; | ||
longitude: string; | ||
}; | ||
|
||
export type TBaseProjectValue = { | ||
projectId: string; | ||
projectType: | ||
| 'other' | ||
| 'experimental' | ||
| 'simulation' | ||
| 'hybrid_simulation' | ||
| 'field_recon' | ||
| 'field_reconnaissance' | ||
| 'None'; | ||
|
||
title: string; | ||
description: string; | ||
users: TProjectUser[]; | ||
dataTypes?: TDropdownValue[]; | ||
authors: TProjectUser[]; | ||
|
||
awardNumbers: TProjectAward[]; | ||
associatedProjects: TAssociatedProject[]; | ||
referencedData: TReferencedWork[]; | ||
keywords: string[]; | ||
nhEvents: TNHEvent[]; | ||
nhTypes: TDropdownValue[]; | ||
frTypes?: TDropdownValue[]; | ||
facilities: TDropdownValue[]; | ||
|
||
dois: string[]; | ||
fileObjs: TFileObj[]; | ||
fileTags: TFileTag[]; | ||
}; | ||
|
||
type TEntityValue = { | ||
title: string; | ||
description?: string; | ||
authors?: TProjectUser[]; | ||
fileObjs?: TFileObj[]; | ||
fileTags: TFileTag[]; | ||
}; | ||
|
||
export type TProjectMeta = { | ||
uuid: string; | ||
name: string; | ||
created: string; | ||
lastUpdated: string; | ||
}; | ||
|
||
export type TBaseProject = TProjectMeta & { | ||
name: 'designsafe.project'; | ||
value: TBaseProjectValue; | ||
}; | ||
|
||
export type TEntityMeta = TProjectMeta & { | ||
value: TEntityValue; | ||
}; |
22 changes: 22 additions & 0 deletions
22
client/modules/_hooks/src/datafiles/projects/useAddEntityToTree.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import apiClient from '../../apiClient'; | ||
|
||
async function addEntity(projectId: string, nodeId: string, uuid: string) { | ||
const res = await apiClient.post( | ||
`/api/projects/v2/${projectId}/entities/associations/${nodeId}/`, | ||
{ uuid } | ||
); | ||
return res.data; | ||
} | ||
|
||
export function useAddEntityToTree(projectId: string, nodeId: string) { | ||
const queryClient = useQueryClient(); | ||
return useMutation({ | ||
mutationFn: ({ uuid }: { uuid: string }) => | ||
addEntity(projectId, nodeId, uuid), | ||
onSuccess: () => | ||
queryClient.invalidateQueries({ | ||
queryKey: ['datafiles', 'projects', 'detail', projectId], | ||
}), | ||
}); | ||
} |
32 changes: 32 additions & 0 deletions
32
client/modules/_hooks/src/datafiles/projects/useAddFileAssociation.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import apiClient from '../../apiClient'; | ||
import { TFileObj } from './types'; | ||
|
||
async function addFileAssociation( | ||
projectId: string, | ||
entityUuid: string, | ||
fileObjs: TFileObj[] | ||
) { | ||
const res = await apiClient.post( | ||
`/api/projects/v2/${projectId}/entities/${entityUuid}/files/`, | ||
{ fileObjs } | ||
); | ||
return res.data; | ||
} | ||
|
||
export function useAddFileAssociation(projectId: string) { | ||
const queryClient = useQueryClient(); | ||
return useMutation({ | ||
mutationFn: ({ | ||
fileObjs, | ||
entityUuid, | ||
}: { | ||
fileObjs: TFileObj[]; | ||
entityUuid: string; | ||
}) => addFileAssociation(projectId, entityUuid, fileObjs), | ||
onSuccess: () => | ||
queryClient.invalidateQueries({ | ||
queryKey: ['datafiles', 'projects', 'detail', projectId], | ||
}), | ||
}); | ||
} |
73 changes: 73 additions & 0 deletions
73
client/modules/_hooks/src/datafiles/projects/useProjectDetail.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { useQuery } from '@tanstack/react-query'; | ||
import apiClient from '../../apiClient'; | ||
import { TBaseProject, TEntityMeta, TFileTag } from './types'; | ||
import { useMemo } from 'react'; | ||
|
||
type TProjectDetailResponse = { | ||
baseProject: TBaseProject; | ||
entities: TEntityMeta[]; | ||
tree: unknown; | ||
}; | ||
|
||
async function getProjectDetail({ | ||
projectId, | ||
signal, | ||
}: { | ||
projectId: string; | ||
signal: AbortSignal; | ||
}) { | ||
const resp = await apiClient.get<TProjectDetailResponse>( | ||
`/api/projects/v2/${projectId}/`, | ||
{ | ||
signal, | ||
} | ||
); | ||
return resp.data; | ||
} | ||
|
||
export function useProjectDetail(projectId: string) { | ||
return useQuery({ | ||
queryKey: ['datafiles', 'projects', 'detail', projectId], | ||
queryFn: ({ signal }) => getProjectDetail({ projectId, signal }), | ||
enabled: !!projectId, | ||
}); | ||
} | ||
|
||
export function useFileAssociations(projectId: string) { | ||
/*Return a record mapping file paths to an array of entities containing those paths.*/ | ||
const { data } = useProjectDetail(projectId); | ||
|
||
const memoizedFileMapping = useMemo(() => { | ||
const entities = data?.entities ?? []; | ||
const fileMapping: Record<string, TEntityMeta[]> = {}; | ||
entities.forEach((entity) => { | ||
const fileObjs = entity.value.fileObjs ?? []; | ||
fileObjs.forEach((fileObj) => { | ||
const entityList = fileMapping[fileObj.path] ?? []; | ||
entityList.push(entity); | ||
fileMapping[fileObj.path] = entityList; | ||
}); | ||
}); | ||
return fileMapping; | ||
}, [data]); | ||
|
||
return memoizedFileMapping; | ||
} | ||
|
||
export function useFileTags(projectId: string) { | ||
/*Return a record mapping file paths to an array of entities containing those paths.*/ | ||
const { data } = useProjectDetail(projectId); | ||
|
||
const memoizedFileMapping = useMemo(() => { | ||
const entities = data?.entities ?? []; | ||
const tagMapping: Record<string, TFileTag[]> = {}; | ||
entities.forEach((entity) => { | ||
const fileTags = entity.value.fileTags ?? []; | ||
tagMapping[entity.uuid] = fileTags; | ||
}); | ||
|
||
return tagMapping; | ||
}, [data]); | ||
|
||
return memoizedFileMapping; | ||
} |
26 changes: 26 additions & 0 deletions
26
client/modules/_hooks/src/datafiles/projects/useProjectEntityReorder.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import apiClient from '../../apiClient'; | ||
|
||
async function reorderEntitity( | ||
projectId: string, | ||
nodeId: string, | ||
order: number | ||
) { | ||
const res = await apiClient.put( | ||
`/api/projects/v2/${projectId}/entities/ordering/`, | ||
{ nodeId, order } | ||
); | ||
return res.data; | ||
} | ||
|
||
export function useProjectEntityReorder(projectId: string, nodeId: string) { | ||
const queryClient = useQueryClient(); | ||
return useMutation({ | ||
mutationFn: ({ order }: { order: number }) => | ||
reorderEntitity(projectId, nodeId, order), | ||
onSuccess: () => | ||
queryClient.invalidateQueries({ | ||
queryKey: ['datafiles', 'projects', 'detail', projectId], | ||
}), | ||
}); | ||
} |
34 changes: 34 additions & 0 deletions
34
client/modules/_hooks/src/datafiles/projects/useProjectListing.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { useQuery } from '@tanstack/react-query'; | ||
import apiClient from '../../apiClient'; | ||
import { TBaseProject } from './types'; | ||
|
||
export type TProjectListingResponse = { | ||
total: number; | ||
result: TBaseProject[]; | ||
}; | ||
|
||
async function getProjectListing({ | ||
page = 1, | ||
limit = 100, | ||
signal, | ||
}: { | ||
page: number; | ||
limit: number; | ||
signal: AbortSignal; | ||
}) { | ||
const resp = await apiClient.get<TProjectListingResponse>( | ||
'/api/projects/v2', | ||
{ | ||
signal, | ||
params: { offset: (page - 1) * limit, limit }, | ||
} | ||
); | ||
return resp.data; | ||
} | ||
|
||
export function useProjectListing(page: number, limit: number) { | ||
return useQuery({ | ||
queryKey: ['datafiles', 'projects', 'listing', page, limit], | ||
queryFn: ({ signal }) => getProjectListing({ page, limit, signal }), | ||
}); | ||
} |
33 changes: 33 additions & 0 deletions
33
client/modules/_hooks/src/datafiles/projects/useProjectPreview.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { useQuery } from '@tanstack/react-query'; | ||
import apiClient from '../../apiClient'; | ||
import { TBaseProject, TEntityMeta } from './types'; | ||
|
||
type TProjectPreviewResponse = { | ||
baseProject: TBaseProject; | ||
entities: TEntityMeta[]; | ||
tree: unknown; | ||
}; | ||
|
||
async function getProjectPreview({ | ||
projectId, | ||
signal, | ||
}: { | ||
projectId: string; | ||
signal: AbortSignal; | ||
}) { | ||
const resp = await apiClient.get<TProjectPreviewResponse>( | ||
`/api/projects/v2/${projectId}/preview/`, | ||
{ | ||
signal, | ||
} | ||
); | ||
return resp.data; | ||
} | ||
|
||
export function useProjectPreview(projectId: string) { | ||
return useQuery({ | ||
queryKey: ['datafiles', 'projects', 'detail', projectId, 'preview'], | ||
queryFn: ({ signal }) => getProjectPreview({ projectId, signal }), | ||
enabled: !!projectId, | ||
}); | ||
} |
20 changes: 20 additions & 0 deletions
20
client/modules/_hooks/src/datafiles/projects/useRemoveEntityFromTree.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import apiClient from '../../apiClient'; | ||
|
||
async function removeEntity(projectId: string, nodeId: string) { | ||
const res = await apiClient.delete( | ||
`/api/projects/v2/${projectId}/entities/associations/${nodeId}/` | ||
); | ||
return res.data; | ||
} | ||
|
||
export function useRemoveEntityFromTree(projectId: string, nodeId: string) { | ||
const queryClient = useQueryClient(); | ||
return useMutation({ | ||
mutationFn: () => removeEntity(projectId, nodeId), | ||
onSuccess: () => | ||
queryClient.invalidateQueries({ | ||
queryKey: ['datafiles', 'projects', 'detail', projectId], | ||
}), | ||
}); | ||
} |
Oops, something went wrong.