Skip to content

Commit

Permalink
WIP: sample sheets...
Browse files Browse the repository at this point in the history
  • Loading branch information
jmchilton committed Dec 22, 2024
1 parent 8fc2cfe commit 18ce2db
Show file tree
Hide file tree
Showing 42 changed files with 2,075 additions and 21 deletions.
4 changes: 4 additions & 0 deletions client/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,4 +312,8 @@ export type ObjectExportTaskResponse = components["schemas"]["ObjectExportTaskRe
export type ExportObjectRequestMetadata = components["schemas"]["ExportObjectRequestMetadata"];
export type ExportObjectResultMetadata = components["schemas"]["ExportObjectResultMetadata"];

export type SampleSheetColumnDefinition = components["schemas"]["SampleSheetColumnDefinitionModel"];
export type SampleSheetColumnDefinitionType = SampleSheetColumnDefinition["type"];
export type SampleSheetColumnDefinitions = SampleSheetColumnDefinition[] | null;

export type AsyncTaskResultSummary = components["schemas"]["AsyncTaskResultSummary"];
10 changes: 10 additions & 0 deletions client/src/components/Collections/CollectionCreatorModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import ListCollectionCreator from "./ListCollectionCreator.vue";
import PairCollectionCreator from "./PairCollectionCreator.vue";
import PairedListCollectionCreator from "./PairedListCollectionCreator.vue";
import PairedOrUnpairedListCollectionCreator from "./PairedOrUnpairedListCollectionCreator.vue";
import SampleSheetCollectionCreator from "./SampleSheetCollectionCreator.vue";
import Heading from "@/components/Common/Heading.vue";
import GenericItem from "@/components/History/Content/GenericItem.vue";
import LoadingSpan from "@/components/LoadingSpan.vue";
Expand Down Expand Up @@ -323,6 +324,15 @@ function resetModal() {
:extensions="props.extensions"
@clicked-create="createPairedCollection"
@on-cancel="hideModal" />
<SampleSheetCollectionCreator
v-else-if="props.collectionType === 'sample_sheet'"
:history-id="props.historyId"
:initial-elements="creatorItems || []"
:default-hide-source-items="props.defaultHideSourceItems"
:from-selection="fromSelection"
:extensions="props.extensions"
@clicked-create="createPairedCollection"
@on-cancel="hideModal" />
</BModal>
</template>

Expand Down
52 changes: 52 additions & 0 deletions client/src/components/Collections/SampleSheetCollectionCreator.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<script lang="ts" setup>
import { useConfig } from "@/composables/config";
import SampleSheetWizard from "./SampleSheetWizard.vue";
const { config, isConfigLoaded } = useConfig();
interface Props {
fileSourcesConfigured: boolean;
ftpUploadSite?: string;
}
defineProps<Props>();
/*
const initialElements = [
["https://zenodo.org/records/3263975/files/DRR000770.fastqsanger.gz", 1, "treatment1", false],
["https://zenodo.org/records/3263975/files/DRR000771.fastqsanger.gz", 2, "treatment1", false],
["https://zenodo.org/records/3263975/files/DRR000772.fastqsanger.gz", 1, "none", true],
["https://zenodo.org/records/3263975/files/DRR000773.fastqsanger.gz", 1, "treatment2", false],
["https://zenodo.org/records/3263975/files/DRR000774.fastqsanger.gz", 2, "treatment3", false],
];
*/
const columnDefinitions = [
{ name: "replicate number", type: "int", description: "The replicate number of this sample." },
{
name: "treatment",
type: "string",
restrictions: ["treatment1", "treatment2", "none"],
description: "The treatment code for this sample.",
},
{
name: "is control?",
type: "boolean",
description: "Was this sample a control? If TRUE, please ensure treatment is set to none.",
},
];
</script>

<template>
<div class="sample-sheet-collection-creator">
<SampleSheetWizard
v-if="isConfigLoaded"
:file-sources-configured="config.file_sources_configured"
:ftp-upload-site="config.ftp_upload_site"
:column-definitions="columnDefinitions" />
<!--
<SampleSheetGrid :initial-elements="initialElements" :columnDefinitions="columnDefinitions" />
-->
</div>
</template>
139 changes: 139 additions & 0 deletions client/src/components/Collections/SampleSheetWizard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<script setup lang="ts">
import { BCardGroup } from "bootstrap-vue";
import { computed, ref } from "vue";
import { type SampleSheetColumnDefinitions } from "@/api";
import { useWizard } from "@/components/Common/Wizard/useWizard";
import { type RulesSourceFrom } from "./wizard/types";
import { useFileSetSources } from "./wizard/useFileSetSources";
import SampleSheetGrid from "./sheet/SampleSheetGrid.vue";
import PasteData from "./wizard/PasteData.vue";
import SelectDataset from "./wizard/SelectDataset.vue";
import SelectFolder from "./wizard/SelectFolder.vue";
import SourceFromCollection from "./wizard/SourceFromCollection.vue";
import SourceFromDatasetAsTable from "./wizard/SourceFromDatasetAsTable.vue";
import SourceFromPastedData from "./wizard/SourceFromPastedData.vue";
import SourceFromRemoteFiles from "./wizard/SourceFromRemoteFiles.vue";
import GenericWizard from "@/components/Common/Wizard/GenericWizard.vue";
const isBusy = ref<boolean>(false);
const { pasteData, tabularDatasetContents, uris, setRemoteFilesFolder, onFtp, setDatasetContents, setPasteTable } =
useFileSetSources(isBusy);
interface Props {
fileSourcesConfigured: boolean;
ftpUploadSite?: string;
columnDefinitions: SampleSheetColumnDefinitions;
}
defineProps<Props>();
const sourceInstructions = computed(() => {
return `Sample sheets can be initialized from a set or files, URIs, or existing datasets.`;
});
const sourceFrom = ref<RulesSourceFrom>("remote_files");
function setSourceForm(newValue: RulesSourceFrom) {
sourceFrom.value = newValue;
}
const targetCollectionId = ref<string | undefined>(undefined);
const wizard = useWizard({
"select-source": {
label: "Select source",
instructions: sourceInstructions,
isValid: () => true,
isSkippable: () => false,
},
"select-remote-files-folder": {
label: "Select folder",
instructions: "Select folder of files to import.",
isValid: () => sourceFrom.value === "remote_files" && Boolean(uris.value.length > 0),
isSkippable: () => sourceFrom.value !== "remote_files",
},
"paste-data": {
label: "Paste data",
instructions: "Paste data containing URIs and optional extra metadata.",
isValid: () => sourceFrom.value === "pasted_table" && pasteData.value.length > 0,
isSkippable: () => sourceFrom.value !== "pasted_table",
},
"select-dataset": {
label: "Select dataset",
instructions: "Select tabular dataset to load URIs and metadata from.",
isValid: () => sourceFrom.value === "dataset_as_table" && tabularDatasetContents.value.length > 0,
isSkippable: () => sourceFrom.value !== "dataset_as_table",
},
"select-collection": {
label: "Select collection",
instructions: "Select existing collection to transform into a sample sheet.",
isValid: () => sourceFrom.value === "collection" && Boolean(targetCollectionId.value),
isSkippable: () => sourceFrom.value !== "collection",
},
"fill-grid": {
label: "Fill sheet",
instructions: "Fill in metadata to describe the files you're importing.",
isValid: () => true,
isSkippable: () => false,
},
});
const importButtonLabel = computed(() => {
if (sourceFrom.value == "collection") {
return "Build";
} else {
return "Import";
}
});
const emit = defineEmits(["dismiss"]);
const initialElements = computed<string[]>(() => {
if (sourceFrom.value == "remote_files") {
const rows: string[] = [];
for (const uri of uris.value) {
rows.push(uri.uri);
}
return rows;
}
return [];
});
function submit() {
emit("dismiss");
}
</script>

<template>
<GenericWizard :use="wizard" :submit-button-label="importButtonLabel" @submit="submit">
<div v-if="wizard.isCurrent('select-source')">
<BCardGroup deck>
<SourceFromRemoteFiles :selected="sourceFrom === 'remote_files'" @select="setSourceForm" />
<SourceFromPastedData :selected="sourceFrom === 'pasted_table'" @select="setSourceForm" />
<SourceFromDatasetAsTable :selected="sourceFrom === 'dataset_as_table'" @select="setSourceForm" />
<SourceFromCollection :selected="sourceFrom === 'collection'" @select="setSourceForm" />
</BCardGroup>
</div>
<div v-else-if="wizard.isCurrent('paste-data')">
<PasteData @onChange="setPasteTable" />
</div>
<div v-else-if="wizard.isCurrent('select-remote-files-folder')">
<SelectFolder :ftp-upload-site="ftpUploadSite" @onChange="setRemoteFilesFolder" @onFtp="onFtp" />
</div>
<div v-else-if="wizard.isCurrent('select-dataset')">
<SelectDataset @onChange="setDatasetContents" />
</div>
<div v-else-if="wizard.isCurrent('select-collection')">
<SelectDataset @onChange="setDatasetContents" />
</div>
<div v-else-if="wizard.isCurrent('fill-grid')">
<SampleSheetGrid
:column-definitions="columnDefinitions"
:initial-elements="initialElements"
height="300px" />
</div>
</GenericWizard>
</template>
22 changes: 22 additions & 0 deletions client/src/components/Collections/sheet/DownloadWorkbookButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script setup lang="ts">
import { library } from "@fortawesome/fontawesome-svg-core";
import { faFileExcel } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BButton } from "bootstrap-vue";
library.add(faFileExcel);
interface Props {
title: string;
}
defineProps<Props>();
const emit = defineEmits(["click"]);
</script>

<template>
<BButton :title="title" role="button" variant="link" size="sm" class="ml-0" @click="emit('click')">
<FontAwesomeIcon icon="file-excel" />
</BButton>
</template>
Loading

0 comments on commit 18ce2db

Please sign in to comment.