Skip to content

Commit

Permalink
User datasets tweaks (#1193)
Browse files Browse the repository at this point in the history
* Verbiage updates, and make description optional by default

* Remove link to user dataset workspace from study summaries page

* Make spacing between elements more consistent

* Reorder attributes on detail page, remove quota usage, and refactor some page sections

* Refactor
  • Loading branch information
dmfalke authored Aug 29, 2024
1 parent 08316b8 commit eb7af83
Show file tree
Hide file tree
Showing 18 changed files with 377 additions and 412 deletions.
32 changes: 17 additions & 15 deletions packages/libs/eda/src/lib/workspace/AnalysisPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -427,21 +427,23 @@ export function AnalysisPanel({
// Note that we are not inluding the custom detail page.
// As of this writing, details pages only add a link to
// EDA. Since we are in EDA, we don't want to add it here.
<UserDatasetDetailController
baseUrl={`${routeBase}/details`}
detailsPageTitle={'My Study'}
workspaceTitle={'My Studies'}
id={wdkRecordIdToDiyUserDatasetId(
studyRecord.attributes.dataset_id as string
)}
dataNoun={{
singular: 'Study',
plural: 'Studies',
}}
enablePublicUserDatasets={true}
includeAllLink={false}
includeNameHeader={false}
/>
<div style={{ marginBlockStart: '1em' }}>
<UserDatasetDetailController
baseUrl={`${routeBase}/details`}
detailsPageTitle={'My Study'}
workspaceTitle={'My Studies'}
id={wdkRecordIdToDiyUserDatasetId(
studyRecord.attributes.dataset_id as string
)}
dataNoun={{
singular: 'Study',
plural: 'Studies',
}}
enablePublicUserDatasets={true}
includeAllLink={false}
includeNameHeader={false}
/>
</div>
) : (
<RecordController
recordClass="dataset"
Expand Down
19 changes: 5 additions & 14 deletions packages/libs/user-datasets/src/lib/Actions/UserDatasetsActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
UserDatasetDetails,
UserDatasetMeta,
UserDatasetVDI,
UserQuotaMetadata,
UserDatasetFileListing,
} from '../Utils/types';
import { FetchClientError } from '@veupathdb/http-utils';
Expand Down Expand Up @@ -504,13 +503,12 @@ export function loadUserDatasetListWithoutLoadingIndicator() {
() => false
),
wdkService.getCurrentUserDatasets(),
wdkService.getUserQuotaMetadata(),
]).then(([filterByProject, userDatasets, userQuotaMetadata]) => {
]).then(([filterByProject, userDatasets]) => {
const vdiToExistingUds = userDatasets.map(
(ud: UserDatasetVDI): UserDataset => {
const { fileCount, shares, fileSizeTotal } = ud;
const partiallyTransformedResponse =
transformVdiResponseToLegacyResponseHelper(ud, userQuotaMetadata);
transformVdiResponseToLegacyResponseHelper(ud);
return {
...partiallyTransformedResponse,
fileCount,
Expand All @@ -535,16 +533,12 @@ export function loadUserDatasetDetailWithoutLoadingIndicator(id: string) {
return validateVdiCompatibleThunk<DetailAction>(({ wdkService }) =>
Promise.all([
wdkService.getUserDataset(id),
wdkService.getUserQuotaMetadata(),
wdkService.getUserDatasetFileListing(id),
]).then(
([userDataset, userQuotaMetadata, fileListing]) => {
([userDataset, fileListing]) => {
const { shares, dependencies } = userDataset as UserDatasetDetails;
const partiallyTransformedResponse =
transformVdiResponseToLegacyResponseHelper(
userDataset,
userQuotaMetadata
);
transformVdiResponseToLegacyResponseHelper(userDataset);
const transformedResponse = {
...partiallyTransformedResponse,
fileListing,
Expand Down Expand Up @@ -693,8 +687,7 @@ type PartialLegacyUserDataset = Omit<
>;

function transformVdiResponseToLegacyResponseHelper(
ud: UserDatasetDetails | UserDatasetVDI,
userQuotaMetadata: UserQuotaMetadata
ud: UserDatasetDetails | UserDatasetVDI
): PartialLegacyUserDataset {
const {
name,
Expand All @@ -709,7 +702,6 @@ function transformVdiResponseToLegacyResponseHelper(
importMessages,
visibility,
} = ud;
const { quota } = userQuotaMetadata;
return {
owner: owner.firstName + ' ' + owner.lastName,
projects: projectIds ?? [],
Expand All @@ -728,7 +720,6 @@ function transformVdiResponseToLegacyResponseHelper(
ownerUserId: owner.userId,
age: Date.now() - Date.parse(created),
id: datasetId,
percentQuotaUsed: quota.usage / quota.limit,
status,
importMessages: importMessages ?? [],
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React from 'react';

import Icon from '@veupathdb/wdk-client/lib/Components/Icon/IconAlt';
import { Mesa, MesaState } from '@veupathdb/coreui/lib/components/Mesa';
import {
AnchoredTooltip,
Mesa,
MesaState,
} from '@veupathdb/coreui/lib/components/Mesa';

import { makeClassifier } from '../UserDatasetUtils';
import UserDatasetDetail from './UserDatasetDetail';
Expand All @@ -14,6 +18,11 @@ class BigwigDatasetDetail extends UserDatasetDetail {
super(props);
this.renderTracksSection = this.renderTracksSection.bind(this);
this.getTracksTableColumns = this.getTracksTableColumns.bind(this);
this.renderCompatibilitySection =
this.renderCompatibilitySection.bind(this);
this.getCompatibilityStatus = this.getCompatibilityStatus.bind(this);
this.getCompatibilityTableColumns =
this.getCompatibilityTableColumns.bind(this);
this.state = {
...this.state,
sequenceId: null,
Expand Down Expand Up @@ -133,13 +142,135 @@ class BigwigDatasetDetail extends UserDatasetDetail {
);
}

/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Compatible Table
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */

renderCompatibilitySection() {
const { userDataset, config, dataNoun } = this.props;
const { displayName } = config;

const compatibilityTableState = MesaState.create({
columns: this.getCompatibilityTableColumns(userDataset),
rows: userDataset.dependencies,
});

const compatibilityStatus = this.getCompatibilityStatus();

return (
<section id="dataset-compatibility">
<h2>
Use This {dataNoun.singular} in {displayName}
</h2>
<h3>
<Icon fa="puzzle-piece" />
Compatibility Information &nbsp;
<AnchoredTooltip
content={`The data and genomes listed here are requisite for using the data in this user ${dataNoun.singular.toLowerCase()}.`}
>
<div className="HelpTrigger">
<Icon fa="question-circle" />
</div>
</AnchoredTooltip>
</h3>
<div style={{ maxWidth: '600px' }}>
<Mesa state={compatibilityTableState} />
</div>
{compatibilityStatus}
</section>
);
}

getCompatibilityStatus() {
const { userDataset, config, dataNoun } = this.props;
const { projectId } = config;

const { status, projects } = userDataset;

/**
* In VDI, we know a dataset is compatible when the site-specific's install status
* indicates a successful install.
*
* We know a dataset is incompatible when the site-specific's install status
* indicates `missing-dependency`
*/
const installStatusForCurrentProject = status.install?.find(
(d) => d.projectId === projectId
);

const isTargetingCurrentSite = projects.includes(projectId);
const isInstalled = [
userDataset.status.import,
installStatusForCurrentProject?.metaStatus,
installStatusForCurrentProject?.dataStatus,
].every((status) => status === 'complete');

const isIncompatible =
installStatusForCurrentProject?.dataStatus === 'missing-dependency';

if (!isTargetingCurrentSite || (isTargetingCurrentSite && isIncompatible)) {
return (
// if projectIds don't match, then we're not installable and thus incompatible
// if we're installable but failed due to a missing dependency, we're incompatible
<p className="danger">
This {dataNoun.singular.toLowerCase()} is not compatible with{' '}
<b>{projectId}</b>.
</p>
);
} else if (isInstalled) {
return (
// if we've installed successfully and we're installable, we're compatible
<p className="success">
This {dataNoun.singular.toLowerCase()} is compatible with{' '}
<b>{projectId}</b>. It is installed for use.
</p>
);
} else {
// instead of attempting to provide very granular messaging for when things are neither
// compatible nor incompatible, let's let the dataset page's Status messaging handle this
return null;
}
}

getCompatibilityTableColumns() {
const { userDataset } = this.props;
const { projects } = userDataset;
return [
{
key: 'project',
name: 'VEuPathDB Website',
renderCell() {
return projects.join(', ');
},
},
{
key: 'resourceDisplayName',
name: 'Required Resource',
renderCell({ row }) {
const { resourceDisplayName } = row;
return resourceDisplayName;
},
},
{
key: 'resourceVersion',
name: 'Required Resource Release',
renderCell({ row }) {
const { resourceVersion } = row;
return resourceVersion;
},
},
];
}

// See note in the base class, UserDatasetDetail
/** @return {import("react").ReactNode[]} */
getPageSections() {
const [headerSection, compatSection, fileSection] = super.getPageSections();
const [headerSection, fileSection] = super.getPageSections();
return [
headerSection,
compatSection,
this.renderCompatibilitySection,
this.renderTracksSection,
fileSection,
];
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Link } from 'react-router-dom';

import UserDatasetDetail from './UserDatasetDetail';

class EdaDatasetDetail extends UserDatasetDetail {
constructor(props) {
super(props);
this.renderEdaLinkout = this.renderEdaLinkout.bind(this);
}

renderEdaLinkout() {
const {
config: { displayName, projectId },
userDataset: { status },
edaWorkspaceUrl,
edaMapUrl,
} = this.props;

const isInstalled =
status?.import === 'complete' &&
status?.install?.find((d) => d.projectId === projectId)?.dataStatus ===
'complete';

if (!isInstalled) return null;

if (edaWorkspaceUrl == null && edaMapUrl == null) return null;

return (
<ul className="eda-linkout">
{!edaWorkspaceUrl ? null : (
<li>
<Link to={edaWorkspaceUrl}>
<i className="ebrc-icon-edaIcon"></i> Explore in {displayName}
</Link>
</li>
)}
{!edaMapUrl ? null : (
<li>
<Link to={edaMapUrl}>
<i className="ebrc-icon-edaIcon"></i> Explore in MapVEu
</Link>
</li>
)}
</ul>
);
}

getAttributes() {
const attributes = super.getAttributes();

if (!this.isInstalled()) return attributes;

const edaLinks = {
attribute: 'Explore',
value: this.renderEdaLinkout(),
};
const spliceIndex = this.props.includeNameHeader ? 2 : 1;
return [
...attributes.slice(0, spliceIndex),
edaLinks,
...attributes.slice(spliceIndex),
];
}
}

export default EdaDatasetDetail;
Loading

0 comments on commit eb7af83

Please sign in to comment.