Commits (10)
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
:validation="$v.local[key]", :validation="$v.local[key]",
:attributes="field.attributes", :attributes="field.attributes",
:label="$t(field.label)", :label="$t(field.label)",
:fieldLabel="field.fieldLabel ? $t(field.fieldLabel) : undefined",
:handler="field.handler",
:helper-label="$t(field.helperLabel)", :helper-label="$t(field.helperLabel)",
:error-label="$t(field.errorLabel)", :error-label="$t(field.errorLabel)",
:class="{ 'col-xl-6': !field.fullWidth, 'col-12': field.fullWidth }" :class="{ 'col-xl-6': !field.fullWidth, 'col-12': field.fullWidth }"
...@@ -25,6 +27,8 @@ ...@@ -25,6 +27,8 @@
:validation="field.validators ? $v.local[key] : undefined", :validation="field.validators ? $v.local[key] : undefined",
:attributes="field.attributes", :attributes="field.attributes",
:label="$t(field.label)", :label="$t(field.label)",
:fieldLabel="field.fieldLabel ? $t(field.fieldLabel) : undefined",
:handler="field.handler",
:helper-label="$t(field.helperLabel)", :helper-label="$t(field.helperLabel)",
:error-label="$t(field.errorLabel)", :error-label="$t(field.errorLabel)",
:class="{ 'col-xl-6': !field.fullWidth, 'col-12': field.fullWidth }" :class="{ 'col-xl-6': !field.fullWidth, 'col-12': field.fullWidth }"
......
<template lang="pug"> <template lang="pug">
q-input(v-if="type === 'hidden'", :type="type", v-model="local") q-input(v-if="type === 'hidden'", :type="type", v-model="local")
q-field(v-else, :dark="true", :label="fieldLabel", :error="validation ? validation.$error : undefined", q-field(v-else, :dark="true", :label="fieldLabel", :error="validation ? validation.$error : undefined",
:error-label="errorLabel", :helper="helperLabel || ''") :error-label="errorLabel", :helper="helperLabel || ''", orientation="vertical")
q-select(v-if="type === 'select'", :float-label="label", :dark="true", v-model="local", :options="selectOptions") q-select(v-if="type === 'select'", :float-label="label", :dark="true", v-model="local", :options="selectOptions")
q-chips-input.q-my-md(v-else-if="type === 'chips'", :float-label="label", :dark="true", v-model="local", q-chips-input.q-my-md(v-else-if="type === 'chips'", :float-label="label", :dark="true", v-model="local",
chips-color="white", chips-bg-color="grey", @duplicate="duplicate()") chips-color="white", chips-bg-color="grey", @duplicate="duplicate()")
q-autocomplete.bg-grey-9(@search="autocompleteSearch", @selected="autocompleteSelected") q-autocomplete.bg-grey-9(@search="autocompleteSearch", @selected="autocompleteSelected")
uploader(v-else-if="type === 'file'", dark, :url="url", @finish="onFileFinish", @select="onFileSelect", :headers="headers", :fields="uploadFields || []")
q-input(v-else, :dark="true", :float-label="label", :type="type", v-model="local", :attributes="attributes") q-input(v-else, :dark="true", :float-label="label", :type="type", v-model="local", :attributes="attributes")
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'
export default { export default {
props: [ props: [
'value', 'value',
...@@ -21,7 +23,9 @@ ...@@ -21,7 +23,9 @@
'errorLabel', 'errorLabel',
'helperLabel', 'helperLabel',
'selectOptions', 'selectOptions',
'autocompleteOptions' 'autocompleteOptions',
'uploadFields',
'handler'
], ],
data () { data () {
return { return {
...@@ -29,6 +33,17 @@ ...@@ -29,6 +33,17 @@
} }
}, },
computed: { computed: {
...mapGetters({
user: 'auth/getUserState'
}),
url () {
return this.user ? `${process.env.API_HOST}/assets/user-${this.user.uuid}` : undefined
},
headers () {
return {
Authorization: `Bearer ${this.$auth.token}`
}
},
error () { error () {
if (this.type === 'hidden') return if (this.type === 'hidden') return
return this.validation && this.validation.$error return this.validation && this.validation.$error
...@@ -66,6 +81,13 @@ ...@@ -66,6 +81,13 @@
}, },
autocompleteSelected (item) { autocompleteSelected (item) {
console.debug('FormRow: autocompleteSelected', item) console.debug('FormRow: autocompleteSelected', item)
},
onFileSelect (selection) {
this.$emit('select', selection)
},
onFileFinish (responses) {
this.local = responses
if (typeof this.handler === 'function') this.handler(responses)
} }
}, },
created () { created () {
......
<template lang="pug">
div
// q-window-resize-observable(@resize="onWindowResize")
canvas(ref="three")
</template>
<script>
import path from 'path'
import { dom } from 'quasar'
const { height, width } = dom
const THREE = require('three')
global.THREE = THREE
require('three/examples/js/controls/OrbitControls')
require('three/examples/js/loaders/BVHLoader.js')
export default {
name: 'BVHPlayer',
props: {
bvhPath: String,
scale: Number,
loop: Boolean,
dump: Boolean,
compact: Boolean,
euler: Boolean,
backgroundColor: { type: String, default: '#000000' },
useOSC: { type: Boolean, default: true },
remoteAddress: String,
remotePort: Number
},
data () {
return {
skeletonName: undefined,
sender: undefined,
camera: undefined,
controls: undefined,
scene: undefined,
renderer: undefined,
stats: undefined,
clipAction: undefined,
mixers: [],
skeletons: [],
frames: [],
boneNames: []
}
},
async mounted () {
this.initThreeJS()
await this.loadBVH(this.bvhPath)
},
watch: {
async bvhPath (val) {
await this.loadBVH(val)
}
},
methods: {
onWindowResize (size) {
if (!this.camera || !this.renderer) return
this.camera.aspect = size.width / size.height
this.camera.updateProjectionMatrix()
this.renderer.setSize(size.width, size.height)
},
initThreeJS () {
// const w = window.innerWidth
// const h = window.innerHeight
const w = width(this.$el)
const h = height(this.$el)
this.clock = new THREE.Clock()
this.camera = new THREE.PerspectiveCamera(60, w / h, 1, 5000)
this.camera.position.set(0, 200, 400)
this.controls = new THREE.OrbitControls(this.camera, this.$refs.three)
this.controls.minDistance = 10
this.controls.maxDistance = 1000
this.scene = new THREE.Scene()
this.scene.background = new THREE.Color(this.backgroundColor)
this.scene.add(new THREE.GridHelper(400, 10))
// renderer
this.renderer = new THREE.WebGLRenderer({
canvas: this.$refs.three,
antialias: true
})
this.renderer.setPixelRatio(window.devicePixelRatio)
// this.renderer.setSize(this.$refs.three.offsetWidth, this.$refs.three.offsetHeight)
this.renderer.setSize(w, h)
this.animate()
},
async loadBVH (bvhPath) {
if (!this.bvhPath) return
const loader = new THREE.BVHLoader()
this.skeletonName = path.basename(bvhPath, path.extname(bvhPath))
loader.load(this.bvhPath, this.handleBVHLoaded)
},
handleBVHLoaded (result) {
const scaleVec = new THREE.Vector3(this.scale, this.scale, this.scale)
const skeletonHelper = new THREE.SkeletonHelper(result.skeleton.bones[0])
skeletonHelper.skeleton = result.skeleton // allow animation mixer to bind to SkeletonHelper directly
const boneContainer = new THREE.Group()
boneContainer.add(result.skeleton.bones[0])
boneContainer.scale.copy(scaleVec)
this.scene.add(skeletonHelper)
this.scene.add(boneContainer)
// play animation
const mixer = new THREE.AnimationMixer(skeletonHelper)
const clipAction = mixer.clipAction(result.clip)
.setLoop(this.loop ? THREE.LoopRepeat : THREE.LoopOnce)
.setEffectiveWeight(1.0)
clipAction.play()
mixer.update(0)
this.clipAction = clipAction
this.mixers.push(mixer)
this.skeletons.push(skeletonHelper)
},
async animate () {
requestAnimationFrame(this.animate)
const delta = this.clock.getDelta()
if (this.mixers.length > 0) {
this.mixers.forEach(mixer => {
mixer.update(delta)
})
}
this.renderer.render(this.scene, this.camera)
}
}
}
</script>
<style scoped lang="stylus">
canvas
margin: 0
padding: 0
width: 100vh
height: 100vh
</style>
...@@ -101,6 +101,11 @@ ...@@ -101,6 +101,11 @@
label: 'Groups', label: 'Groups',
route: 'users.groups', route: 'users.groups',
path: '/users/groups' path: '/users/groups'
},
assets: {
label: 'Assets',
route: 'users.assets',
path: '/users/assets'
} }
} }
} }
...@@ -117,6 +122,10 @@ ...@@ -117,6 +122,10 @@
(t === 'users' && parts[1] === 'groups_edit')) return true (t === 'users' && parts[1] === 'groups_edit')) return true
else return false else return false
}, },
isAssets () {
const parts = this.$route.name.split('.')
return parts[0] === 'users' && parts[1].indexOf('assets') === 0
},
createScreen () { createScreen () {
const parts = this.$route.name.split('.') const parts = this.$route.name.split('.')
return parts[parts.length - 1] === 'create' || parts[parts.length - 1] === 'groups_create' return parts[parts.length - 1] === 'create' || parts[parts.length - 1] === 'groups_create'
...@@ -130,6 +139,7 @@ ...@@ -130,6 +139,7 @@
if (t === 'users' && parts[1] === 'groups') t = 'groups' if (t === 'users' && parts[1] === 'groups') t = 'groups'
if (t === 'users' && parts[1] === 'groups_create') t = 'groups' if (t === 'users' && parts[1] === 'groups_create') t = 'groups'
if (t === 'users' && parts[1] === 'groups_edit') t = 'groups' if (t === 'users' && parts[1] === 'groups_edit') t = 'groups'
if (t === 'users' && parts[1].indexOf('assets') === 0) t = 'assets'
if (t in this.topLevel) { if (t in this.topLevel) {
let _label = this.topLevel[t].label let _label = this.topLevel[t].label
...@@ -298,6 +308,13 @@ ...@@ -298,6 +308,13 @@
name: 'users.groups_create' name: 'users.groups_create'
} }
} }
if (this.breadcrumbs[0].label === 'Assets' && this.$route.name !== 'users.assets_upload' && !this.breadcrumbs[1]) {
ab = {
label: this.$t('navigation.users.assets_upload'),
route: 'assets/upload',
name: 'users.assets_upload'
}
}
if (this.timeline) { if (this.timeline) {
ab = { ab = {
label: this.$t('buttons.add_media'), label: this.$t('buttons.add_media'),
......
...@@ -235,6 +235,28 @@ ...@@ -235,6 +235,28 @@
q-item-side(v-if="currentRoute === 'users.groups_create'") q-item-side(v-if="currentRoute === 'users.groups_create'")
q-btn.bg-primary.text-white(type="a", to="/users/groups", icon="clear", round, size="sm") q-btn.bg-primary.text-white(type="a", to="/users/groups", icon="clear", round, size="sm")
// ------------------------------------------------------------------------------------------------------ assets
q-item.q-pa-none.ui-border-bottom(v-if="user && showAssets", multiline)
q-item-main
q-item-tile
user-nav-button.text-white(
:route="{ name: 'users.assets' }",
:label="$t('navigation.users.assets')",
name="users.assets",
icon="insert_drive_file")
q-item.q-my-sm.lt-sm(v-if="currentApp === 'assets'")
q-item-main
user-nav-button.text-white.round-borders(
:route="'/users/assets/upload'",
:label="$t('navigation.users.assets_upload')",
:name="'users.assets_upload'",
:icon="'add'",
:disabled="currentRoute === 'users.assets_upload'",
:class="[currentRoute === 'users.assets_upload' ? 'bg-grey-9' : 'bg-primary']")
q-item-side(v-if="currentRoute === 'users.assets_upload'")
q-btn.bg-primary.text-white(type="a", :to="{ name: 'users.assets' }", icon="clear", round, size="sm")
// -------------------------------------------------------------------------------------------- account settings // -------------------------------------------------------------------------------------------- account settings
q-item.q-pa-none.ui-border-bottom(v-if="user", multiline, :class="{'active-app': currentApp === 'users'}") q-item.q-pa-none.ui-border-bottom(v-if="user", multiline, :class="{'active-app': currentApp === 'users'}")
q-item-main q-item-main
...@@ -315,6 +337,10 @@ ...@@ -315,6 +337,10 @@
groups: [ groups: [
'users.groups', 'users.groups',
'users.groups_edit' 'users.groups_edit'
],
assets: [
'users.assets',
'users.assets_upload'
] ]
}, },
activeUserButtons: [], activeUserButtons: [],
...@@ -342,6 +368,9 @@ ...@@ -342,6 +368,9 @@
showGroups () { showGroups () {
return !process.env.UI_HIDE_GROUPS return !process.env.UI_HIDE_GROUPS
}, },
showAssets () {
return process.env.UI_SHOW_ASSETS
},
editUserURL () { editUserURL () {
return process.env.OAUTH_EDIT_PROFILE_URL return process.env.OAUTH_EDIT_PROFILE_URL
}, },
...@@ -376,6 +405,7 @@ ...@@ -376,6 +405,7 @@
let routeSplit = typeof route.name === 'string' ? route.name.split('.') : undefined let routeSplit = typeof route.name === 'string' ? route.name.split('.') : undefined
if (routeSplit && routeSplit[0] !== 'site') this.currentApp = routeSplit[0] if (routeSplit && routeSplit[0] !== 'site') this.currentApp = routeSplit[0]
if (routeSplit && route.name.indexOf('users.assets') === 0) this.currentApp = 'assets'
else this.currentApp = 'Motionbank' else this.currentApp = 'Motionbank'
if (routeSplit && routeSplit[1].substr(0, 6) === 'groups') this.currentApp = 'groups' if (routeSplit && routeSplit[1].substr(0, 6) === 'groups') this.currentApp = 'groups'
......
...@@ -27,11 +27,14 @@ ...@@ -27,11 +27,14 @@
export default { export default {
name: 'Permissions', name: 'Permissions',
components: { ContentBlock, Headline, GroupsStepper }, components: { ContentBlock, Headline, GroupsStepper },
props: ['resource'], props: ['resource', 'simple'],
data () { data () {
return { return {
type: undefined, type: undefined,
aclOptions: [ aclOptions: this.simple ? [
{ label: this.$t('labels.none'), value: undefined },
{ label: this.$t('labels.view'), value: 'view' }
] : [
{ label: this.$t('labels.none'), value: undefined }, { label: this.$t('labels.none'), value: undefined },
{ label: this.$t('labels.view'), value: 'view' }, { label: this.$t('labels.view'), value: 'view' },
{ label: this.$t('labels.contribute'), value: 'contribute' }, { label: this.$t('labels.contribute'), value: 'contribute' },
...@@ -83,6 +86,7 @@ ...@@ -83,6 +86,7 @@
}, },
methods: { methods: {
getText () { getText () {
if (this.simple) return ''
let route = this.$route let route = this.$route
let routeSplit = typeof route.name === 'string' ? route.name.split('.') : undefined let routeSplit = typeof route.name === 'string' ? route.name.split('.') : undefined
return this.$t('help.acl.' + routeSplit[0]) return this.$t('help.acl.' + routeSplit[0])
......
...@@ -26,8 +26,11 @@ ...@@ -26,8 +26,11 @@
multiple () { multiple () {
this.allowMultiple = this.multiple this.allowMultiple = this.multiple
}, },
fields () { fields: {
this.addFields = this.fields || [] deep: true,
handler () {
this.addFields = this.fields || []
}
} }
}, },
methods: { methods: {
......