Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
37 changes: 25 additions & 12 deletions client/src/components/Collections/BuildFileSetWizard.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { BCardGroup } from "bootstrap-vue";
import { BAlert, BCardGroup } from "bootstrap-vue";
import { computed, ref } from "vue";

import { GalaxyApi } from "@/api";
Expand All @@ -11,6 +11,7 @@ import { forBuilder, type ForBuilderResponse } from "@/components/Collections/wi
import { useWizard } from "@/components/Common/Wizard/useWizard";
import { useToolRouting } from "@/composables/route";
import localize from "@/utils/localization";
import { errorMessageAsString } from "@/utils/simple-error";

import type {
ParsedFetchWorkbook,
Expand Down Expand Up @@ -112,7 +113,7 @@ const wizard = useWizard({
},
"upload-workbook": {
label: "Upload workbook",
instructions: "Upload a workbook containing with URIs and metadata",
instructions: "Upload a workbook containing URIs with metadata",
isValid: () => sourceFrom.value === "workbook" && workbookCompleted.value,
isSkippable: () => sourceFrom.value !== "workbook",
},
Expand Down Expand Up @@ -239,7 +240,7 @@ async function handleWorkbook(base64Content: string) {
handleUploadedData(data);
} else {
console.log(error);
uploadErrorMessage.value = "There was an error processing the file.";
uploadErrorMessage.value = "There was an error processing the file. " + errorMessageAsString(error);
}
}

Expand All @@ -260,17 +261,26 @@ const {
<template>
<GenericWizard :use="wizard" :submit-button-label="importButtonLabel" :title="title" @submit="submit">
<template v-slot:header>
<BAlert
:show="!!uploadErrorMessage"
variant="danger"
class="my-2"
dismissible
@dismissed="uploadErrorMessage = ''">
{{ uploadErrorMessage }}
</BAlert>
<h2 data-galaxy-file-drop-target>
{{ title }}
<FontAwesomeIcon
class="workbook-upload-helper mr-1"
:class="dropZoneClasses"
:title="dropWorkbookTitle"
:icon="faUpload"
@click.prevent="browseFiles"
@drop.prevent="handleDrop"
@dragover.prevent="isDragging = true"
@dragleave.prevent="isDragging = false" />
<a v-b-tooltip.hover aria-label="Upload Completed Workbook" :title="dropWorkbookTitle" href="#">
<FontAwesomeIcon
class="workbook-upload-helper mr-1"
:class="dropZoneClasses"
:icon="faUpload"
@click.prevent="browseFiles"
@drop.prevent="handleDrop"
@dragover.prevent="isDragging = true"
@dragleave.prevent="isDragging = false" />
</a>
<HiddenWorkbookUploadInput ref="uploadRef" @onFileUpload="onFileUpload" />
</h2>
</template>
Expand Down Expand Up @@ -337,5 +347,8 @@ const {
// modeled a bit after upload-helper in the upload component...
.workbook-upload-helper {
color: $border-color;
&:hover {
color: $brand-primary;
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ import { faDownload } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BCard, BCardTitle, BLink } from "bootstrap-vue";

// We use this in two capacities - one where we have to do a post and do complex things
// to generate the workbook and one where we just have an easy link. Support both.
interface Props {
generateWorkbookLink?: string;
}

withDefaults(defineProps<Props>(), {
generateWorkbookLink: undefined,
});

const emit = defineEmits(["download"]);
</script>

Expand All @@ -11,6 +21,8 @@ const emit = defineEmits(["download"]);
<BCardTitle>
<b>Step 1: Download</b>
</BCardTitle>
<BLink @click="emit('download')"><FontAwesomeIcon size="xl" :icon="faDownload" /> Download workbook.</BLink>
<BLink :href="generateWorkbookLink" @click="emit('download')"
><FontAwesomeIcon size="xl" :icon="faDownload" /> Download workbook.</BLink
>
</BCard>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ defineExpose({

<template>
<label style="display: none">
<input ref="fileInputRef" type="file" accept=".xlsx" @change="onFileUpload" />
<input ref="fileInputRef" type="file" accept=".xlsx,.xls,.tsv,.csv,.tabular" @change="onFileUpload" />
</label>
</template>
2 changes: 2 additions & 0 deletions client/src/components/Collections/wizard/fetchWorkbooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ const COLUMN_TITLE_PREFIXES: Record<string, ColumnMappingType> = {
deferredurl: "url_deferred",
genome: "dbkey",
dbkey: "dbkey",
build: "dbkey",
filetype: "file_type",
type: "file_type",
extension: "file_type",
info: "info",
tag: "tags",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,20 @@
- doc: "dbkey maps to the dbkey target type"
column_header: "dbkey"
maps_to: "dbkey"
- doc: "build maps to the dbkey target type"
column_header: "build"
maps_to: "dbkey"


- doc: "filetype maps to the file_type target type"
column_header: "file type"
maps_to: "file_type"
- doc: "extension maps to the file_type target type"
column_header: "extension"
maps_to: "file_type"
- doc: "Type maps to the file_type target type"
column_header: "Type"
maps_to: "file_type"

- doc: "info maps to the info target type"
column_header: "info"
Expand Down
2 changes: 2 additions & 0 deletions lib/galaxy/model/dataset_collections/rule_target_columns.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
"genome": "dbkey",
"dbkey": "dbkey",
"genomebuild": "dbkey",
"build": "dbkey",
"filetype": "file_type",
"extension": "file_type",
"fileextension": "file_type",
"type": "file_type",
"info": "info",
"tag": "tags",
"grouptag": "group_tags",
Expand Down
21 changes: 14 additions & 7 deletions lib/galaxy/model/dataset_collections/workbook_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,17 +235,24 @@ def load_workbook_from_base64(content: str) -> ReadOnlyWorkbook:
is_excel = file_like.read(4) == b"\x50\x4b\x03\x04"
workbook: ReadOnlyWorkbook
file_like.seek(0)
try:
if is_excel:
if is_excel:
try:
workbook = ExcelReadOnlyWorkbook(load_workbook(file_like, data_only=True))
else:
except Exception as e:
extra_message = str(e)
raise RequestParameterInvalidException(
f"The provided content is not a valid Excel file (or at least not one Galaxy knows how to parse). Please check the content and try again. The underlying error was [{extra_message}]"
)
else:
try:
tabular = decoded_content.decode("utf-8")
file_like_as_utf8 = StringIO(tabular)
workbook = CsvReaderReadOnlyWorkbook(file_like_as_utf8)
except Exception:
raise RequestParameterInvalidException(
"The provided content is not a valid Excel file. Please check the content and try again."
)
except Exception as e:
extra_message = str(e)
raise RequestParameterInvalidException(
f"The provided content is not a parsable as a valid CSV or TSV (or at least not one Galaxy knows how to parse). Please check the content and try again. The underlying error was [{extra_message}]"
)
return workbook


Expand Down
23 changes: 22 additions & 1 deletion test/unit/data/dataset_collections/test_workbook_util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
from galaxy.model.dataset_collections.workbook_util import index_to_excel_column
import base64

from galaxy.model.dataset_collections.workbook_util import (
index_to_excel_column,
load_workbook_from_base64,
)
from galaxy.util.resources import resource_path


def test_index_to_excel_column():
Expand All @@ -8,3 +14,18 @@ def test_index_to_excel_column():
assert index_to_excel_column(700) == "ZY"
assert index_to_excel_column(701) == "ZZ"
assert index_to_excel_column(702) == "AAA"


def test_load_workbook_from_base64():
workbook_base64 = resource_path_to_base64("filled_in_workbook_1.xlsx")
workbook = load_workbook_from_base64(workbook_base64)
assert workbook is not None

workbook_base64 = resource_path_to_base64("filled_in_workbook_1.tsv")
workbook = load_workbook_from_base64(workbook_base64)
assert workbook is not None


def resource_path_to_base64(resource_name: str) -> str:
resource_bytes = resource_path("galaxy.model.unittest_utils", resource_name).read_bytes()
return base64.b64encode(resource_bytes).decode("utf-8")
Loading