mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge pull request #12387 from guerler/add_tables_to_pages
Display Tabular datasets as sortable tables, and PDF and HTML in embedded frames in Pages
This commit is contained in:
+48
-50
@@ -1,54 +1,52 @@
|
||||
<template>
|
||||
<div class="w-100 p-2">
|
||||
<b-card body-class="p-0">
|
||||
<b-card-header>
|
||||
<span class="float-right">
|
||||
<b-button
|
||||
:href="downloadUrl"
|
||||
variant="link"
|
||||
size="sm"
|
||||
role="button"
|
||||
title="Download Collection"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-download" />
|
||||
</b-button>
|
||||
<CurrentUser v-slot="{ user }">
|
||||
<UserHistories v-if="user" :user="user" v-slot="{ currentHistoryId }">
|
||||
<b-button
|
||||
v-if="currentHistoryId"
|
||||
@click="onCopyCollection(currentHistoryId)"
|
||||
href="#"
|
||||
role="button"
|
||||
variant="link"
|
||||
title="Import Collection"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-file-import" />
|
||||
</b-button>
|
||||
</UserHistories>
|
||||
</CurrentUser>
|
||||
</span>
|
||||
<span>
|
||||
<span>Dataset Collection:</span>
|
||||
<span class="font-weight-light">{{ collectionName }}</span>
|
||||
</span>
|
||||
</b-card-header>
|
||||
<b-card-body>
|
||||
<LoadingSpan v-if="loading" message="Loading Collection" />
|
||||
<div v-else class="content-height">
|
||||
<b-alert v-if="!!messageText" :variant="messageVariant" show>
|
||||
{{ messageText }}
|
||||
</b-alert>
|
||||
<CollectionTree :node="itemContent" :skip-head="true" />
|
||||
</div>
|
||||
</b-card-body>
|
||||
</b-card>
|
||||
</div>
|
||||
<b-card body-class="p-0">
|
||||
<b-card-header>
|
||||
<span class="float-right">
|
||||
<b-button
|
||||
:href="downloadUrl"
|
||||
variant="link"
|
||||
size="sm"
|
||||
role="button"
|
||||
title="Download Collection"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-download" />
|
||||
</b-button>
|
||||
<CurrentUser v-slot="{ user }">
|
||||
<UserHistories v-if="user" :user="user" v-slot="{ currentHistoryId }">
|
||||
<b-button
|
||||
v-if="currentHistoryId"
|
||||
@click="onCopyCollection(currentHistoryId)"
|
||||
href="#"
|
||||
role="button"
|
||||
variant="link"
|
||||
title="Import Collection"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-file-import" />
|
||||
</b-button>
|
||||
</UserHistories>
|
||||
</CurrentUser>
|
||||
</span>
|
||||
<span>
|
||||
<span>Dataset Collection:</span>
|
||||
<span class="font-weight-light">{{ collectionName }}</span>
|
||||
</span>
|
||||
</b-card-header>
|
||||
<b-card-body>
|
||||
<LoadingSpan v-if="loading" message="Loading Collection" />
|
||||
<div v-else class="content-height">
|
||||
<b-alert v-if="!!messageText" :variant="messageVariant" show>
|
||||
{{ messageText }}
|
||||
</b-alert>
|
||||
<CollectionTree :node="itemContent" :skip-head="true" />
|
||||
</div>
|
||||
</b-card-body>
|
||||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,58 +1,91 @@
|
||||
<template>
|
||||
<div class="w-100 p-2">
|
||||
<b-card body-class="p-0">
|
||||
<b-card-header v-if="!embedded">
|
||||
<span class="float-right">
|
||||
<b-button
|
||||
:href="downloadUrl"
|
||||
variant="link"
|
||||
size="sm"
|
||||
role="button"
|
||||
title="Download Dataset"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-download" />
|
||||
</b-button>
|
||||
<b-button
|
||||
:href="importUrl"
|
||||
role="button"
|
||||
variant="link"
|
||||
title="Import Dataset"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-file-import" />
|
||||
</b-button>
|
||||
</span>
|
||||
<span>
|
||||
<span>Dataset:</span>
|
||||
<span class="font-weight-light">{{ datasetName }}</span>
|
||||
</span>
|
||||
</b-card-header>
|
||||
<b-card-body>
|
||||
<b-card body-class="p-0">
|
||||
<b-card-header v-if="!embedded">
|
||||
<span class="float-right">
|
||||
<b-button
|
||||
:href="downloadUrl"
|
||||
variant="link"
|
||||
size="sm"
|
||||
role="button"
|
||||
title="Download Dataset"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-download" />
|
||||
</b-button>
|
||||
<b-button
|
||||
:href="importUrl"
|
||||
role="button"
|
||||
variant="link"
|
||||
title="Import Dataset"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-file-import" />
|
||||
</b-button>
|
||||
</span>
|
||||
<span>
|
||||
<span>Dataset:</span>
|
||||
<span class="font-weight-light">{{ datasetName }}</span>
|
||||
</span>
|
||||
</b-card-header>
|
||||
<b-card-body>
|
||||
<UrlDataProvider :url="itemUrl" v-slot="{ result: itemContent, loading, error }">
|
||||
<LoadingSpan v-if="loading" message="Loading Dataset" />
|
||||
<div v-else-if="error">{{ error }}</div>
|
||||
<div v-else class="embedded-dataset content-height">
|
||||
<pre v-if="itemContent.item_data">
|
||||
<code class="text-normalwrap">{{ itemContent.item_data }}</code>
|
||||
</pre>
|
||||
<div v-else>No content found.</div>
|
||||
<b-link v-if="itemContent.truncated" :href="itemContent.item_url"> Show More... </b-link>
|
||||
<UrlDataProvider :url="datatypesUrl" v-slot="{ result: datatypesModel, loading: datatypesLoading }">
|
||||
<LoadingSpan v-if="datatypesLoading" message="Loading Datatypes" />
|
||||
<div v-else>
|
||||
<b-embed
|
||||
v-if="isSubTypeOfAny(datasetType, ['pdf', 'html'], datatypesModel)"
|
||||
type="iframe"
|
||||
aspect="16by9"
|
||||
:src="displayUrl"
|
||||
/>
|
||||
<div v-else-if="itemContent.item_data">
|
||||
<div v-if="isSubTypeOfAny(datasetType, ['tabular'], datatypesModel)">
|
||||
<UrlDataProvider
|
||||
:url="metaUrl"
|
||||
v-slot="{ result: metaData, loading: metaLoading, error: metaError }"
|
||||
>
|
||||
<LoadingSpan v-if="metaLoading" message="Loading Metadata" />
|
||||
<div v-else-if="metaError">{{ metaError }}</div>
|
||||
<b-table
|
||||
v-else
|
||||
striped
|
||||
hover
|
||||
:fields="getFields(metaData)"
|
||||
:items="getItems(itemContent.item_data, metaData)"
|
||||
/>
|
||||
</UrlDataProvider>
|
||||
</div>
|
||||
<pre v-else>
|
||||
<code class="text-normalwrap">{{ itemContent.item_data }}</code>
|
||||
</pre>
|
||||
</div>
|
||||
<div v-else>No content found.</div>
|
||||
<b-link v-if="itemContent.truncated" :href="itemContent.item_url"> Show More... </b-link>
|
||||
</div>
|
||||
</UrlDataProvider>
|
||||
</div>
|
||||
</b-card-body>
|
||||
</b-card>
|
||||
</div>
|
||||
</UrlDataProvider>
|
||||
</b-card-body>
|
||||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
import LoadingSpan from "components/LoadingSpan";
|
||||
import axios from "axios";
|
||||
import { UrlDataProvider } from "components/providers/UrlDataProvider";
|
||||
import { DatatypesMapperModel } from "components/Datatypes/model";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
LoadingSpan,
|
||||
UrlDataProvider,
|
||||
},
|
||||
props: {
|
||||
args: {
|
||||
@@ -68,47 +101,81 @@ export default {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
itemContent: null,
|
||||
loading: true,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getContent().then((data) => {
|
||||
this.itemContent = data;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
datasetType() {
|
||||
const dataset = this.datasets[this.args.history_dataset_id];
|
||||
return dataset.ext;
|
||||
},
|
||||
datasetName() {
|
||||
const dataset = this.datasets[this.args.history_dataset_id];
|
||||
return dataset && dataset.name;
|
||||
},
|
||||
datatypesUrl() {
|
||||
return "api/datatypes/types_and_mapping";
|
||||
},
|
||||
downloadUrl() {
|
||||
return `${getAppRoot()}dataset/display?dataset_id=${this.args.history_dataset_id}`;
|
||||
},
|
||||
displayUrl() {
|
||||
return `${getAppRoot()}datasets/${this.args.history_dataset_id}/display`;
|
||||
},
|
||||
importUrl() {
|
||||
return `${getAppRoot()}dataset/imp?dataset_id=${this.args.history_dataset_id}`;
|
||||
},
|
||||
itemUrl() {
|
||||
return `${getAppRoot()}api/datasets/${this.args.history_dataset_id}/get_content_as_text`;
|
||||
return `api/datasets/${this.args.history_dataset_id}/get_content_as_text`;
|
||||
},
|
||||
metaUrl() {
|
||||
return `api/datasets/${this.args.history_dataset_id}`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async getContent() {
|
||||
try {
|
||||
const response = await axios.get(this.itemUrl);
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
return `Failed to retrieve content. ${e}`;
|
||||
isSubTypeOfAny(child, parents, datatypesModel) {
|
||||
const datatypesMapper = new DatatypesMapperModel(datatypesModel);
|
||||
return datatypesMapper.isSubTypeOfAny(child, parents);
|
||||
},
|
||||
getFields(metaData) {
|
||||
const fields = [];
|
||||
const columnNames = metaData.metadata_column_names || [];
|
||||
const columnCount = metaData.metadata_columns;
|
||||
for (let i = 0; i < columnCount; i++) {
|
||||
fields.push({
|
||||
key: `${i}`,
|
||||
label: columnNames[i] || i,
|
||||
sortable: true,
|
||||
});
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
getItems(textData, metaData) {
|
||||
const tableData = [];
|
||||
const delimiter = metaData.metadata_delimiter || "\t";
|
||||
const comments = metaData.metadata_comment_lines || 0;
|
||||
const lines = textData.split("\n");
|
||||
lines.forEach((line, i) => {
|
||||
if (i >= comments) {
|
||||
const tabs = line.split(delimiter);
|
||||
const rowData = {};
|
||||
let hasData = false;
|
||||
tabs.forEach((cellData, j) => {
|
||||
const cellDataTrimmed = cellData.trim();
|
||||
if (cellDataTrimmed) {
|
||||
hasData = true;
|
||||
}
|
||||
rowData[j] = cellDataTrimmed;
|
||||
});
|
||||
if (hasData) {
|
||||
tableData.push(rowData);
|
||||
}
|
||||
}
|
||||
});
|
||||
return tableData;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.content-height {
|
||||
max-height: 15rem;
|
||||
max-height: 20rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<div class="w-100 p-2">
|
||||
<b-card nobody>
|
||||
<JobMetrics class="job-metrics" :job-id="args.job_id" />
|
||||
</b-card>
|
||||
</div>
|
||||
<b-card nobody>
|
||||
<JobMetrics class="job-metrics" :job-id="args.job_id" />
|
||||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<div class="w-100 p-2">
|
||||
<b-card nobody>
|
||||
<JobParameters class="job-parameters" :job-id="args.job_id" :param="args.param" :include-title="false" />
|
||||
</b-card>
|
||||
</div>
|
||||
<b-card nobody>
|
||||
<JobParameters class="job-parameters" :job-id="args.job_id" :param="args.param" :include-title="false" />
|
||||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<template>
|
||||
<div class="w-100 p-2">
|
||||
<b-card nobody class="content-height">
|
||||
<div :class="name" :job_id="args.job_id">
|
||||
<pre><code class="text-normalwrap">{{ jobContent }}</code></pre>
|
||||
</div>
|
||||
</b-card>
|
||||
</div>
|
||||
<b-card nobody class="content-height">
|
||||
<div :class="name" :job_id="args.job_id">
|
||||
<pre><code class="text-normalwrap">{{ jobContent }}</code></pre>
|
||||
</div>
|
||||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<template>
|
||||
<div class="w-100 p-2">
|
||||
<b-card body-class="embed-responsive embed-responsive-4by3">
|
||||
<LoadingSpan v-if="loading" class="m-2" message="Loading Visualization" />
|
||||
<div v-else-if="error" class="m-2">{{ error }}</div>
|
||||
<iframe v-else class="embed-responsive-item" :src="visualizationUrl" />
|
||||
</b-card>
|
||||
</div>
|
||||
<b-card body-class="embed-responsive embed-responsive-4by3">
|
||||
<LoadingSpan v-if="loading" class="m-2" message="Loading Visualization" />
|
||||
<div v-else-if="error" class="m-2">{{ error }}</div>
|
||||
<iframe v-else class="embed-responsive-item" :src="visualizationUrl" />
|
||||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,48 +1,46 @@
|
||||
<template>
|
||||
<div class="w-100 p-2">
|
||||
<b-card body-class="p-0">
|
||||
<b-card-header v-if="!embedded">
|
||||
<span class="float-right">
|
||||
<b-button
|
||||
:href="downloadUrl"
|
||||
variant="link"
|
||||
size="sm"
|
||||
role="button"
|
||||
title="Download Workflow"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-download" />
|
||||
</b-button>
|
||||
<b-button
|
||||
:href="importUrl"
|
||||
role="button"
|
||||
variant="link"
|
||||
title="Import Workflow"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-file-import" />
|
||||
</b-button>
|
||||
</span>
|
||||
<span>
|
||||
<span>Workflow:</span>
|
||||
<span class="font-weight-light">{{ workflowName }}</span>
|
||||
</span>
|
||||
</b-card-header>
|
||||
<b-card-body>
|
||||
<LoadingSpan v-if="loading" message="Loading Workflow" />
|
||||
<div v-else class="content-height">
|
||||
<div v-for="step in itemContent.steps" :key="step.order_index" class="mb-2">
|
||||
<div>Step {{ step.order_index + 1 }}: {{ step.label }}</div>
|
||||
<WorkflowTree :input="step" :skip-head="true" />
|
||||
</div>
|
||||
<b-card body-class="p-0">
|
||||
<b-card-header v-if="!embedded">
|
||||
<span class="float-right">
|
||||
<b-button
|
||||
:href="downloadUrl"
|
||||
variant="link"
|
||||
size="sm"
|
||||
role="button"
|
||||
title="Download Workflow"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-download" />
|
||||
</b-button>
|
||||
<b-button
|
||||
:href="importUrl"
|
||||
role="button"
|
||||
variant="link"
|
||||
title="Import Workflow"
|
||||
type="button"
|
||||
class="py-0 px-1"
|
||||
v-b-tooltip.hover
|
||||
>
|
||||
<span class="fa fa-file-import" />
|
||||
</b-button>
|
||||
</span>
|
||||
<span>
|
||||
<span>Workflow:</span>
|
||||
<span class="font-weight-light">{{ workflowName }}</span>
|
||||
</span>
|
||||
</b-card-header>
|
||||
<b-card-body>
|
||||
<LoadingSpan v-if="loading" message="Loading Workflow" />
|
||||
<div v-else class="content-height">
|
||||
<div v-for="step in itemContent.steps" :key="step.order_index" class="mb-2">
|
||||
<div>Step {{ step.order_index + 1 }}: {{ step.label }}</div>
|
||||
<WorkflowTree :input="step" :skip-head="true" />
|
||||
</div>
|
||||
</b-card-body>
|
||||
</b-card>
|
||||
</div>
|
||||
</div>
|
||||
</b-card-body>
|
||||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
</div>
|
||||
</b-alert>
|
||||
</div>
|
||||
<div v-for="(obj, index) in markdownObjects" :key="index">
|
||||
<div v-for="(obj, index) in markdownObjects" :key="index" class="markdown-components">
|
||||
<p v-if="obj.name == 'default'" v-html="obj.content" class="text-justify m-2" />
|
||||
<div v-else-if="obj.name == 'generate_galaxy_version'" class="galaxy-version">
|
||||
<pre><code>{{ getVersion }}</code></pre>
|
||||
|
||||
@@ -21,6 +21,7 @@ export const SingleQueryProvider = (lookup) => {
|
||||
data() {
|
||||
return {
|
||||
result: undefined,
|
||||
error: undefined,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -47,6 +48,8 @@ export const SingleQueryProvider = (lookup) => {
|
||||
this.result = result;
|
||||
},
|
||||
(err) => {
|
||||
this.result = {};
|
||||
this.error = err;
|
||||
this.$emit("error", err);
|
||||
}
|
||||
);
|
||||
@@ -55,6 +58,7 @@ export const SingleQueryProvider = (lookup) => {
|
||||
return this.$scopedSlots.default({
|
||||
loading: this.loading,
|
||||
result: this.result,
|
||||
error: this.error,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -12,3 +12,10 @@
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.markdown-wrapper {
|
||||
@extend .px-4;
|
||||
.markdown-components {
|
||||
@extend .py-2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,10 +270,11 @@ class ReadyForExportMarkdownDirectiveHandler(GalaxyInternalMarkdownDirectiveHand
|
||||
self.ensure_rendering_data_for("history_datasets", obj)[key] = val or default_val
|
||||
|
||||
def handle_dataset_display(self, line, hda):
|
||||
self.extend_history_dataset_rendering_data(hda, "name", hda.name, "")
|
||||
self.handle_dataset_name(line, hda)
|
||||
self.handle_dataset_type(line, hda)
|
||||
|
||||
def handle_dataset_embedded(self, line, hda):
|
||||
self.extend_history_dataset_rendering_data(hda, "name", hda.name, "")
|
||||
self.handle_dataset_name(line, hda)
|
||||
|
||||
def handle_dataset_peek(self, line, hda):
|
||||
self.extend_history_dataset_rendering_data(hda, "peek", hda.peek, "*No Dataset Peek Available*")
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
<div class="unified-panel-body">
|
||||
<div style="overflow: auto; height: 100%;">
|
||||
<div class="page-body">
|
||||
<div class="page-body p-3">
|
||||
<div style="float: right">
|
||||
${self.render_item_links( item )}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user