From bd3f1bb3dbcf530f370a9381aae33f0224cfc41e Mon Sep 17 00:00:00 2001 From: Jeremy Myers Date: Thu, 12 Oct 2023 16:01:00 -0400 Subject: [PATCH] Render preliminarily dataset list and dataset details pages --- .../src/lib/Actions/UserDatasetsActions.ts | 119 ++++++++++++++++-- .../lib/Components/List/UserDatasetList.tsx | 31 +++-- .../UserDatasetDetailController.tsx | 4 +- .../Controllers/UserDatasetListController.tsx | 18 --- .../src/lib/Controllers/UserDatasetRouter.tsx | 2 +- .../src/lib/Service/UserDatasetWrappers.ts | 29 ++--- .../libs/user-datasets/src/lib/Service/api.ts | 3 +- .../user-datasets/src/lib/Service/index.ts | 10 ++ .../UserDatasetListStoreModule.ts | 4 +- .../libs/user-datasets/src/lib/Utils/types.ts | 32 ++++- .../src/hooks/diyStudySummaries.tsx | 3 +- 11 files changed, 193 insertions(+), 62 deletions(-) diff --git a/packages/libs/user-datasets/src/lib/Actions/UserDatasetsActions.ts b/packages/libs/user-datasets/src/lib/Actions/UserDatasetsActions.ts index 12bcc808f7..c3ab1a989b 100644 --- a/packages/libs/user-datasets/src/lib/Actions/UserDatasetsActions.ts +++ b/packages/libs/user-datasets/src/lib/Actions/UserDatasetsActions.ts @@ -20,7 +20,7 @@ import { } from '../Service/UserDatasetWrappers'; import { FILTER_BY_PROJECT_PREF } from '../Utils/project-filter'; -import { UserDataset, UserDatasetMeta } from '../Utils/types'; +import { UserDataset, UserDatasetMeta, UserDatasetVDI } from '../Utils/types'; export type Action = | DetailErrorAction @@ -107,11 +107,11 @@ export const DETAIL_LOADING = 'user-datasets/detail-loading'; export type DetailLoadingAction = { type: typeof DETAIL_LOADING; payload: { - id: number; + id: string; }; }; -export function detailLoading(id: number): DetailLoadingAction { +export function detailLoading(id: string): DetailLoadingAction { return { type: DETAIL_LOADING, payload: { @@ -127,13 +127,13 @@ export const DETAIL_RECEIVED = 'user-datasets/detail-received'; export type DetailReceivedAction = { type: typeof DETAIL_RECEIVED; payload: { - id: number; + id: string; userDataset?: UserDataset; }; }; export function detailReceived( - id: number, + id: string, userDataset?: UserDataset ): DetailReceivedAction { return { @@ -392,6 +392,7 @@ type SharingAction = | SharingSuccessAction | SharingErrorAction; +// replace w/ VDI service export function loadUserDatasetList() { return validateUserDatasetCompatibleThunk(({ wdkService }) => [ listLoading(), @@ -402,20 +403,68 @@ export function loadUserDatasetList() { // ignore error and default to false () => false ), + // @ts-ignore wdkService.getCurrentUserDatasets(), - ]).then( - ([filterByProject, userDatasets]) => - listReceived(userDatasets, filterByProject), - listErrorReceived - ), + ]).then(([filterByProject, userDatasets]) => { + // console.log({filterByProject, userDatasets}) + const vdiToExistingUds = userDatasets.map( + (ud: UserDatasetVDI): UserDataset => { + const { + name, + description, + summary, + owner, + datasetType, + projectIDs, + datasetID, + } = ud; + return { + owner: owner.firstName + ' ' + owner.lastName, + projects: projectIDs, + created: ud.created, + type: { + display: datasetType.displayName ?? datasetType.name, + name: datasetType.name, + version: datasetType.version, + }, + meta: { + name, + description: description ?? name, + summary: summary ?? '', + }, + ownerUserId: owner.userID, + dependencies: [], + age: 0, + size: ud.fileSizeTotal, + id: datasetID, + isCompatible: false, + isInstalled: false, + sharedWith: [], + questions: [], + uploaded: 1, + modified: 1, + percentQuotaUsed: 0, + datafiles: [], + }; + } + ); + // return listReceived(userDatasets, filterByProject) + return listReceived(vdiToExistingUds, filterByProject); + }, listErrorReceived), ]); } -export function loadUserDatasetDetail(id: number) { +export function loadUserDatasetDetail(id: string) { return validateUserDatasetCompatibleThunk(({ wdkService }) => [ detailLoading(id), + // @ts-ignore wdkService.getUserDataset(id).then( - (userDataset) => detailReceived(id, userDataset), + // @ts-ignore + (userDataset) => { + const trasnformedResposne = + transformVdiResponseToLegacyResponse(userDataset); + return detailReceived(id, trasnformedResposne); + }, (error: ServiceError) => error.status === 404 ? detailReceived(id) : detailError(error) ), @@ -493,3 +542,49 @@ export function updateProjectFilter(filterByProject: boolean) { projectFilter(filterByProject), ]); } + +// @ts-ignore +function transformVdiResponseToLegacyResponse(ud) { + // (ud: UserDatasetVDI): UserDataset => { + const { + name, + description, + summary, + owner, + datasetType, + projectIDs, + datasetID, + files, + } = ud; + return { + owner: owner.firstName + ' ' + owner.lastName, + projects: projectIDs ?? [], + created: ud.created, + type: { + display: datasetType.displayName ?? datasetType.name, + name: datasetType.name, + version: datasetType.version, + }, + meta: { + name, + description: description ?? name, + summary: summary ?? '', + }, + ownerUserId: owner.userID, + dependencies: [], + age: 0, + // @ts-ignore + size: ud.fileSizeTotal ?? files.reduce((prev, curr) => prev + curr.size, 0), + id: datasetID, + isCompatible: false, + isInstalled: false, + sharedWith: [], + questions: [], + uploaded: 1, + modified: 1, + percentQuotaUsed: 0, + datafiles: files, + }; + // } + // ) +} diff --git a/packages/libs/user-datasets/src/lib/Components/List/UserDatasetList.tsx b/packages/libs/user-datasets/src/lib/Components/List/UserDatasetList.tsx index bdd8e62f3f..1f0b247ec7 100644 --- a/packages/libs/user-datasets/src/lib/Components/List/UserDatasetList.tsx +++ b/packages/libs/user-datasets/src/lib/Components/List/UserDatasetList.tsx @@ -67,7 +67,7 @@ interface Props { } interface State { - selectedRows: number[]; + selectedRows: Array; uiState: { sort: MesaSortObject }; searchTerm: string; sharingModalOpen: boolean; @@ -122,7 +122,7 @@ class UserDatasetList extends React.Component { } isRowSelected(row: UserDataset): boolean { - const id: number = row.id; + const id: number | string = row.id; const { selectedRows } = this.state; return selectedRows.includes(id); } @@ -137,7 +137,15 @@ class UserDatasetList extends React.Component { } onMetaAttributeSaveFactory(dataset: UserDataset, attrKey: string) { - const { meta } = dataset; + // const { meta } = dataset; + const meta = { + // @ts-ignore + description: dataset.description ?? 'none', + // @ts-ignore + name: dataset.name ?? 'none', + // @ts-ignore + summary: dataset.summary ?? 'none', + }; const { updateUserDatasetDetail } = this.props; return (value: string) => updateUserDatasetDetail(dataset, { ...meta, [attrKey]: value }); @@ -304,18 +312,18 @@ class UserDatasetList extends React.Component { } onRowSelect(row: UserDataset): void { - const id: number = row.id; + const id: number | string = row.id; const { selectedRows } = this.state; if (selectedRows.includes(id)) return; - const newSelection: number[] = [...selectedRows, id]; + const newSelection: Array = [...selectedRows, id]; this.setState({ selectedRows: newSelection }); } onRowDeselect(row: UserDataset): void { - const id: number = row.id; + const id: number | string = row.id; const { selectedRows } = this.state; if (!selectedRows.includes(id)) return; - const newSelection: number[] = selectedRows.filter( + const newSelection: Array = selectedRows.filter( (selectedId) => selectedId !== id ); this.setState({ selectedRows: newSelection }); @@ -328,14 +336,19 @@ class UserDatasetList extends React.Component { .filter((dataset: UserDataset) => !selectedRows.includes(dataset.id)) .map((dataset: UserDataset) => dataset.id); if (!unselectedRows.length) return; - const newSelection: number[] = [...selectedRows, ...unselectedRows]; + const newSelection: Array = [ + ...selectedRows, + ...unselectedRows, + ]; this.setState({ selectedRows: newSelection }); } onMultipleRowDeselect(rows: UserDataset[]): void { if (!rows.length) return; const { selectedRows } = this.state; - const deselectedIds: number[] = rows.map((row: UserDataset) => row.id); + const deselectedIds: Array = rows.map( + (row: UserDataset) => row.id + ); const newSelection = selectedRows.filter( (id) => !deselectedIds.includes(id) ); diff --git a/packages/libs/user-datasets/src/lib/Controllers/UserDatasetDetailController.tsx b/packages/libs/user-datasets/src/lib/Controllers/UserDatasetDetailController.tsx index 7de6c2625d..714a6fccea 100644 --- a/packages/libs/user-datasets/src/lib/Controllers/UserDatasetDetailController.tsx +++ b/packages/libs/user-datasets/src/lib/Controllers/UserDatasetDetailController.tsx @@ -88,9 +88,7 @@ class UserDatasetDetailController extends PageController { const idChanged = prevProps == null || prevProps.ownProps.id !== this.props.ownProps.id; if (idChanged) { - this.props.dispatchProps.loadUserDatasetDetail( - Number(this.props.ownProps.id) - ); + this.props.dispatchProps.loadUserDatasetDetail(this.props.ownProps.id); } } diff --git a/packages/libs/user-datasets/src/lib/Controllers/UserDatasetListController.tsx b/packages/libs/user-datasets/src/lib/Controllers/UserDatasetListController.tsx index 76c8623249..0183625d99 100644 --- a/packages/libs/user-datasets/src/lib/Controllers/UserDatasetListController.tsx +++ b/packages/libs/user-datasets/src/lib/Controllers/UserDatasetListController.tsx @@ -24,10 +24,6 @@ import { DataNoun, UserDataset } from '../Utils/types'; import '../Components/UserDatasets.scss'; -import { useConfiguredVdiClient } from '../Hooks/user-datasets'; -// const VDI_SERVICE_BASE_URL = 'https://vdi-dev.local.apidb.org:8443' -const VDI_SERVICE_BASE_URL = 'http://localhost:8080'; - const ActionCreators = { showLoginForm, loadUserDatasetList, @@ -179,7 +175,6 @@ class UserDatasetListController extends PageController { ) : ( )} - ); @@ -200,17 +195,4 @@ const enhance = connect( }) ); -type VDIProps = { - baseUrl: string; -}; - -function VDI({ baseUrl }: VDIProps) { - const vdi = useConfiguredVdiClient(baseUrl); - // console.log(vdi); - const uds = vdi.getCurrentUserDatasets(); - // const uds = vdi.getCommunityDatasets(); - console.log(uds); - return <>Working?; -} - export default withRouter(enhance(UserDatasetListController)); diff --git a/packages/libs/user-datasets/src/lib/Controllers/UserDatasetRouter.tsx b/packages/libs/user-datasets/src/lib/Controllers/UserDatasetRouter.tsx index 404ef0be74..ef77b776e1 100644 --- a/packages/libs/user-datasets/src/lib/Controllers/UserDatasetRouter.tsx +++ b/packages/libs/user-datasets/src/lib/Controllers/UserDatasetRouter.tsx @@ -47,7 +47,7 @@ export function UserDatasetRouter({ return ( ) => { return ( diff --git a/packages/libs/user-datasets/src/lib/Service/UserDatasetWrappers.ts b/packages/libs/user-datasets/src/lib/Service/UserDatasetWrappers.ts index a6dac89924..e780d2efe6 100644 --- a/packages/libs/user-datasets/src/lib/Service/UserDatasetWrappers.ts +++ b/packages/libs/user-datasets/src/lib/Service/UserDatasetWrappers.ts @@ -30,24 +30,24 @@ const userIdsByEmailDecoder = record({ }); export const userDatasetsServiceWrappers = { - getCurrentUserDatasets: (wdkService: WdkService) => () => - wdkService._fetchJson( - 'get', - '/users/current/user-datasets?expandDetails=true' - ), - getUserDataset: (wdkService: WdkService) => (id: number) => - wdkService._fetchJson( - 'get', - `/users/current/user-datasets/${id}` - ), + // getCurrentUserDatasets: (wdkService: WdkService) => () => + // wdkService._fetchJson( + // 'get', + // '/users/current/user-datasets?expandDetails=true' + // ), + // getUserDataset: (wdkService: WdkService) => (id: number) => + // wdkService._fetchJson( + // 'get', + // `/users/current/user-datasets/${id}` + // ), updateUserDataset: - (wdkService: WdkService) => (id: number, meta: UserDatasetMeta) => + (wdkService: WdkService) => (id: number | string, meta: UserDatasetMeta) => wdkService._fetchJson( 'put', `/users/current/user-datasets/${id}/meta`, JSON.stringify(meta) ), - removeUserDataset: (wdkService: WdkService) => (id: number) => + removeUserDataset: (wdkService: WdkService) => (id: number | string) => wdkService._fetchJson('delete', `/users/current/user-datasets/${id}`), editUserDatasetSharing: (wdkService: WdkService) => @@ -79,8 +79,9 @@ export const userDatasetsServiceWrappers = { ); }, getUserDatasetDownloadUrl: - (wdkService: WdkService) => (datasetId: number, filename: string) => { - if (typeof datasetId !== 'number') + (wdkService: WdkService) => + (datasetId: number | string, filename: string) => { + if (typeof datasetId !== 'number' && typeof datasetId !== 'string') throw new TypeError( `Can't build downloadUrl; invalid datasetId given (${datasetId}) [${typeof datasetId}]` ); diff --git a/packages/libs/user-datasets/src/lib/Service/api.ts b/packages/libs/user-datasets/src/lib/Service/api.ts index 4f7b01e1fd..03076c80ae 100644 --- a/packages/libs/user-datasets/src/lib/Service/api.ts +++ b/packages/libs/user-datasets/src/lib/Service/api.ts @@ -13,6 +13,7 @@ import { UserDatasetMeta, NewUserDatasetRequest, NewUserDataset, + userDatasetDetail, } from '../Utils/types'; import { array, type, TypeOf, string } from 'io-ts'; @@ -95,7 +96,7 @@ export class UserDatasetApi extends FetchClientWithCredentials { createJsonRequest({ path: `${VDI_SERVICE}/${id}`, method: 'GET', - transformResponse: ioTransformer(userDataset), + transformResponse: ioTransformer(userDatasetDetail), }) ); }; diff --git a/packages/libs/user-datasets/src/lib/Service/index.ts b/packages/libs/user-datasets/src/lib/Service/index.ts index bad80d5edc..5df2b59bbb 100644 --- a/packages/libs/user-datasets/src/lib/Service/index.ts +++ b/packages/libs/user-datasets/src/lib/Service/index.ts @@ -8,10 +8,19 @@ import { makeUserDatasetUploadServiceWrappers, } from './UserDatasetUploadWrappers'; +import { UserDatasetApi } from './api'; + +const VDI_SERVICE_BASE_URL = 'http://localhost:8080'; + export function wrapWdkService( serviceConfig: UserDatasetUploadServiceConfig | undefined, wdkService: WdkService ) { + const vdiService = new UserDatasetApi( + { baseUrl: VDI_SERVICE_BASE_URL }, + wdkService + ); + const wrappersToInclude = serviceConfig == null ? userDatasetsServiceWrappers @@ -22,6 +31,7 @@ export function wrapWdkService( return { ...wdkService, + ...vdiService, ...mapValues(wrappersToInclude, (wdkServiceWrapper) => wdkServiceWrapper(wdkService) ), diff --git a/packages/libs/user-datasets/src/lib/StoreModules/UserDatasetListStoreModule.ts b/packages/libs/user-datasets/src/lib/StoreModules/UserDatasetListStoreModule.ts index 850b746194..f8c7bf6a0f 100644 --- a/packages/libs/user-datasets/src/lib/StoreModules/UserDatasetListStoreModule.ts +++ b/packages/libs/user-datasets/src/lib/StoreModules/UserDatasetListStoreModule.ts @@ -37,7 +37,7 @@ type ForbiddenState = { type CompleteState = { status: 'complete'; - userDatasets: number[]; + userDatasets: Array; userDatasetsById: Record; filterByProject: boolean; }; @@ -84,6 +84,7 @@ export function reduce(state: State = initialState, action: Action): State { }; case DETAIL_UPDATE_SUCCESS: + // @ts-ignore return state.status === 'complete' ? { ...state, @@ -98,6 +99,7 @@ export function reduce(state: State = initialState, action: Action): State { : state; case DETAIL_REMOVE_SUCCESS: + // @ts-ignore return state.status === 'complete' ? { ...state, diff --git a/packages/libs/user-datasets/src/lib/Utils/types.ts b/packages/libs/user-datasets/src/lib/Utils/types.ts index c690b3d2be..132bc4dfc5 100644 --- a/packages/libs/user-datasets/src/lib/Utils/types.ts +++ b/packages/libs/user-datasets/src/lib/Utils/types.ts @@ -30,7 +30,7 @@ export interface UserDatasetShare { } export interface UserDataset { - created: number; + created: number | string; age: number; isInstalled: boolean; isCompatible: boolean; @@ -44,7 +44,7 @@ export interface UserDataset { size: number; }>; projects: string[]; - id: number; + id: number | string; meta: UserDatasetMeta; modified: number; owner: string; @@ -215,6 +215,7 @@ const importStatus = keyof({ complete: null, invalid: null, failed: null, + queued: null, }); const statusDetails = intersection([ @@ -247,6 +248,33 @@ export const userDataset = intersection([ origin: string, projectIDs: array(string), status: statusDetails, + fileCount: number, + fileSizeTotal: number, + created: string, + }), + partial({ + summary: string, + description: string, + sourceUrl: string, + shares: array(shareDetails), + importMessages: array(string), + }), +]); + +export const userDatasetDetail = intersection([ + type({ + datasetID: string, + owner: ownerDetails, + datasetType: datasetTypeDetails, + visibility: visibilityOptions, + name: string, + origin: string, + // projectIDs: array(string), + status: statusDetails, + // fileCount: number, + // fileSizeTotal: number, + created: string, + files: array(type({ name: string, size: number })), }), partial({ summary: string, diff --git a/packages/libs/web-common/src/hooks/diyStudySummaries.tsx b/packages/libs/web-common/src/hooks/diyStudySummaries.tsx index a15277eb83..1a912514cf 100644 --- a/packages/libs/web-common/src/hooks/diyStudySummaries.tsx +++ b/packages/libs/web-common/src/hooks/diyStudySummaries.tsx @@ -78,7 +78,7 @@ export function useDiyStudySummaryRows(): UserStudySummaryRow[] | undefined { if (currentUser.isGuest) { return []; } - + // @ts-ignore return wdkService.getCurrentUserDatasets(); }, [currentUser] @@ -116,6 +116,7 @@ export function useDiyStudySummaryRows(): UserStudySummaryRow[] | undefined { : userDataset.owner, sharedWith: userDataset.sharedWith + // @ts-ignore ?.map(({ userDisplayName }) => userDisplayName) ?.join(', ') ?? '', },