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

Replace the rules input or rules seeding component. #19329

Closed
wants to merge 1 commit into from
Closed
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
169 changes: 169 additions & 0 deletions client/src/components/Collections/BuildFileSetWizard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
<script setup lang="ts">
import { BCardGroup } from "bootstrap-vue";
import { computed, ref } from "vue";
import { getGalaxyInstance } from "@/app";
import { useWizard } from "@/components/Common/Wizard/useWizard";
import { useToolRouting } from "@/composables/route";
import { type RemoteFile, type RulesCreatingWhat, type RulesSourceFrom } from "./wizard/types";
import { useFileSetSources } from "./wizard/useFileSetSources";
import CreatingWhat from "./wizard/CreatingWhat.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;
}
const props = defineProps<Props>();
const creatingWhat = ref<RulesCreatingWhat>("datasets");
const creatingWhatTitle = computed(() => {
return creatingWhat.value == "datasets" ? "Datasets" : "Collections";
});
const sourceInstructions = computed(() => {
return `${creatingWhatTitle.value} can be created from a set or files, URIs, or existing datasets.`;
});
const sourceFrom = ref<RulesSourceFrom>("remote_files");
const { routeToTool } = useToolRouting();
const wizard = useWizard({
"select-what": {
label: "What is being created?",
instructions: computed(() => {
return `Are you creating datasets or collections?`;
}),
isValid: () => true,
isSkippable: () => false,
},
"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",
},
});
const importButtonLabel = computed(() => {
if (sourceFrom.value == "collection") {
return "Transform";
} else {
return "Import";
}
});
const emit = defineEmits(["dismiss"]);
type SelectionType = "raw" | "remote_files";
type ElementsType = RemoteFile[] | string[][];
// it would be nice to have a real type from the rule builder but
// it is older code. This is really outlining what this component can
// produce and not what the rule builder can consume which is a wide
// superset of this.
interface Entry {
dataType: RulesCreatingWhat;
ftpUploadSite?: string;
elements?: ElementsType | undefined;
content?: string;
selectionType: SelectionType;
}
function launchRuleBuilder() {
const Galaxy = getGalaxyInstance();
let elements: ElementsType | undefined = undefined;
let selectionType: SelectionType = "raw";
if (sourceFrom.value == "remote_files") {
elements = uris.value;
selectionType = "remote_files";
} else if (sourceFrom.value == "pasted_table") {
elements = pasteData.value;
} else if (sourceFrom.value == "dataset_as_table") {
elements = tabularDatasetContents.value;
}
const entry: Entry = {
dataType: creatingWhat.value,
ftpUploadSite: props.ftpUploadSite,
selectionType: selectionType,
elements: elements,
};
Galaxy.currHistoryPanel.buildCollectionFromRules(entry, null, true);
}
function submit() {
if (sourceFrom.value == "collection") {
routeToTool("__APPLY_RULES__");
} else {
launchRuleBuilder();
}
emit("dismiss");
}
function setCreatingWhat(what: RulesCreatingWhat) {
creatingWhat.value = what;
}
function setSourceForm(newValue: RulesSourceFrom) {
sourceFrom.value = newValue;
}
</script>

<template>
<GenericWizard :use="wizard" :submit-button-label="importButtonLabel" @submit="submit">
<div v-if="wizard.isCurrent('select-what')">
<CreatingWhat :creating-what="creatingWhat" @onChange="setCreatingWhat" />
</div>
<div v-else-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
v-if="creatingWhat == 'collections'"
: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>
</GenericWizard>
</template>
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import _l from "utils/localization";
import Vue from "vue";

import { rawToTable } from "@/components/Collections/tables";

import { collectionCreatorModalSetup } from "./common/modal";

function ruleBasedCollectionCreatorModal(elements, elementsType, importType, options) {
@@ -58,22 +60,7 @@ function createCollectionViaRules(selection, defaultHideSourceItems = true) {
importType = selection.dataType || "collections";
elements = selection.elements;
} else {
const hasNonWhitespaceChars = RegExp(/[^\s]/);
// Have pasted data, data from a history dataset, or FTP list.
const lines = selection.content
.split(/[\n\r]/)
.filter((line) => line.length > 0 && hasNonWhitespaceChars.exec(line));
// Really poor tabular parser - we should get a library for this or expose options? I'm not
// sure.
let hasTabs = false;
if (lines.length > 0) {
const firstLine = lines[0];
if (firstLine.indexOf("\t") >= 0) {
hasTabs = true;
}
}
const regex = hasTabs ? /\t/ : /\s+/;
elements = lines.map((line) => line.split(regex));
elements = rawToTable(selection.content);
elementsType = selection.selectionType;
importType = selection.dataType || "collections";
}
61 changes: 61 additions & 0 deletions client/src/components/Collections/tables.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { computed, ref } from "vue";

export function useTableSummary() {
const rawValue = ref<string>("");

const table = computed(() => {
return rawToTable(rawValue.value);
});

const columnCount = computed<number>(() => {
const tableVal = table.value;
if (tableVal && tableVal.length) {
return tableVal[0]?.length || 0;
} else {
return 0;
}
});

const isJaggedData = computed<boolean>(() => {
const tableVal = table.value;
const columnCountVal = columnCount.value;
for (const row of tableVal) {
if (row.length != columnCountVal) {
return true;
}
}
return false;
});

const jaggedDataWarning = computed<string | undefined>(() => {
if (isJaggedData.value) {
return "This data contains a different number of columns per-row, this probably shouldn't be used as is.";
} else {
return undefined;
}
});
return {
rawValue,
isJaggedData,
jaggedDataWarning,
columnCount,
table,
};
}

export function rawToTable(content: string): string[][] {
const hasNonWhitespaceChars = RegExp(/[^\s]/);
// Have pasted data, data from a history dataset, or FTP list.
const lines = content.split(/[\n\r]/).filter((line) => line.length > 0 && hasNonWhitespaceChars.exec(line));
// Really poor tabular parser - we should get a library for this or expose options? I'm not
// sure.
let hasTabs = false;
if (lines.length > 0) {
const firstLine = lines[0];
if (firstLine && firstLine.indexOf("\t") >= 0) {
hasTabs = true;
}
}
const regex = hasTabs ? /\t/ : /\s+/;
return lines.map((line) => line.split(regex));
}
43 changes: 43 additions & 0 deletions client/src/components/Collections/wizard/CreatingWhat.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script setup lang="ts">
import { BCard, BCardGroup, BCardTitle } from "bootstrap-vue";
import { borderVariant } from "@/components/Common/Wizard/utils";
import { type RulesCreatingWhat } from "./types";
interface Props {
creatingWhat: RulesCreatingWhat;
}
const emit = defineEmits(["onChange"]);
defineProps<Props>();
</script>

<template>
<BCardGroup deck>
<BCard
data-creating-what="datasets"
class="wizard-selection-card"
:border-variant="borderVariant(creatingWhat === 'datasets')"
@click="emit('onChange', 'datasets')">
<BCardTitle>
<b>Datasets</b>
</BCardTitle>
<div>
This options lets you import any number of individual Galaxy datasets. These will be unique items in
your Galaxy history.
</div>
</BCard>
<BCard
data-creating-what="collections"
class="wizard-selection-card"
:border-variant="borderVariant(creatingWhat === 'collections')"
@click="emit('onChange', 'collections')">
<BCardTitle>
<b>Collections</b>
</BCardTitle>
<div>This options lets you create or more Galaxy dataset collections.</div>
</BCard>
</BCardGroup>
</template>
17 changes: 17 additions & 0 deletions client/src/components/Collections/wizard/JaggedDataAlert.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script setup lang="ts">
import { BAlert } from "bootstrap-vue";
interface Props {
jaggedDataWarning?: string;
}
defineProps<Props>();
</script>

<template>
<span>
<BAlert v-if="jaggedDataWarning" show variant="warning">
{{ jaggedDataWarning }}
</BAlert>
</span>
</template>
Loading

Unchanged files with check annotations Beta

<template>

Check warning on line 1 in client/src/components/Alert.vue

GitHub Actions / client-unit-test (18)

Component name "Alert" should always be multi-word
<b-alert :variant="galaxyKwdToBootstrap" :show="showP" v-bind="$props">
<!-- @slot Message to display in alert -->
<slot> {{ message }} </slot>
/** Display a close button in the alert that allows it to be dismissed */
dismissible: Boolean,
/** Label for the close button, for aria */
dismissLabel: String,

Check warning on line 35 in client/src/components/Alert.vue

GitHub Actions / client-unit-test (18)

Prop 'dismissLabel' requires default value to be set
/** If a number, number of seconds to show before dismissing */
show: [Boolean, Number],

Check warning on line 37 in client/src/components/Alert.vue

GitHub Actions / client-unit-test (18)

Prop 'show' requires default value to be set
/** Should the alert fade out */
fade: Boolean,
},
<template>

Check warning on line 1 in client/src/components/Annotation.vue

GitHub Actions / client-unit-test (18)

Component name "Annotation" should always be multi-word
<ClickToEdit
ref="annotationInput"
v-slot="{ toggleEdit, placeholder, stateValidator }"
<template>
<div>
{{ prefix }}
<span v-html="citationHtml" />

Check warning on line 41 in client/src/components/Citation/CitationItem.vue

GitHub Actions / client-unit-test (18)

'v-html' directive can lead to XSS attack
<a v-if="link" :href="link" target="_blank">
Visit Citation
</template>
<div v-if="source === 'histories'" class="infomessage">
<div v-html="config?.citations_export_message_html"></div>

Check warning on line 68 in client/src/components/Citation/CitationsList.vue

GitHub Actions / client-unit-test (18)

'v-html' directive can lead to XSS attack
</div>
<div class="citations-formatted">
extensions?: string[];
extensionsToggle?: boolean;
noItems?: boolean;
collectionType?: string;

Check warning on line 42 in client/src/components/Collections/common/CollectionCreator.vue

GitHub Actions / client-unit-test (18)

Prop 'collectionType' requires default value to be set
}
const props = withDefaults(defineProps<Props>(), {