Commit 54927128 authored by anton's avatar anton

Update from release_2_2

parents ea925350 f4867688
......@@ -10,7 +10,36 @@ and this project adheres to
## [Unreleased]
No changes.
### Added
- Duplicate a Timeline on its `edit` page
### Fixed
- Swimlane breaks when loading improperly formatted Annotations
## [2.2.1] - 2020-07-23
### Added
- Build time environment variable `UI_COLOR_HASH_SHADE` (default: '100')
- Build time environment variable `UI_HIDE_GROUPS` (default: false)
- Build time environment variable `USE_GENERIC_ANNOTATION` (default: false)
### Changed
- Router does not execute checkSession on `users.callback` route
- Default route for `/piecemaker` redirects conditionally based
on `USE_GENERIC_ANNOTATION`
- Navigation honors `USE_GENERIC_ANNOTATION` build var
### Fixed
- Redundant grouping in `SwimLane` component when annotation types are undefined
- Annotation sort order on `piecemaker.media.annotate_generic` screen
- `piecemaker.media.annotate_generic` screen shows component display options
## [2.2.0] - 2020-06-22
......@@ -362,7 +391,7 @@ module
lots of annotations need to be loaded
- Delete map no longer fails when encountering access
denied errors (still suffers from
[#119](https://gitlab.rlp.net/motionbank/systems-frontend/issues/119))
[#119](https://gitlab.rlp.net/motionbank/applications/systems-frontend/issues/119))
### Removed
......@@ -417,7 +446,7 @@ AnnotationList)
(works from version 15+)
- Perform date related queries to MongoDB with
properly formatted timezones (see:
[#106](https://gitlab.rlp.net/motionbank/systems-frontend/issues/106))
[#106](https://gitlab.rlp.net/motionbank/applications/systems-frontend/issues/106))
### Changed
......@@ -500,25 +529,26 @@ of a video cannot be retrieved
- Start proper versioning at 1.0.0
[Unreleased]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v2.2.0...release_2_2
[2.2.0]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v2.1.2...v2.2.0
[2.1.2]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v2.1.1...v2.1.2
[2.1.1]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v2.1.0...v2.1.1
[2.1.0]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v2.0.0...v2.1.0
[2.0.0]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.3.10...v2.0.0
[1.3.10]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.3.9...v1.3.10
[1.3.9]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.3.8...v1.3.9
[1.3.8]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.3.7...v1.3.8
[1.3.7]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.3.6...v1.3.7
[1.3.6]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.3.5...v1.3.6
[1.3.5]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.3.4...v1.3.5
[1.3.4]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.3.3...v1.3.4
[1.3.3]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.3.2...v1.3.3
[1.3.2]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.3.1...v1.3.2
[1.3.1]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.3.0...v1.3.1
[1.3.0]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.2.1...v1.3.0
[1.2.1]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.2.0...v1.2.1
[1.2.0]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.1.1...v1.2.0
[1.1.1]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.1.0...v1.1.1
[1.1.0]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/v1.0.0...v1.1.0
[1.0.0]: https://gitlab.rlp.net/motionbank/systems-frontend/compare/initial...v1.0.0
[Unreleased]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v2.2.1...release_2_2
[2.2.1]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v2.2.0...v2.2.1
[2.2.0]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v2.1.2...v2.2.0
[2.1.2]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v2.1.1...v2.1.2
[2.1.1]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v2.1.0...v2.1.1
[2.1.0]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v2.0.0...v2.1.0
[2.0.0]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.3.10...v2.0.0
[1.3.10]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.3.9...v1.3.10
[1.3.9]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.3.8...v1.3.9
[1.3.8]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.3.7...v1.3.8
[1.3.7]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.3.6...v1.3.7
[1.3.6]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.3.5...v1.3.6
[1.3.5]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.3.4...v1.3.5
[1.3.4]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.3.3...v1.3.4
[1.3.3]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.3.2...v1.3.3
[1.3.2]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.3.1...v1.3.2
[1.3.1]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.3.0...v1.3.1
[1.3.0]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.2.1...v1.3.0
[1.2.1]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.2.0...v1.2.1
[1.2.0]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.1.1...v1.2.0
[1.1.1]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.1.0...v1.1.1
[1.1.0]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/v1.0.0...v1.1.0
[1.0.0]: https://gitlab.rlp.net/motionbank/applications/systems-frontend/compare/initial...v1.0.0
{
"name": "systems-frontend",
"version": "2.2.0",
"version": "2.2.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......
{
"name": "systems-frontend",
"version": "2.2.0",
"version": "2.2.2",
"description": "Combined frontend project for Motion Bank web services",
"productName": "Motion Bank Systems Frontend",
"cordovaId": "org.motionbank.frontend",
......
......@@ -139,6 +139,7 @@ module.exports = function (ctx) {
APP_VERSION: JSON.stringify(getVersion()),
BUILD_TIME: JSON.stringify(Date.now()),
USE_RESOURCE_CACHE: JSON.stringify(process.env.USE_RESOURCE_CACHE || false),
USE_GENERIC_ANNOTATION: JSON.stringify(process.env.USE_GENERIC_ANNOTATION || false),
UI_VERSION: JSON.stringify(process.env.UI_VERSION || require('./package.json').version),
FLUENTFFMPEG_COV: JSON.stringify(false),
//
......@@ -155,8 +156,10 @@ module.exports = function (ctx) {
USE_TAGS: JSON.stringify(process.env.USE_TAGS || true),
USE_METADATA: JSON.stringify(process.env.USE_TAGS || true),
USE_CUSTOM_MEDIA_STORE: JSON.stringify(process.env.USE_CUSTOM_MEDIA_STORE || false),
UI_COLOR_HASH_SHADE: JSON.stringify(process.env.UI_COLOR_HASH_SHADE || '100'),
UI_HIDE_MOSYS: JSON.stringify(process.env.UI_HIDE_MOSYS || false),
UI_HIDE_DOCUMENTS: JSON.stringify(process.env.UI_HIDE_DOCUMENTS || false),
UI_HIDE_GROUPS: JSON.stringify(process.env.UI_HIDE_GROUPS || false),
MODULE_PROVIDER: JSON.stringify(process.env.MODULE_PROVIDER || null)
}
},
......
<template lang="pug">
q-modal(v-model="showModal", minimized)
.bg-dark.q-pa-md.text-center
.q-py-md {{ $t('labels.duplicate_timeline_title') }}
q-input(v-model="title", dark)
.q-mt-md
q-btn.q-mx-xs(color="primary", @click="confirm") {{ $t('buttons.duplicate_timeline') }}
q-btn.q-mx-xs(color="faded", @click="clear") {{ $t('buttons.cancel') }}
</template>
<script>
export default {
name: 'DuplicateTimelineModal',
data () {
return {
showModal: false,
title: undefined
}
},
methods: {
show (title) {
this.showModal = true
this.title = title
},
clear () {
this.showModal = false
this.title = undefined
},
confirm () {
this.$emit('confirm', this.title)
this.clear()
}
}
}
</script>
<style scoped lanhg="stylus">
</style>
......@@ -55,7 +55,7 @@
watch: {
},
methods: {
getLabel (val) {
getLabel (val = '') {
let valMatch = val.match(/[A-Z][a-z]+|[0-9]+/g)
if (valMatch !== null) {
if (this.useLabels) {
......
......@@ -56,7 +56,10 @@
methods: {
checkAnnotationType () {
if (this.selectedAnnotation !== null && this.selectedAnnotation !== undefined) {
return this.selectedAnnotation.body.type
if (this.selectedAnnotation.body.type && this.selectedAnnotation.body.type.indexOf('SpecificResource') > -1) {
return this.selectedAnnotation.body.source.type
}
else return this.selectedAnnotation.body.type
}
},
getAnnotationText (val) {
......@@ -67,14 +70,8 @@
case 'TextualBody':
this.annotationText = val.body.value
break
case 'Video':
this.annotationText = val.body.source.id
break
case 'VocabularyEntry':
this.annotationText = val.body.source.id
break
default:
this.annotationText = 'unknown'
this.annotationText = val.body.source.id || 'unknown'
break
}
}
......
......@@ -323,13 +323,21 @@
if (this.annotations) {
if (this.groupAnnotationsBy === 'type') {
groups = this.annotations.reduce((sum, annotation) => {
const type = annotation.body.type || annotation.body.source.type
if (sum.indexOf(type) === -1) sum.push(type)
if (annotation.body) {
const type = typeof annotation.body.type === 'string' && annotation.body.type.indexOf('SpecificResource') > -1
? annotation.body.source.type : annotation.body.type
if (sum.indexOf(type) === -1) sum.push(type)
}
return sum
}, [])
for (let group of groups) {
filtered[group] = this.annotations.filter(annotation => annotation.body.type === group ||
annotation.body.source.type === group)
filtered[group] = this.annotations.filter(annotation => {
if (annotation.body) {
return (typeof annotation.body.type === 'string' && annotation.body.type.indexOf('SpecificResource') > -1
? annotation.body.source.type : annotation.body.type) === group
}
return false
})
}
}
else if (this.groupAnnotationsBy === 'creator') {
......
Subproject commit 379ed2b44384f666567f8d101079201cb40d2a0f
Subproject commit 2ad1d1328d6418dd2bf664ee04030bdb82fa30db
......@@ -31,6 +31,7 @@ export default {
download_package: 'Download Package',
download: 'Download',
done: 'Done',
duplicate_timeline: 'Duplicate Timeline',
edit: 'Edit',
export_grid: 'Export Grid',
export_timeline: 'Export Timeline',
......@@ -129,7 +130,8 @@ export default {
editing_forbidden: 'You are not allowed to edit this item.',
annotate_timeline_forbidden: 'You are not allowed to annotate this Timeline.',
media_could_not_be_accessed: 'The supplied media URL could not be accessed.',
access_to_media_denied: 'Access to the media URL was denied.'
access_to_media_denied: 'Access to the media URL was denied.',
duplicate_timeline_failed: 'Duplicate Timeline failed: {error}'
},
labels: {
rejected: 'Rejected.',
......@@ -152,6 +154,7 @@ export default {
author: 'Author',
creator: 'Creator',
duration_seconds: 'Duration (s)',
duplicate_timeline_title: 'Duplicate Timeline title',
biovision_hierarchy: 'Biovision Hierarchy',
anonymous_creator: 'Anonymous',
unknown_creator: 'Unknown',
......@@ -249,6 +252,7 @@ export default {
submit_success: 'Submission successful',
timeline_imported: 'Timeline imported successfully',
timeline_deleted: 'Timeline deleted',
timeline_duplicated: 'Timeline duplicated successfully',
grid_imported: 'Grid imported successfully',
grid_deleted: 'Grid deleted',
confirm_delete: 'Delete this item?',
......
......@@ -6,7 +6,7 @@ const getAnnotationColor = annotation => {
let type = annotation.body.source ? annotation.body.source.type : undefined
type = type || annotation.body.type
type = type && type.indexOf('#') > -1 ? type.split('#').pop() : type
return toMaterialStyle(type || 'SpecificResource', '100')
return toMaterialStyle(type || 'SpecificResource', process.env.UI_COLOR_HASH_SHADE)
}
export {
......
......@@ -321,7 +321,8 @@
try {
// this.annotations = await this.$store.dispatch('queue/enqueue',
// this.$store.dispatch('annotations/find', this.media.body.source.id))
this.annotations = await this.$store.dispatch('annotations/find', this.media.body.source.id)
this.annotations = (await this.$store.dispatch('annotations/find', this.media.body.source.id))
.sort(this.$sort.onRef)
}
catch (err) {
this.$handleError(this, err, 'errors.list_annotations_failed')
......
<template lang="pug">
full-screen
duplicate-timeline-modal(ref="duplicateModal", @confirm="duplicateTimeline")
// --------------------------------------------------------------------------------------------------- edit timeline
content-block(:position="'first'")
......@@ -9,6 +11,9 @@
form-main(v-if="acl.put", v-model="payload", :schema="schema")
//
div(slot="form-buttons-add", :class="{'full-width row q-mb-sm': isMobile}")
q-btn.col(v-if="$route.params.uuid", slot="form-buttons-add",
:label="$t('buttons.duplicate_timeline')", @click="showDuplicateModal",
color="grey", :class="[!isMobile ? 'q-mr-sm' : '']")
q-btn.col(v-if="$route.params.uuid", slot="form-buttons-add",
:label="exportLabel", @click="exportTimeline",
color="grey", :class="[!isMobile ? 'q-mr-sm' : '']")
......@@ -39,6 +44,7 @@
import { openURL } from 'quasar'
import { mapGetters } from 'vuex'
import PageSubNav from '../../../components/shared/navigation/PageSubNav'
import DuplicateTimelineModal from '../../../components/piecemaker/modals/DuplicateTimelineModal'
export default {
components: {
......@@ -49,7 +55,8 @@
Tags,
ContentBlock,
ContentParagraph,
Permissions
Permissions,
DuplicateTimelineModal
},
data () {
const _this = this
......@@ -108,6 +115,75 @@
})
},
methods: {
showDuplicateModal () {
this.$refs.duplicateModal.show(this.timeline.title + ' Copy')
},
async duplicateTimeline (title) {
console.log('duplicate as', title, this.timeline)
if (!title || !this.timeline) return
this.$q.loading.show()
try {
const timeline = await this.$store.dispatch('maps/post', {
title,
type: this.timeline.type
})
if (timeline) {
let result = await this.$store.dispatch('annotations/find', { 'target.id': this.timeline.id })
const annotations = result.items
for (let annotation of annotations) {
annotation = annotation.toObject()
let created, payload, title
if (annotation.body) {
if (annotation.body && annotation.body.type === 'Video') {
const { items } = (await this.$store.dispatch('annotations/find', { 'target.id': annotation.id }))
title = items.shift()
payload = {
body: annotation.body,
target: {
id: timeline.id,
type: annotation.target.type,
selector: annotation.target.selector
}
}
}
else {
payload = {
body: annotation.body,
target: {
id: timeline.id,
type: annotation.target.type,
selector: annotation.target.selector
}
}
}
}
if (payload) {
created = await this.$store.dispatch('annotations/post', payload)
}
if (title) {
title = title.toObject()
await this.$store.dispatch('annotations/post', {
body: title.body,
target: {
id: created.id,
type: title.target.type
}
})
}
}
}
}
catch (err) {
this.$handleError(this, err, 'errors.duplicate_timeline_failed')
}
this.$q.loading.hide()
this.$store.commit('notifications/addMessage', {
body: 'messages.timeline_duplicated',
mode: 'alert',
type: 'success'
})
return this.$router.push({ name: 'piecemaker.timelines.list' })
},
async exportTimeline () {
if (this.downloadURL) return openURL(this.downloadURL)
this.$q.loading.show()
......
......@@ -64,6 +64,21 @@
}
catch (e) { this.media[i].metadata = {} }
}
// const aggs = {
// annotations_per_minute: {
// date_histogram: {
// field: 'target.selector._valueMillis',
// calendar_interval: '1m'
// }
// }
// }
// const query = {
// match: { 'target.id': this.map.id }
// }
// const aggregations = await this.$store.dispatch('search/query', { index: 'annotations', aggs, query })
// console.debug('Aggregations', aggregations)
this.$q.loading.hide()
},
computed: {
......@@ -75,12 +90,11 @@
async search () {
this.$q.loading.show()
const query = {
'target.id': this.map.id,
'body.type': 'TextualBody',
'body.value': RegExp(`.*${this.query}.*`, 'ig')
match: { 'body.value': this.query }
}
const result = await this.$store.dispatch('annotations/find', query)
this.results = result && Array.isArray(result.items) ? result.items.sort(this.$sort.onRef) : []
const result = await this.$store.dispatch('search/query', { index: 'annotations', query })
this.results = (result && Array.isArray(result.hits) ? result.hits.sort(this.$sort.onRef) : [])
.map(hit => hit._source)
this.$q.loading.hide()
},
formatDate (millis) {
......@@ -94,7 +108,7 @@
videoEnd = videoStart.plus(video.metadata.duration * 1000)
if (annoTime >= videoStart && annoTime < videoEnd) return video
}
return {}
return { annotation: {}, metadata: {} }
}
}
}
......
......@@ -30,6 +30,7 @@ Router.beforeEach((to, from, next) => {
else cb()
}
waitForStore(Router.app, () => {
if (to.name === 'users.callback') return next()
const redirectPath = Router.app.$store.state.auth.redirectTo
if (redirectPath) Router.app.$store.commit('auth/clearRedirect')
Router.app.$auth.checkSession(Router.app.$store).catch(() => {
......
......@@ -4,7 +4,10 @@ export default {
children: [
{
path: '/piecemaker',
redirect: {name: 'piecemaker.media.list_generic'}
name: 'piecemaker.default',
redirect: {
name: process.env.USE_GENERIC_ANNOTATION ? 'piecemaker.media.list_generic' : 'piecemaker.timelines.list'
}
},
{
......
......@@ -30,7 +30,8 @@ import {
queue,
swimLane,
vocabularies,
settings
settings,
search
} from './modules'
import mediaFactory from './modules/media'
......@@ -115,7 +116,8 @@ const modules = {
queue,
swimLane,
vocabularies,
settings
settings,
search
}
for (let key in mobaApiModules) {
if (mobaApiModules[key]) modules[key] = mobaApiModules[key]
......
......@@ -10,6 +10,7 @@ import files from './files'
import queue from './queue'
import swimLane from './swim-lane'
import settings from './settings'
import search from './search'
import vocabularies from './vocabularies'
export {
......@@ -25,5 +26,6 @@ export {
queue,
swimLane,
settings,
search,
vocabularies
}
const axios = require('axios')
const search = {
namespaced: true,
state: {},
actions: {
async query (context, { index, query, aggs }) {
const config = {
headers: {
Authorization: `${this.$router.app.$auth.tokenType} ${this.$router.app.$auth.token}`
}
}
let result = await axios.post(`${process.env.API_HOST}/search/${index}`, { query, aggs }, config)
return result.data
}
}
}
export default search
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment