mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge branch 'release_21.09' into dev
This commit is contained in:
@@ -73,12 +73,12 @@ describe("Invocations.vue with invocation", () => {
|
||||
expect(rows.length).toBe(1);
|
||||
const row = rows[0];
|
||||
const columns = row.findAll("td");
|
||||
expect(columns.at(0).text()).toBe("workflow name");
|
||||
expect(columns.at(1).text()).toBe("history name");
|
||||
expect(columns.at(2).text()).toBe(moment.utc(invocationData.create_time).fromNow());
|
||||
expect(columns.at(3).text()).toBe(moment.utc(invocationData.update_time).fromNow());
|
||||
expect(columns.at(4).text()).toBe("scheduled");
|
||||
expect(columns.at(5).text()).toBe("");
|
||||
expect(columns.at(1).text()).toBe("workflow name");
|
||||
expect(columns.at(2).text()).toBe("history name");
|
||||
expect(columns.at(3).text()).toBe(moment.utc(invocationData.create_time).fromNow());
|
||||
expect(columns.at(4).text()).toBe(moment.utc(invocationData.update_time).fromNow());
|
||||
expect(columns.at(5).text()).toBe("scheduled");
|
||||
expect(columns.at(6).text()).toBe("");
|
||||
});
|
||||
|
||||
it("toggles detail rendering", async () => {
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
striped
|
||||
caption-top
|
||||
:busy="loading"
|
||||
fixed>
|
||||
fixed
|
||||
class="invocations-table">
|
||||
<template v-slot:row-details="row">
|
||||
<b-card>
|
||||
<small class="float-right" :data-invocation-id="row.item.id">
|
||||
@@ -31,25 +32,39 @@
|
||||
@invocation-cancelled="$emit('reload-invocations')" />
|
||||
</b-card>
|
||||
</template>
|
||||
<template v-slot:cell(workflow_id)="data">
|
||||
<template v-slot:cell(expand)="data">
|
||||
<b-link
|
||||
class="toggle-invocation-details"
|
||||
v-b-tooltip
|
||||
title="Show Invocation details"
|
||||
href="#"
|
||||
@click.stop="swapRowDetails(data)">
|
||||
<b>{{ getWorkflowNameByInstanceId(data.item.workflow_id) }}</b>
|
||||
</b-link>
|
||||
v-b-tooltip.hover.top
|
||||
title="Show Invocation Details"
|
||||
class="btn-sm fa fa-chevron-down toggle-invocation-details"
|
||||
v-if="!data.detailsShowing"
|
||||
@click.stop="swapRowDetails(data)" />
|
||||
<b-link
|
||||
v-b-tooltip.hover.top
|
||||
title="Hide Invocation Details"
|
||||
class="btn-sm fa fa-chevron-up toggle-invocation-details"
|
||||
v-if="data.detailsShowing"
|
||||
@click.stop="swapRowDetails(data)" />
|
||||
</template>
|
||||
<template v-slot:cell(workflow_id)="data">
|
||||
<div
|
||||
v-b-tooltip.hover.top
|
||||
:title="getWorkflowNameByInstanceId(data.item.workflow_id)"
|
||||
class="truncate">
|
||||
<b-link href="#" @click.stop="swapRowDetails(data)">
|
||||
<b>{{ getWorkflowNameByInstanceId(data.item.workflow_id) }}</b>
|
||||
</b-link>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:cell(history_id)="data">
|
||||
<b-link
|
||||
id="switch-to-history"
|
||||
v-b-tooltip
|
||||
title="Switch to History"
|
||||
href="#"
|
||||
@click.stop="switchHistory(data.item.history_id)">
|
||||
<b>{{ getHistoryNameById(data.item.history_id) }}</b>
|
||||
</b-link>
|
||||
<div
|
||||
v-b-tooltip.hover.top.html
|
||||
:title="`<b>Switch to History:</b><br>${getHistoryNameById(data.item.history_id)}`"
|
||||
class="truncate">
|
||||
<b-link id="switch-to-history" href="#" @click.stop="switchHistory(data.item.history_id)">
|
||||
<b>{{ getHistoryNameById(data.item.history_id) }}</b>
|
||||
</b-link>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:cell(create_time)="data">
|
||||
<UtcDate :date="data.value" mode="elapsed" />
|
||||
@@ -94,12 +109,13 @@ export default {
|
||||
},
|
||||
data() {
|
||||
const fields = [
|
||||
{ key: "workflow_id", label: "Workflow" },
|
||||
{ key: "history_id", label: "History" },
|
||||
{ key: "create_time", label: "Invoked" },
|
||||
{ key: "update_time", label: "Updated" },
|
||||
{ key: "state" },
|
||||
{ key: "execute", label: "" },
|
||||
{ key: "expand", label: "", class: "col-button" },
|
||||
{ key: "workflow_id", label: "Workflow", class: "col-name" },
|
||||
{ key: "history_id", label: "History", class: "col-history" },
|
||||
{ key: "create_time", label: "Invoked", class: "col-small" },
|
||||
{ key: "update_time", label: "Updated", class: "col-small" },
|
||||
{ key: "state", class: "col-small" },
|
||||
{ key: "execute", label: "", class: "col-button" },
|
||||
];
|
||||
return {
|
||||
invocationItemsModel: [],
|
||||
@@ -145,3 +161,25 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.invocations-table {
|
||||
min-width: 40rem;
|
||||
}
|
||||
.table::v-deep .col-name {
|
||||
width: 40%;
|
||||
}
|
||||
.table::v-deep .col-history {
|
||||
width: 20%;
|
||||
}
|
||||
.table::v-deep .col-small {
|
||||
width: 100px;
|
||||
}
|
||||
.table::v-deep .col-button {
|
||||
width: 50px;
|
||||
}
|
||||
.table::v-deep .truncate {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,6 +2,8 @@ import logging
|
||||
import re
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.sql import select
|
||||
from sqlalchemy.sql.expression import func
|
||||
|
||||
@@ -245,7 +247,18 @@ class TagHandler:
|
||||
return self.sa_session.query(galaxy.model.Tag).filter_by(name=tag_name).first()
|
||||
|
||||
def _create_tag_instance(self, tag_name):
|
||||
return galaxy.model.Tag(type=0, name=tag_name)
|
||||
# For good performance caller should first check if there's already an appropriate tag
|
||||
Session = sessionmaker(self.sa_session.bind)
|
||||
tag = galaxy.model.Tag(type=0, name=tag_name)
|
||||
with Session() as separate_session:
|
||||
separate_session.add(tag)
|
||||
try:
|
||||
separate_session.commit()
|
||||
separate_session.flush()
|
||||
except IntegrityError:
|
||||
# tag already exists, get from database
|
||||
separate_session.rollback()
|
||||
return self._get_tag(tag_name)
|
||||
|
||||
def _get_or_create_tag(self, tag_str):
|
||||
"""Get or create a Tag object from a tag string."""
|
||||
|
||||
@@ -100,6 +100,12 @@ class TagHandlerTestCase(BaseTestCase):
|
||||
self.tag_handler.delete_item_tags(user=self.user, item=hda)
|
||||
self.assertEqual(hda.tags, [])
|
||||
|
||||
def test_unique_constraint_applied(self):
|
||||
tag_name = 'abc'
|
||||
tag = self.tag_handler._create_tag_instance(tag_name)
|
||||
same_tag = self.tag_handler._create_tag_instance(tag_name)
|
||||
assert tag.id == same_tag.id
|
||||
|
||||
def test_item_has_tag(self):
|
||||
hda = self._create_vanilla_hda()
|
||||
tags = ['tag1']
|
||||
|
||||
Reference in New Issue
Block a user