From 888437c3dd3362df04a65965e75e8d1bd9c86278 Mon Sep 17 00:00:00 2001 From: Timm Fitschen <t.fitschen@indiscale.com> Date: Fri, 18 Oct 2024 22:08:25 +0200 Subject: [PATCH] ENH: Add handling of EVEBS-FDO type --- .gitignore | 1 + Dockerfile | 3 + next-env.d.ts | 5 - next.config.js | 6 + package-lock.json | 13 ++ package.json | 1 + pages/fdo/show/[prefix]/[suffix].tsx | 263 ++++++++++++++++++++------- src/components/fdos/details.tsx | 36 ++-- src/constants.js | 4 + src/providers/dataProvider.tsx | 11 +- 10 files changed, 240 insertions(+), 103 deletions(-) delete mode 100644 next-env.d.ts diff --git a/.gitignore b/.gitignore index 5b26e50..12063c9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules # next.js build files .next +next-env.d.ts # environment variables .env .env.* diff --git a/Dockerfile b/Dockerfile index 7f7a9d6..7c511c8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,12 @@ FROM refinedev/node:18 AS base +RUN npm install -g --update npm + FROM base AS deps RUN apk add --no-cache libc6-compat + COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./ RUN \ diff --git a/next-env.d.ts b/next-env.d.ts deleted file mode 100644 index a4a7b3f..0000000 --- a/next-env.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -/// <reference types="next" /> -/// <reference types="next/image-types/global" /> - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. diff --git a/next.config.js b/next.config.js index e7e879c..9a289c5 100644 --- a/next.config.js +++ b/next.config.js @@ -4,4 +4,10 @@ module.exports = { i18n, transpilePackages: ["@refinedev/nextjs-router"], output: "standalone", + eslint: { + ignoreDuringBuilds: true, + }, + typescript: { + ignoreBuildErrors: true, + }, }; diff --git a/package-lock.json b/package-lock.json index 776ada3..00b8d68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "nookies": "^2.5.2", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-json-view-lite": "^1.5.0", "styled-components": "^6.1.11", "unstorage": "^1.10.1" }, @@ -10343,6 +10344,18 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "node_modules/react-json-view-lite": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-1.5.0.tgz", + "integrity": "sha512-nWqA1E4jKPklL2jvHWs6s+7Na0qNgw9HCP6xehdQJeg6nPBTFZgGwyko9Q0oj+jQWKTTVRS30u0toM5wiuL3iw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-markdown": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-6.0.3.tgz", diff --git a/package.json b/package.json index edeb12c..3c4c6a3 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "nookies": "^2.5.2", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-json-view-lite": "^1.5.0", "styled-components": "^6.1.11", "unstorage": "^1.10.1" }, diff --git a/pages/fdo/show/[prefix]/[suffix].tsx b/pages/fdo/show/[prefix]/[suffix].tsx index 8412158..ce5ee79 100644 --- a/pages/fdo/show/[prefix]/[suffix].tsx +++ b/pages/fdo/show/[prefix]/[suffix].tsx @@ -3,10 +3,13 @@ import React from 'react' import { ErrorComponent } from '../../../../src/components/ErrorComponent' import { GetServerSideProps } from 'next' import { serverSideTranslations } from 'next-i18next/serverSideTranslations' -import { useShow, useTranslate, useParsed, useCustom, useApiUrl } from '@refinedev/core' +import { useTranslate, useParsed, useCustom, useApiUrl } from '@refinedev/core' import { Show } from '@refinedev/mui' import { Typography } from '@mui/material' import CircularProgress from '@mui/material/CircularProgress' +import AssignmentIcon from '@mui/icons-material/Assignment' +import Avatar from '@mui/material/Avatar' +import { blue } from '@mui/material/colors' import Box from '@mui/material/Box' import Stack from '@mui/material/Stack' import Chip from '@mui/material/Chip' @@ -23,8 +26,115 @@ import ContentPaste from '@mui/icons-material/ContentPaste' import Cloud from '@mui/icons-material/Cloud' import VerifiedIcon from '@mui/icons-material/Verified' import ReportIcon from '@mui/icons-material/Report' +import { JsonView, darkStyles, defaultStyles } from 'react-json-view-lite'; +import { styled, ThemeProvider } from '@mui/material/styles' +import Details from '../../../../src/components/fdos/details' +import IFdo from '../../../../src/interfaces/IFdo' +import { FDO_COMMUNITY_TYPE_EVEBS as EVEBS, FDO_COMMUNITY_MD_PROFILE_EDC as EDC, FDO_COMMUNITY_MD_PROFILE_AAS as AAS, HANDLE_SYSTEM_BASE_URI as HS_BASE_URI } from '../../../../src/constants' +import 'react-json-view-lite/dist/index.css'; -const resolvePid = (pid: string) => `https://hdl.handle.net/${pid}` +const resolvePid = (pid: string) => `${HS_BASE_URI}/${pid}` + +const getFdoDetails = (data: object) => { + console.log(data) + if(!data) return undefined + + const fdoDetails = { + isFdo: data["isFdo"], + typePid: data["fdoType"], + profilePid: data["fdoProfile"], + dataPid: data["dataPid"], + metadataPid: data["metadataPid"], + repository: data.attributes["0.TYPE/DOIPService"], + attributes: data["attributes"], + } + + return fdoDetails +} + +interface IJsonMetadata { + metadata: object +} + +interface IEvebsDetails { + metadataJson: IJsonMetadata + dataspace: string + dataspaceIcon: string + technology: string + technologyIcon: string +} + +const getEvebsDetails = (typePid, repository, metadataRecord) => { + console.log(metadataRecord); + const row = (category: string, classification: string, logo: string) => { + return { category, classification, logo } + } + const techInfo = metadataRecord.fdoProfile === AAS ? "BaSyx AAS" : "EDC"; + const techLogo = metadataRecord.fdoProfile === AAS ? "/images/aas.png" : "/images/eclipse-logo.png"; + const dataspaceInfo = metadataRecord.fdoProfile === AAS ? "RWTH" : "MDS"; + const dataspaceLogo = metadataRecord.fdoProfile === AAS ? "/images/rwth.png" : "/images/mds.png"; + + return [ + row('Type', <Link href={resolvePid(typePid)}>{ "EVEBS-FDO" }</Link>, ''), + row('Repository', <Link href="#">{repository}</Link>, + repository.toLowerCase().indexOf("cordra") > -1 ? "/images/cordra-primary-blue.png" : "/images/la_logo.png"), + + row('Dataspace', dataspaceInfo, dataspaceLogo), + row('Technology', techInfo, techLogo), + ] +} + +const EvebsDetails = ({typePid, repository, metadataPid}) => { + const apiUrl = useApiUrl() + const t = useTranslate() + const { data, isLoading, isError, error } = useCustom({ + url: `${HS_BASE_URI}/${metadataPid}?locatt=payloadIndex:0`, + method: 'get', + errorNotification: () => false, + queryOptions: { + retry: false + } + }) + const metadataRecord = useCustom({ + url: `${apiUrl}/fdo/${metadataPid}`, + method: 'get', + errorNotification: () => false, + queryOptions: { + retry: false + } + }); + + const metadata = data?.data; + + console.log(isLoading, data, repository, typePid, metadata); + return isLoading || metadataRecord.isLoading ? <Item>loading json</Item> : ( + <> + <Item sx={{ width: '50%' }} > + <Typography variant="h5" gutterBottom> {metadata?.displayName || metadata.idShort || metadata.id} </Typography> <Typography variant="subtitle1" gutterBottom > {metadata?.description[0].text} </Typography> + <Box> + <Details rows={getEvebsDetails(typePid, repository, metadataRecord.data.data)}></Details> + </Box> + </Item> + <Item> + <Box> + <Typography variant="h6" gutterBottom>Metadata (JSON)</Typography> + <JsonView data={metadata} shouldExpandNode={lvl => lvl<3} style={defaultStyles} /> + </Box> + </Item> + </> + ) +} + +const Item = styled(Paper)(({ theme }) => ({ + backgroundColor: '#fff', + ...theme.typography.body2, + padding: theme.spacing(1), + textAlign: 'left', + color: theme.palette.text.secondary, + ...theme.applyStyles('dark', { + backgroundColor: '#1A2027' + }) +})) const ShowFDO = () => { const { params } = useParsed() @@ -47,83 +157,96 @@ const ShowFDO = () => { const handleUrl = resolvePid(showId) const dataPid = data?.data?.dataPid const metadataPid = data?.data?.metadataPid - const profilePid = '21.T11969/141bf451b18a79d0fe66' + + const fdoDetails = getFdoDetails(data?.data); + const isEvebs = fdoDetails?.typePid === EVEBS return ( <Show isLoading={isLoading} - title={<Typography variant="h5">{ showId }{ !isLoading && (data?.data?.isFdo ? <Chip label="FDO" color="success" variant="outlined" /> : <Chip label="Not an FDO" color="error" variant="outlined" />)}</Typography>} + title={<Typography variant="h5">{ showId } + + { !isLoading && (data?.data?.isFdo ? <Chip label="FDO" color="success" variant="outlined" sx={{marginLeft: 1}}/> : <Chip label="Not an FDO" color="error" variant="outlined" sx={{marginLeft: 1}}/>)} + </Typography>} > { isLoading && <Box sx={{ textAlign: 'center' }}><CircularProgress/></Box>} - <Paper sx={{ width: 320, maxWidth: '100%' }}> - <MenuList> - <MenuItem> - <ListItemIcon> - <RadioButtonUncheckedIcon/> - </ListItemIcon> - <ListItemText> - <Link href={`${handleUrl}?noredirect`}>Handle Record</Link> - </ListItemText> - </MenuItem> - <MenuItem> - <ListItemIcon> - <StorageIcon/> - </ListItemIcon> - <ListItemText> - <Link href={handleUrl}>To Repository</Link> - </ListItemText> - </MenuItem> - { data?.data?.isFdo && (<> - <Divider /> - <MenuItem> - <ListItemIcon> - { dataPid - ? <VerifiedIcon color="success"/> - : <ReportIcon color="error"/> - } - </ListItemIcon> - <ListItemText> - { metadataPid - ? <Link href={resolvePid(dataPid)}>Data</Link> - : 'Data not available.' - } - </ListItemText> - </MenuItem> - <MenuItem> - <ListItemIcon> - { metadataPid - ? <VerifiedIcon color="success"/> - : <ReportIcon color="error"/> - } - </ListItemIcon> - <ListItemText> - { metadataPid - ? <Link href={resolvePid(metadataPid)}>Metadata</Link> - : 'Metadata not available.' - } - </ListItemText> - </MenuItem> - <MenuItem> - <ListItemIcon> - { profilePid - ? <VerifiedIcon color="success"/> - : <ReportIcon color="error"/> - } - </ListItemIcon> - <ListItemText> - { profilePid - ? <Link href={resolvePid(profilePid)}>Profile</Link> - : 'Profile not available.' - } - </ListItemText> - </MenuItem> - </>)} - </MenuList> - </Paper> + <div> + <Stack + direction="row" + // divider={<Divider orientation="vertical" flexItem />} + spacing={2} + > + <Item> + <MenuList> + <MenuItem> + <ListItemIcon> + <RadioButtonUncheckedIcon/> + </ListItemIcon> + <ListItemText> + <Link href={`${handleUrl}?noredirect`}>Handle Record</Link> + </ListItemText> + </MenuItem> + <MenuItem> + <ListItemIcon> + <StorageIcon/> + </ListItemIcon> + <ListItemText> + <Link href={handleUrl}>To Repository</Link> + </ListItemText> + </MenuItem> + { data?.data?.isFdo && (<> + <Divider /> + <MenuItem> + <ListItemIcon> + { dataPid + ? <VerifiedIcon color="success"/> + : <ReportIcon color="error"/> + } + </ListItemIcon> + <ListItemText> + { metadataPid + ? <Link href={resolvePid(dataPid)}>Data</Link> + : 'Data not available.' + } + </ListItemText> + </MenuItem> + <MenuItem> + <ListItemIcon> + { metadataPid + ? <VerifiedIcon color="success"/> + : <ReportIcon color="error"/> + } + </ListItemIcon> + <ListItemText> + { metadataPid + ? <Link href={resolvePid(metadataPid)}>Metadata</Link> + : 'Metadata not available.' + } + </ListItemText> + </MenuItem> + <MenuItem> + <ListItemIcon> + { fdoDetails.profilePid + ? <VerifiedIcon color="success"/> + : <ReportIcon color="error"/> + } + </ListItemIcon> + <ListItemText> + { fdoDetails.profilePid + ? <Link href={resolvePid(fdoDetails.profilePid)}>Profile</Link> + : 'Profile not available.' + } + </ListItemText> + </MenuItem> + </>)} + </MenuList> + </Item> + { isEvebs && <EvebsDetails {...fdoDetails}/> } + </Stack> + </div><br/><br/> </Show> - ) } diff --git a/src/components/fdos/details.tsx b/src/components/fdos/details.tsx index 04a91d9..29a44b9 100644 --- a/src/components/fdos/details.tsx +++ b/src/components/fdos/details.tsx @@ -8,6 +8,7 @@ import TableHead from '@mui/material/TableHead' import TableRow from '@mui/material/TableRow' import Paper from '@mui/material/Paper' import Typography from '@mui/material/Typography' +import Link from '@mui/material/Link' const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { @@ -15,7 +16,7 @@ const StyledTableCell = styled(TableCell)(({ theme }) => ({ color: theme.palette.common.white }, [`&.${tableCellClasses.body}`]: { - fontSize: 16, + fontSize: 14, backgroundColor: theme.palette.common.white, ...theme.applyStyles('dark', { backgroundColor: '#262c32' @@ -31,11 +32,6 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({ } })) -const typeInfo = 'CETTS' -const repoInfo = 'LinkAhead' -const dataSpInfo = 'RWTH' -const techInfo = 'EDC' - function createData ( category: string, classification: string, @@ -45,36 +41,26 @@ function createData ( return { category, classification, logo } } -const rows = [ - createData('Type:', typeInfo, ''), - createData('Repository:', repoInfo, ''), - createData('Dataspace:', dataSpInfo, ''), - createData('Technology:', techInfo, '') -] -export default function CustomizedTables () { +export default function CustomizedTables ({rows}) { return ( - <TableContainer component={Paper}> - <Table aria-label="simple table"> - <TableHead> - {/* <TableRow> - <StyledTableCell>Info1 </StyledTableCell> - <StyledTableCell align="right">Info2</StyledTableCell> - <StyledTableCell align="right">Info3</StyledTableCell> - </TableRow> */} - </TableHead> + <Table aria-label="simple table" sx={{border: 0}}> <TableBody > {rows.map((row) => ( <StyledTableRow key={row.category}> <StyledTableCell component="th" scope="row" sx={{ border: 0 }}> - <Typography variant="h6" gutterBottom> {row.category}</Typography> + <Typography sx={{fontSize: 14}} gutterBottom> {row.category}</Typography> </StyledTableCell> <StyledTableCell align="left">{row.classification}</StyledTableCell> - <StyledTableCell align="left" sx={{ border: 0 }}>{row.logo}</StyledTableCell> + <StyledTableCell align="right" sx={{ maxWidth: 140 }}>{row.logo && <img + style={{ maxHeight: '35px' }} + src={row.logo} + title={row.category} + /> + }</StyledTableCell> </StyledTableRow> ))} </TableBody> </Table> - </TableContainer> ) } diff --git a/src/constants.js b/src/constants.js index c891c2a..cee9f3c 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,3 +1,7 @@ import { version } from './version' export const API_URL = process.env.NEXT_PUBLIC_API_URL || '/api' export const FDO_MANAGER_WEBUI_VERSION = version +export const FDO_COMMUNITY_TYPE_EVEBS = process.env.NEXT_PUBLIC_FDO_COMMUNITY_TYPE_EVEBS || "21.T11966/f7f29218c8d5832ab5b5" +export const FDO_COMMUNITY_MD_PROFILE_AAS = process.env.NEXT_PUBLIC_FDO_COMMUNITY_MD_PROFILE_AAS || "21.T11966/49321f913c960ec3c943" +export const FDO_COMMUNITY_MD_PROFILE_EDC = process.env.NEXT_PUBLIC_FDO_COMMUNITY_MD_PROFILE_EDC || "21.T11966/3f1cfd3bb60bee84c22b" +export const HANDLE_SYSTEM_BASE_URI = process.env.NEXT_PUBLIC_HANDLE_SYSTEM_BASE_URI || "https://hdl.handle.net" diff --git a/src/providers/dataProvider.tsx b/src/providers/dataProvider.tsx index ad9336c..10d87ca 100644 --- a/src/providers/dataProvider.tsx +++ b/src/providers/dataProvider.tsx @@ -4,7 +4,12 @@ import { Configuration, ProfilesApi, RepositoriesApi, FDOsApi, InfoApi, LoggingA import axios from 'axios' const getNewlyCreated = async (newLocation: string) => { - return await axios.get(newLocation) + const response = await axios.get(newLocation) + console.log(response); + if (response.data.data) { + return response.data.data; + } + return response.data; } const apiDataProvider = (apiUrl: string): DataProvider => { @@ -66,7 +71,7 @@ const apiDataProvider = (apiUrl: string): DataProvider => { meta }) => { if (method === 'get') { - return { data: (await getNewlyCreated(url)).data.data } + return { data: (await getNewlyCreated(url)) } } else { throw new Error('Not implemented') } @@ -81,7 +86,7 @@ const apiDataProvider = (apiUrl: string): DataProvider => { if (response.status === 201) { const newLocation = response.headers.location const newData = await getNewlyCreated(newLocation) - return { data: newData.data.data } + return { data: newData } } else { throw new Error('Create with anything else than 201 not implemented.') } -- GitLab