Commit 72ee54cf authored by Anton Koch's avatar Anton Koch

Merge branch '306-shared---annotation-index' into 'master'

added annotation-index to piecemaker (shared) (#306)

See merge request !29
parents e32ba79f a485ea74
Pipeline #29762 passed with stage
in 5 minutes and 36 seconds
<template lang="pug">
// div.bg-orange(:class="{'q-mt-xl': position !== 'first', 'q-pb-xl ui-border-bottom': position !== 'last'}")
div(:class="{'q-mt-xl': position !== 'first', '': position !== 'last'}")
div.col-12(:class="[{'q-mt-xl': position !== 'first', '': position !== 'last'}, `col-md-${columnsMd}`]")
slot
</template>
......@@ -8,7 +8,7 @@
import { mapGetters } from 'vuex'
export default {
name: 'content-block',
props: ['position'],
props: ['position', 'columnsMd'],
computed: {
...mapGetters({
isMobile: 'globalSettings/getIsMobile'
......
<template lang="pug">
q-item.q-pa-none
q-item-main(:class="[{'opacity-0': loading}, {'fade-in': !loading}]")
q-item-tile.bg-dark.q-px-sm.q-py-xs
q-input(ref="input", @click="toggleMode(true)", @input="inputChange(true)",
type="textarea", v-model="model", dark, hide-underline)
q-item-side.relative-position(:class="{'opacity-0': !changed }")
q-btn.bg-white.text-dark(@click="updateAnnotation()", flat, size="sm", :disabled="!changed", round)
q-icon(name="check")
q-btn.on-right(@click.native="toggleMode(false)", flat, size="sm", style="border: 1px solid #3f3f3f;", round)
q-icon(name="clear")
</template>
<script>
import uuidValidate from 'uuid-validate'
import { Assert } from 'mbjs-utils'
export default {
name: 'editableTableData',
props: ['data'],
data () {
return {
loading: false,
buffer: undefined,
model: undefined,
edit: false,
changed: undefined
}
},
mounted () {
this.model = this.data.row.body.value
},
methods: {
async updateAnnotation () {
let annotation = this.data.row
annotation.body.value = this.model
try {
this.loading = true
Assert.isType(annotation, 'object')
Assert.ok(uuidValidate(annotation._uuid))
Assert.isType(annotation.body.value, 'string')
await this.$store.dispatch('annotations/patch', [annotation._uuid, annotation])
this.getAnnotation()
this.$store.commit('notifications/addMessage', {
body: 'messages.updated_annotation',
mode: 'alert',
type: 'success'
})
this.toggleMode(false)
this.inputChange(false)
}
catch (err) {
this.$handleError(this, err, 'errors.update_annotation_failed')
}
},
async getAnnotation () {
const result = await this.$store.dispatch('annotations/get', this.data.row._uuid)
this.model = result.body.value
this.loading = false
},
inputChange (bool) {
this.changed = bool
},
toggleMode (bool) {
if (!this.edit) this.buffer = this.model
this.edit = bool
if (!bool) {
this.inputChange(false)
this.model = this.buffer
this.buffer = undefined
}
}
}
}
</script>
<style scoped lang="stylus">
.fade-in
animation fade-in ease 1s
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.opacity-0
opacity 0!important
cursor default
.active-input
border-bottom 1px solid #444
transition none
margin-top -1px
transform translateY(1px)
</style>
......@@ -30,22 +30,17 @@
<script>
import { openURL } from 'quasar'
import { mapGetters } from 'vuex'
import SiteFooter from '../partials/SiteFooter'
export default {
components: {
SiteFooter
},
computed: {
...mapGetters({
isMobile: 'globalSettings/getIsMobile'
})
},
data: function () {
return {
openURL,
isElectron: this.$q.platform.is.electron
isElectron: this.$q.platform.is.electron,
isMobile: this.$q.platform.is.mobile
}
}
}
......
......@@ -178,6 +178,7 @@
},
dropdownItems () {
let di = []
// ---------------------------------------------------------------------------------------------------- timeline
if (this.timeline) {
di.push({
label: this.$t('navigation.piecemaker.piecemaker_media_list'),
......@@ -197,12 +198,17 @@
name: 'piecemaker.timelines.search'
})
}
// --------------------------------------------------------------------------------------------------- mediaData
if (this.mediaMetadata) {
di = []
di.push({
label: this.$t('navigation.piecemaker.piecemaker_media_annotate'),
route: '/piecemaker/media/' + this.media._uuid + '/annotate',
name: 'piecemaker.media.annotate'
}, {
label: this.$t('labels.annotations'),
route: '/piecemaker/media/' + this.media._uuid + '/annotations-index',
name: 'piecemaker.media.index'
}, {
label: this.$t('navigation.piecemaker.piecemaker_media_edit'),
route: '/piecemaker/media/' + this.media._uuid + '/edit',
......@@ -213,6 +219,7 @@
name: 'piecemaker.media.sync'
})
}
// -------------------------------------------------------------------------------------------------------- grid
if (this.grid) {
di = []
di.push({
......@@ -229,6 +236,7 @@
name: 'mosys.grids.edit'
})
}
// ---------------------------------------------------------------------------------------------------- document
if (this.document) {
di = []
di.push({
......
......@@ -80,6 +80,13 @@
:name="'piecemaker.media.annotate'",
:class="{'text-primary background-primary-20' : currentRoute === 'piecemaker.media.annotate'}")
q-item-tile
user-nav-button(
:route="'/piecemaker/media/' + currentId.media + '/annotations-index'",
:label="$t('labels.annotations')",
:name="'piecemaker.media.index'",
:class="{'text-primary background-primary-20' : currentRoute === 'piecemaker.media.index'}")
q-item-tile
user-nav-button(
:route="'/piecemaker/media/' + currentId.media + '/edit'",
......@@ -313,6 +320,7 @@
],
media: [
'piecemaker.media.annotate',
'piecemaker.media.index',
'piecemaker.media.edit',
'piecemaker.media.sync'
],
......@@ -363,6 +371,7 @@
this.timeline = undefined
this.mediaMetadata = undefined
this.grid = undefined
console.log('ROUTE', route)
// this.currentRoute = route.name
// detect current app
......@@ -382,7 +391,7 @@
// media
if (this.routes.media.includes(route.name)) {
this.currentId.media = route.params.uuid
this.currentId.media = (route.params.uuid || route.params.id)
this.getMedia()
}
else {
......@@ -411,8 +420,8 @@
}
},
async getMedia () {
if (this.$route.params.uuid) {
this.media = await this.$store.dispatch('annotations/get', this.$route.params.uuid)
if (this.$route.params.uuid || this.$route.params.id) {
this.media = await this.$store.dispatch('annotations/get', (this.$route.params.uuid || this.$route.params.id))
this.mediaMetadata = await this.$store.dispatch('metadata/get', this.media)
if (this.media && !this.currentId.timeline) this.currentId.timeline = parseURI(this.media.target.id).uuid
}
......
<template lang="pug">
div
// buttons and search bar above the table
.row.gutter-md.q-mb-md
//
.col-3.col-sm-5.col-md-4.col-lg-3.col-xl-3
slot(name="top-buttons", slot-scope="props")
.col-9.col-sm-7.col-md-8.col-lg-9.col-xl-9
.col-12
q-search(v-model="filter", dark, icon="search")
.col-12.col-md-6
q-search.bg-grey-10.q-pa-sm(v-model="filter", dark, icon="search", hide-underline)
q-table.full-width(
v-if="cols.length > 0",
dark,
ref="table",
row-key="name",
:data="rows",
:columns="cols",
:selection="selection",
:selected.sync="selected",
@request="request",
:loading="loading",
:rows-per-page-options="rowsPerPage",
:pagination.sync="pagination",
:hide-bottom="hideBottom",
:filter="filter",
:title="tableTitle")
v-if="cols.length > 0",
dark,
ref="table",
row-key="name",
:data="rows",
:columns="cols",
:selection="selection",
:selected.sync="selected",
@request="request",
:loading="loading",
:rows-per-page-options="rowsPerPage",
:pagination.sync="pagination",
:hide-bottom="hideBottom",
:filter="filter",
:title="tableTitle")
template(slot="top-left", slot-scope="props")
slot(name="buttons-left")
<!--template(slot="top-right", slot-scope="props")-->
<!--q-search(v-model="filter", dark, icon="search")-->
q-td(slot="body-cell-title", slot-scope="props", :props="props")
template(v-if="customTitleLink")
q-btn(
type="a",
color="primary",
:to="getCustomLink(customTitleLink, props.row._uuid)",
flat
)
q-btn( type="a", color="primary", :to="getCustomLink(customTitleLink, props.row._uuid)", flat)
promise-span(:value="props.value")
template(v-else)
q-btn(
v-if="hasShow",
type="a",
color="primary",
:to="getViewLink(props.row._uuid)",
flat
)
q-btn(v-if="hasShow", type="a", color="primary", :to="getViewLink(props.row._uuid)", flat)
promise-span(:value="props.value")
promise-span(v-if="!hasShow", :value="props.value")
q-td(slot="body-cell-tags", slot-scope="props", :props="props")
promise-span(:value="props.value")
q-td(slot="body-cell-start", slot-scope="props", :props="props")
.q-pa-sm.text-grey-6.bg-dark(@click="start(props.value)", style="cursor: pointer;")
| {{ returnDatetime(props.value) }}
q-td(slot="body-cell-annotation", slot-scope="props", :props="props")
editable-table-data(:data="props", :key="props")
q-td(slot="body-cell-actions", slot-scope="props", :props="props")
q-btn(v-for="btn in props.value", :key="btn.icon", "flat", size="md", :icon="btn.icon",
@click="defaultClick(btn, props)") {{ $t(btn.title) }}
</template>
<script>
import { PromiseSpan } from '../elements'
import { mapGetters } from 'vuex'
import { userHasFeature } from 'mbjs-quasar/src/lib'
// import { DateTime } from 'luxon'
import { DateTime } from 'luxon'
import EditableTableData from '../forms/EditableTableData'
export default {
props: ['config', 'path', 'query', 'title', 'basePath', 'hasShow', 'requestTransform', 'customTitleLink'],
components: {
PromiseSpan
PromiseSpan,
EditableTableData
},
data () {
return {
......@@ -90,12 +85,19 @@
}
},
methods: {
returnDatetime (val) {
return DateTime.fromMillis(val).toLocaleString(DateTime.DATETIME_SHORT_WITH_SECONDS)
},
start (val) {
this.$emit('start', val)
},
updateConfig () {
if (!this.config || !this.config.columns) return
this.pagination = Object.assign(this.pagination, this.config.pagination)
const _this = this
let _query = this.config && this.config.actions
const makeFormatter = function (field) {
if (field === 'actions') {
if (field === 'actions' && _query) {
return () => {
return _this.config.actions.filter(action => {
if (action.feature) return _this.user && userHasFeature(_this.user, action.feature)
......@@ -121,20 +123,22 @@
},
type: 'string'
}, column)
if (!column.format) {
if (!column.format && this.config.actions) {
column.format = makeFormatter(column.field)
}
return column
})
cols.push({
name: 'actions',
align: 'right',
type: 'string',
filter: false,
sortable: false,
sort: false,
format: makeFormatter('actions')
})
if (this.config.actions) {
cols.push({
name: 'actions',
align: 'right',
type: 'string',
filter: false,
sortable: false,
sort: false,
format: makeFormatter('actions')
})
}
this.cols = cols
},
async defaultClick (btn, props) {
......@@ -166,6 +170,7 @@
data.items = await this.config.request(/* { pagination, filter } */)
}
if (!data.items) data = await this.$store.dispatch(`${this.path}/find`, this.query)
console.log('DATA', data)
if (!data.items) {
this.loading = false
return
......
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