Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CORE-132] Autogenerate dataTable from Data Uploader #5174

Merged
merged 6 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/libs/ajax/workspaces/Workspaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,12 @@ export const Workspaces = (signal?: AbortSignal) => ({
_.mergeAll([authOpts(), { signal }])
).then((r) => r.blob()),

autoGenerateTsv: (entityType: string, prefix: string): Promise<Blob> =>
fetchOrchestration(
`api/workspaces/${namespace}/${name}/entities/${entityType}/paired-tsv`,
_.mergeAll([authOpts(), jsonBody({ prefix }), { signal, method: 'POST' }])
).then((r: { blob: () => any }) => r.blob()),

copyEntities: async (
destNamespace: string,
destName: string,
Expand Down
1 change: 1 addition & 0 deletions src/libs/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ const eventsList = {
uploaderUploadMetadata: 'uploader:metadata:upload',
uploaderCreateTable: 'uploader:table:create',
uploaderUpdateTable: 'uploader:table:update',
uploaderAutoGenerateTable: 'uploader:table:autoGenerate',
user: {
authToken: {
load: {
Expand Down
11 changes: 11 additions & 0 deletions src/libs/feature-previews-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const FIRECLOUD_UI_MIGRATION = 'firecloudUiMigration';
export const COHORT_BUILDER_CARD = 'cohortBuilderCard';
export const GCP_BUCKET_LIFECYCLE_RULES = 'gcpBucketLifecycleRules';
export const SPEND_REPORTING = 'spendReporting';
export const AUTO_GENERATE_DATA_TABLES = 'autoGenerateDataTables';

// If the groups option is defined for a FeaturePreview, it must contain at least one group.
type GroupsList = readonly [string, ...string[]];
Expand Down Expand Up @@ -126,6 +127,16 @@ const featurePreviewsConfig: readonly FeaturePreview[] = [
)}`,
lastUpdated: '11/19/2024',
},
{
id: AUTO_GENERATE_DATA_TABLES,
title: 'Autogenerate data table for single and paired end sequencing',
description:
'Enabling this feature will show a new option in the data uploader to autogenerate a data table instead of uploading your own TSV. This feature will attempt to automatch known file patterns for single and paired end sequencing and autogenerate a data table linking to those files.',
feedbackUrl: `mailto:[email protected]?subject=${encodeURIComponent(
'Feedback on Autogenerate data table for single and paired end sequencing'
)}`,
lastUpdated: '11/26/2024',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious - is this date a guess for when it's going out or what?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is a guess of when I anticipate this work to get to prod.

},
];

export default featurePreviewsConfig;
58 changes: 55 additions & 3 deletions src/workspace-data/upload-data/UploadData.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { readFileAsText } from '@terra-ui-packages/core-utils';
import _ from 'lodash/fp';
import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
import { code, div, h, h2, h3, li, p, span, strong, ul } from 'react-hyperscript-helpers';
import { ButtonPrimary, Link, topSpinnerOverlay, transparentSpinnerOverlay, VirtualizedSelect } from 'src/components/common';
import { ButtonOutline, ButtonPrimary, Link, topSpinnerOverlay, transparentSpinnerOverlay, VirtualizedSelect } from 'src/components/common';
import FileBrowser from 'src/components/data/FileBrowser';
import Dropzone from 'src/components/Dropzone';
import FloatingActionButton from 'src/components/FloatingActionButton';
Expand All @@ -17,6 +17,8 @@ import { Workspaces } from 'src/libs/ajax/workspaces/Workspaces';
import colors from 'src/libs/colors';
import { reportError, withErrorReporting } from 'src/libs/error';
import Events from 'src/libs/events';
import { isFeaturePreviewEnabled } from 'src/libs/feature-previews';
import { AUTO_GENERATE_DATA_TABLES } from 'src/libs/feature-previews-config';
import * as Nav from 'src/libs/nav';
import { forwardRefWithName, useCancellation, useOnMount } from 'src/libs/react-utils';
import * as StateHistory from 'src/libs/state-history';
Expand Down Expand Up @@ -564,10 +566,12 @@ const MetadataUploadPanel = ({
const basePrefix = `${rootPrefix}${collection}/`;
const [filesLoading, setFilesLoading] = useState(false);
const [uploading, setUploading] = useState(false);
const [autoGenerating, setAutoGenerating] = useState(false);

const [metadataFile, setMetadataFile] = useState(null);
const [metadataTable, setMetadataTable] = useState(null);
const [filenames, setFilenames] = useState({});
const [autoGeneratedFile, setAutoGeneratedFile] = useState(null);

const setErrors = (errors) => {
setMetadataTable({ errors });
Expand Down Expand Up @@ -762,10 +766,54 @@ const MetadataUploadPanel = ({
}
});

const handleAutoGeneratedFile = (autoGeneratedFile, eventName, eventStatus) => {
const isDone = eventStatus !== 'generated';
if (autoGeneratedFile) {
void Metrics().captureEvent(eventName, {
...autoGeneratedFile,
status: eventStatus,
});
isDone && setAutoGeneratedFile(null);
}
};

const doAutoGenerate = _.flow(Utils.withBusyState(setAutoGenerating))(async () => {
try {
const workspace = Workspaces().workspace(namespace, name);

setAutoGeneratedFile({
workspaceNamespace: namespace,
workspaceName: name,
entityType: collection,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be better to ask the user to specify the table name - perhaps with a suggested default of the collection value - instead of assuming? I fear that the subdirectory into which users upload files is not what they desire for a table name.

Copy link

@admull admull Nov 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's ok to keep as currently implemented for preview and something we can get feedback on!

prefix: basePrefix,
});

const autoGeneratedTsv = await workspace.autoGenerateTsv(collection, basePrefix);
setMetadataFile(autoGeneratedTsv);

handleAutoGeneratedFile(autoGeneratedFile, Events.uploaderAutoGenerateTable, 'generated');
} catch (error) {
handleAutoGeneratedFile(autoGeneratedFile, Events.uploaderAutoGenerateTable, 'failed');
await reportError('Failed to autogenerate entity metadata', error);
}
});

// Render

const renderAutoGenerateSection = () => {
if (!isFeaturePreviewEnabled(AUTO_GENERATE_DATA_TABLES)) return null;

return div({ style: { display: 'flex', flexDirection: 'column', alignItems: 'center' } }, [
h(ButtonOutline, { style: { ...styles.heading, flex: 0 }, onClick: doAutoGenerate }, [
'Autogenerate table for single or paired end sequencing (BETA)',
]),
h2({ style: { ...styles.heading, flex: 0, margin: '0.25rem' } }, [span({ ref: header, tabIndex: -1 }, ['OR'])]),
]);
};

return div({ style: { height: '100%', display: 'flex', flexFlow: 'column nowrap' } }, [
h2({ style: { ...styles.heading, flex: 0 } }, [
renderAutoGenerateSection(),
h2({ style: { ...styles.heading, flex: 0, margin: '0.25rem' } }, [
icon('listAlt', { size: 20, style: { marginRight: '1ch' } }),
span({ ref: header, tabIndex: -1 }, ['Upload Your Metadata Files']),
]),
Expand Down Expand Up @@ -859,14 +907,18 @@ const MetadataUploadPanel = ({
metadataTable,
onConfirm: ({ metadata }) => {
doUpload(metadata);
// Track if autogenerated table is accepted
handleAutoGeneratedFile(autoGeneratedFile, Events.uploaderAutoGenerateTable, 'accepted');
},
onCancel: () => {
setMetadataFile(null);
setMetadataTable(null);
// Track if autogenerated table is cancelled
handleAutoGeneratedFile(autoGeneratedFile, Events.uploaderAutoGenerateTable, 'cancelled');
},
onRename: renameTable,
}),
(filesLoading || uploading) && topSpinnerOverlay,
(filesLoading || uploading || autoGenerating) && topSpinnerOverlay,
]);
};

Expand Down
Loading