Skip to content

Commit

Permalink
Merge pull request #125 from databio/add-metadata
Browse files Browse the repository at this point in the history
Metadata tweaks
  • Loading branch information
nleroy917 authored Jun 10, 2024
2 parents d8b2fd0 + c16543b commit c869467
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 59 deletions.
11 changes: 11 additions & 0 deletions ui/bedbase-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,8 @@ export interface components {
universe_metadata?: components["schemas"]["UniverseMetadata"] | null;
/** Raw Metadata */
raw_metadata?: components["schemas"]["BedPEPHub"] | components["schemas"]["BedPEPHubRestrict"] | null;
/** Bedsets */
bedsets?: components["schemas"]["BedSetMinimal"][] | null;
};
/** BedMetadataBasic */
BedMetadataBasic: {
Expand Down Expand Up @@ -595,6 +597,15 @@ export interface components {
/** Bed Ids */
bed_ids?: string[];
};
/** BedSetMinimal */
BedSetMinimal: {
/** Id */
id: string;
/** Name */
name?: string | null;
/** Description */
description?: string | null;
};
/** BedSetPlots */
BedSetPlots: {
region_commonality?: components["schemas"]["FileModel"];
Expand Down
2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"generate-types": "npx openapi-typescript http://127.0.0.1:8000/openapi.json -o bedbase-types.d.ts"
"generate-types": "npx openapi-typescript https://api-dev.bedbase.org/openapi.json -o bedbase-types.d.ts"
},
"dependencies": {
"@tanstack/react-query": "^5.28.0",
Expand Down
110 changes: 85 additions & 25 deletions ui/src/components/bed-splash-components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Fragment, useState } from 'react';
import { components } from '../../../bedbase-types';
import { useCopyToClipboard } from '@uidotdev/usehooks';
import { bytesToSize, formatDateTime } from '../../utils';
import { Dropdown } from 'react-bootstrap';
import { Dropdown, OverlayTrigger } from 'react-bootstrap';

const API_BASE = import.meta.env.VITE_API_BASE || '';

Expand Down Expand Up @@ -45,10 +45,7 @@ export const BedSplashHeader = (props: Props) => {
{copiedId ? <i className="bi bi-check me-1" /> : <i className="bi bi-clipboard me-1" />}
</button>
</h4>
<p className="text-muted">
{metadata.name} {' | '}
{metadata.raw_metadata?.global_sample_id || 'No source available'}
</p>
<p className="text-muted">{metadata.name}</p>
</div>
<div className="d-flex flex-row align-items-center gap-1">
<a href={`${API_BASE}/bed/${record_identifier}/metadata?full=true`}>
Expand Down Expand Up @@ -148,44 +145,107 @@ export const BedSplashHeader = (props: Props) => {
<div className="d-flex flex-row gap-1 text-lg">
<div className="d-flex flex-row">
<p className="mb-0">
<a href={`http://refgenomes.databio.org/v3/genomes/splash/${metadata?.genome_digest}`} target="_blank">
<div className="badge bg-primary">
<i className="bi bi-database-fill me-2"/>
{metadata?.genome_alias || 'No assembly available'}
</div>
</a>
<OverlayTrigger
placement="top"
overlay={
<div className="tooltip">
<div className="tooltip-arrow" />
<div className="tooltip-inner">Genome assembly</div>
</div>
}
>
<a href={`http://refgenomes.databio.org/v3/genomes/splash/${metadata?.genome_digest}`} target="_blank">
<div className="badge bg-primary">
<i className="bi bi-database-fill me-2" />
{metadata?.genome_alias || 'No assembly available'}
</div>
</a>
</OverlayTrigger>
</p>
</div>
<div className="d-flex flex-row">
<p className="mb-0">
<div className="badge bg-primary">
<i className="bi bi-file-earmark-text-fill me-1"/>
{metadata?.bed_format || 'No format available'}
</div>
<OverlayTrigger
placement="top"
overlay={
<div className="tooltip">
<div className="tooltip-arrow" />
<div className="tooltip-inner">BED file format</div>
</div>
}
>
<div className="badge bg-primary">
<i className="bi bi-file-earmark-text-fill me-1" />
{metadata?.bed_format || 'No format available'}
</div>
</OverlayTrigger>
</p>
</div>
<div className="d-flex flex-row">
<p className="mb-0">
<div className="badge bg-primary">
<i className="bi bi-folder-fill me-1"/>
{metadata?.bed_type || 'No bed type available'}
</div>
<OverlayTrigger
placement="top"
overlay={
<div className="tooltip">
<div className="tooltip-arrow" />
<div className="tooltip-inner">BED type</div>
</div>
}
>
<div className="badge bg-primary">
<i className="bi bi-folder-fill me-1" />
{metadata?.bed_type || 'No bed type available'}
</div>
</OverlayTrigger>
</p>
</div>
<div className="d-flex flex-row">
<p className="mb-0">
<a href={`http://purl.obolibrary.org/obo/${(metadata?.license_id || 'DUO:0000042').replace(/:/g, '_')}`} target="_blank">
<div className="badge bg-primary">
<i className="bi bi-patch-check-fill me-1"/>
{metadata?.license_id || 'DUO:0000042'}
</div>
<a
href={`http://purl.obolibrary.org/obo/${(metadata?.license_id || 'DUO:0000042').replace(/:/g, '_')}`}
target="_blank"
>
<OverlayTrigger
placement="top"
overlay={
<div className="tooltip">
<div className="tooltip-arrow" />
<div className="tooltip-inner">License</div>
</div>
}
>
<div className="badge bg-primary">
<i className="bi bi-award-fill me-1" />
{metadata?.license_id || 'DUO:0000042'}
</div>
</OverlayTrigger>
</a>
</p>
</div>
{metadata?.is_universe && (
<div className="d-flex flex-row">
<p className="mb-0 cursor-default">
<OverlayTrigger
placement="top"
overlay={
<div className="tooltip">
<div className="tooltip-arrow" />
<div className="tooltip-inner">This BED file is part of the Universe</div>
</div>
}
>
<div className="badge bg-secondary">
<i className="bi bi bi-globe2 me-1" />
Universe
</div>
</OverlayTrigger>
</p>
</div>
)}
</div>
<div className="d-flex flex-column text-sm">
<div className="d-flex flex-row align-items-center text-muted">
<i className="bi bi-calendar me-1"/>
<i className="bi bi-calendar me-1" />
<p className="mb-0">
<span>Created:</span>{' '}
{metadata?.submission_date ? formatDateTime(metadata?.submission_date) : 'No date available'}
Expand Down
14 changes: 14 additions & 0 deletions ui/src/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ a {
min-height: 100vh;
}

.h-80 {
height: 80%;
}

/* This is for the nav bar */
.hidden {
display: none;
Expand Down Expand Up @@ -148,6 +152,12 @@ a {
animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite;
}

.truncate {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

/* The typing effect */
@keyframes typing {
from {
Expand Down Expand Up @@ -178,6 +188,10 @@ a {
cursor: pointer;
}

.cursor-default {
cursor: default;
}

.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
Expand Down
100 changes: 69 additions & 31 deletions ui/src/pages/bed-splash.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,37 +108,75 @@ export const BedSplash = () => {
{metadata !== undefined ? <BedSplashHeader metadata={metadata} record_identifier={bedId} /> : null}
</Col>
</Row>
<h2 className="fw-bold">Overview</h2>
<Col sm={12} md={12} className="mb-2 w-100">
<div className="border rounded p-1 shadow-sm">
<table className="table table-sm rounded text-truncate">
<thead>
<tr>
<th scope="col">Key</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody className="text-sm">
{Object.keys(metadata?.raw_metadata || {}).map((k) => {
if (k === 'input_file' || k === 'global_sample_id' || k === 'file_name') {
return null;
// @ts-expect-error wants to get mad because it could be an object and React cant render that (it wont be)
} else if (!metadata?.raw_metadata[k]) {
return null;
} else {
return (
<tr key={k}>
<td className="fst-italic">{snakeToTitleCase(k)}</td>
{/* @ts-expect-error wants to get mad because it could be an object and React cant render that (it wont be) */}
<td>{metadata?.raw_metadata[k] || 'N/A'}</td>
</tr>
);
}
})}
</tbody>
</table>
</div>
</Col>
<Row className="mb-2">
<Col sm={12} md={6}>
<h2 className="fw-bold">Overview</h2>
<div className="border rounded p-1 shadow-sm">
<table className="table table-sm rounded text-truncate">
<thead>
<tr>
<th scope="col">Key</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody className="text-sm">
{Object.keys(metadata?.raw_metadata || {}).map((k) => {
if (k === 'input_file' || k === 'file_name' || k === 'sample_name') {
return null;
// @ts-expect-error wants to get mad because it could be an object and React cant render that (it wont be)
} else if (!metadata?.raw_metadata[k]) {
return null;
} else {
return (
<tr key={k}>
<td style={{ maxWidth: '50px' }} className="fst-italic">
{snakeToTitleCase(k)}
</td>

<td style={{ maxWidth: '120px' }} className="truncate">
{/* @ts-expect-error wants to get mad because it could be an object and React cant render that (it wont be) */}
{metadata?.raw_metadata[k] || 'N/A'}
</td>
</tr>
);
}
})}
</tbody>
</table>
</div>
</Col>
<Col sm={12} md={6}>
<h2 className="fw-bold">BED Sets</h2>
<div className="border rounded p-1 shadow-sm h-80">
<table className="table table-sm rounded text-truncate text-sm">
<thead>
<tr>
<th scope="col">BED set ID</th>
<th scope="col">Name</th>
<th scope="col">Description</th>
<th scope="col">View</th>
</tr>
</thead>
<tbody>
{metadata?.bedsets?.map((bedset) => (
<tr key={bedset.id} className="truncate">
<td className="truncate" style={{ maxWidth: '150px' }}>
{bedset.id}
</td>
<td className="truncate" style={{ maxWidth: '100px' }}>
{bedset.name || 'No name'}
</td>
<td>{bedset.description || 'No description'}</td>
<td>
<a href={`/bedset/${bedset.id}`}>View</a>
</td>
</tr>
)) || 'N/A'}
</tbody>
</table>
</div>
</Col>
</Row>
<h2 className="fw-bold">Statistics</h2>
<Row className="mb-4">
{metadata && (
Expand Down
4 changes: 2 additions & 2 deletions ui/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ type ObjectType = 'bed' | 'bedset';

export const makeHttpDownloadLink = (md5: string) => {
const API_BASE = import.meta.env.VITE_API_BASE || '';
return `${API_BASE}/objects/bed.${md5}.bedfile/access/http`;
return `${API_BASE}/objects/bed.${md5}.bed_file/access/http`;
};

export const makeS3DownloadLink = (md5: string) => {
const API_BASE = import.meta.env.VITE_BEDHOST_API_URL || '';
return `${API_BASE}/objects/bed.${md5}.bedfile/access/s3`;
return `${API_BASE}/objects/bed.${md5}.bed_file/access/s3`;
};

export const formatNumberWithCommas = (n: number) => {
Expand Down

0 comments on commit c869467

Please sign in to comment.