362 lines
11 KiB
Vue
362 lines
11 KiB
Vue
![]() |
<template>
|
||
|
<div :class="getModelSlug()">
|
||
|
<nav class="breadcrumb" aria-label="breadcrumbs">
|
||
|
<ul>
|
||
|
<li>
|
||
|
<router-link :to="getModelPathPrefix() + '/'">{{ getModelIndexTitle() }}</router-link>
|
||
|
</li>
|
||
|
<li v-if="isRow">
|
||
|
<router-link :to="getModelPathPrefix() + '/' + record._parent_uuid">{{ renderParentHeaderLabel(record) }}</router-link>
|
||
|
<!-- {{ renderParentHeaderLabel(record) }} -->
|
||
|
</li>
|
||
|
<li v-if="mode == 'creating'">
|
||
|
New
|
||
|
</li>
|
||
|
<li v-if="mode == 'viewing'">
|
||
|
{{ renderHeaderLabel(record) }}
|
||
|
</li>
|
||
|
<li v-if="mode == 'editing' || mode == 'deleting'">
|
||
|
<router-link :to="getModelPathPrefix() + '/' + record.uuid">{{ renderHeaderLabel(record) }}</router-link>
|
||
|
</li>
|
||
|
<li v-if="mode == 'editing'">
|
||
|
Edit
|
||
|
</li>
|
||
|
<li v-if="mode == 'deleting'">
|
||
|
Delete
|
||
|
</li>
|
||
|
</ul>
|
||
|
</nav>
|
||
|
|
||
|
<slot></slot>
|
||
|
|
||
|
<b-button v-if="allowEdit && mode == 'viewing' && hasModelPerm('edit')"
|
||
|
type="is-primary"
|
||
|
tag="router-link"
|
||
|
:to="getModelPathPrefix() + '/' + record.uuid + '/edit'">
|
||
|
Edit This
|
||
|
</b-button>
|
||
|
|
||
|
<div v-if="mode == 'creating' || mode == 'editing'"
|
||
|
class="buttons">
|
||
|
<b-button type="is-primary"
|
||
|
:disabled="saveDisabled"
|
||
|
@click="save()">
|
||
|
Save
|
||
|
</b-button>
|
||
|
<b-button v-if="mode == 'creating'"
|
||
|
tag="router-link"
|
||
|
:to="getModelPathPrefix() + '/'">
|
||
|
Cancel
|
||
|
</b-button>
|
||
|
<b-button v-if="mode == 'editing'"
|
||
|
tag="router-link"
|
||
|
:to="getModelPathPrefix() + '/' + record.uuid">
|
||
|
Cancel
|
||
|
</b-button>
|
||
|
</div>
|
||
|
|
||
|
<div v-if="hasRows && mode == 'viewing'">
|
||
|
<b-menu>
|
||
|
<b-menu-list>
|
||
|
<b-menu-item v-for="row in rows"
|
||
|
:key="row.uuid"
|
||
|
tag="router-link"
|
||
|
:to="getRowPathPrefix() + '/' + row.uuid">
|
||
|
<template slot="label" slot-scope="props">
|
||
|
<span v-html="renderRowLabel(row)"></span>
|
||
|
</template>
|
||
|
</b-menu-item>
|
||
|
</b-menu-list>
|
||
|
</b-menu>
|
||
|
</div>
|
||
|
|
||
|
<slot name="footer"></slot>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
export default {
|
||
|
name: 'ByjoveModelCrud',
|
||
|
props: {
|
||
|
mode: String,
|
||
|
modelName: String,
|
||
|
modelSlug: String,
|
||
|
modelTitle: String,
|
||
|
modelTitlePlural: String,
|
||
|
modelIndexTitle: String,
|
||
|
modelPermissionPrefix: String,
|
||
|
modelPathPrefix: String,
|
||
|
modelRoutePrefix: String,
|
||
|
apiIndexUrl: String,
|
||
|
apiObjectUrl: String,
|
||
|
labelRenderer: Function,
|
||
|
parentHeaderLabelRenderer: Function,
|
||
|
headerLabelRenderer: Function,
|
||
|
rowLabelRenderer: Function,
|
||
|
hasRows: {
|
||
|
type: Boolean,
|
||
|
default: false,
|
||
|
},
|
||
|
apiRowsUrl: String,
|
||
|
isRow: {
|
||
|
type: Boolean,
|
||
|
default: false,
|
||
|
},
|
||
|
rowPathPrefix: String,
|
||
|
rowFilters: {
|
||
|
type: Function,
|
||
|
default: (uuid) => {
|
||
|
return JSON.stringify([{field: 'batch_uuid', op: 'eq', value: uuid}])
|
||
|
},
|
||
|
},
|
||
|
allowEdit: {
|
||
|
type: Boolean,
|
||
|
default: true,
|
||
|
},
|
||
|
saveDisabled: {
|
||
|
type: Boolean,
|
||
|
default: false,
|
||
|
},
|
||
|
},
|
||
|
data: function() {
|
||
|
return {
|
||
|
record: {},
|
||
|
rows: [],
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// TODO: why doesn't beforeRouteUpdate() work instead?
|
||
|
// cf. https://router.vuejs.org/guide/essentials/dynamic-matching.html#reacting-to-params-changes
|
||
|
watch: {
|
||
|
'$route' (to, from) {
|
||
|
if (to.name == (this.getModelRoutePrefix() + '.edit') && !this.hasModelPerm('edit')) {
|
||
|
this.$buefy.toast.open({
|
||
|
message: "You do not have permission to access that page.",
|
||
|
type: 'is-danger',
|
||
|
position: 'is-bottom',
|
||
|
})
|
||
|
this.$router.push(this.getModelPathPrefix() + '/')
|
||
|
}
|
||
|
|
||
|
// re-fetch record in case it was just changed
|
||
|
if (to.name != (this.getModelRoutePrefix() + '.new')) {
|
||
|
this.fetch(to.params.uuid)
|
||
|
}
|
||
|
},
|
||
|
},
|
||
|
|
||
|
// beforeRouteUpdate (to, from, next) {
|
||
|
// // re-fetch record in case it was just changed
|
||
|
// if (to.name != (this.getModelRoutePrefix() + '.new')) {
|
||
|
// this.fetch(to.params.uuid)
|
||
|
// }
|
||
|
// next()
|
||
|
// },
|
||
|
|
||
|
mounted() {
|
||
|
|
||
|
// redirect if user doesn't have permission to be here
|
||
|
if ((this.mode == 'creating' && !this.hasModelPerm('create'))
|
||
|
|| (this.mode == 'editing' && !this.hasModelPerm('edit'))) {
|
||
|
this.$buefy.toast.open({
|
||
|
message: "You do not have permission to access that page.",
|
||
|
type: 'is-danger',
|
||
|
position: 'is-bottom',
|
||
|
})
|
||
|
this.$router.push(this.getModelPathPrefix() + '/')
|
||
|
}
|
||
|
|
||
|
// fetch initial page data unless 'creating'
|
||
|
if (this.mode != 'creating') {
|
||
|
this.fetch(this.$route.params.uuid)
|
||
|
}
|
||
|
},
|
||
|
|
||
|
methods: {
|
||
|
|
||
|
getModelSlug() {
|
||
|
if (this.modelSlug) {
|
||
|
return this.modelSlug
|
||
|
}
|
||
|
return this.modelName.toLowerCase() + 's'
|
||
|
},
|
||
|
|
||
|
getModelTitle() {
|
||
|
if (this.modelTitle) {
|
||
|
return this.modelTitle
|
||
|
}
|
||
|
return this.modelName
|
||
|
},
|
||
|
|
||
|
getModelTitlePlural() {
|
||
|
if (this.modelTitlePlural) {
|
||
|
return this.modelTitlePlural
|
||
|
}
|
||
|
return this.getModelTitle() + 's'
|
||
|
},
|
||
|
|
||
|
getModelIndexTitle() {
|
||
|
if (this.modelIndexTitle) {
|
||
|
return this.modelIndexTitle
|
||
|
}
|
||
|
return this.getModelTitlePlural()
|
||
|
},
|
||
|
|
||
|
getModelPathPrefix() {
|
||
|
if (this.modelPathPrefix) {
|
||
|
return this.modelPathPrefix
|
||
|
}
|
||
|
return '/' + this.getModelSlug()
|
||
|
},
|
||
|
|
||
|
getModelRoutePrefix() {
|
||
|
if (this.modelRoutePrefix) {
|
||
|
return this.modelRoutePrefix
|
||
|
}
|
||
|
return this.getModelSlug()
|
||
|
},
|
||
|
|
||
|
getRowPathPrefix() {
|
||
|
if (this.rowPathPrefix) {
|
||
|
return this.rowPathPrefix
|
||
|
}
|
||
|
return '/' + this.getModelSlug() + '/rows'
|
||
|
},
|
||
|
|
||
|
getApiIndexUrl() {
|
||
|
if (this.apiIndexUrl) {
|
||
|
return this.apiIndexUrl
|
||
|
}
|
||
|
return '/api/' + this.getModelSlug()
|
||
|
},
|
||
|
|
||
|
getApiObjectUrl() {
|
||
|
if (this.apiObjectUrl) {
|
||
|
return this.apiObjectUrl
|
||
|
}
|
||
|
let url = this.getApiIndexUrl()
|
||
|
// drop trailing 's' then add slash
|
||
|
return url.slice(0, -1) + '/'
|
||
|
},
|
||
|
|
||
|
getApiRowsUrl() {
|
||
|
return this.apiRowsUrl
|
||
|
},
|
||
|
|
||
|
getModelPermissionPrefix() {
|
||
|
if (this.modelPermissionPrefix) {
|
||
|
return this.modelPermissionPrefix
|
||
|
}
|
||
|
return this.getModelSlug()
|
||
|
},
|
||
|
|
||
|
hasPerm(perm) {
|
||
|
|
||
|
// if user is root then assume permission
|
||
|
if (this.$store.state.user && this.$store.state.user.is_root) {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// otherwise do true perm check for user
|
||
|
return this.$store.state.permissions.includes(perm)
|
||
|
},
|
||
|
|
||
|
hasModelPerm(perm) {
|
||
|
|
||
|
// do normal check, but first add prefix
|
||
|
let prefix = this.getModelPermissionPrefix()
|
||
|
return this.hasPerm(prefix + '.' + perm)
|
||
|
},
|
||
|
|
||
|
renderLabel(obj) {
|
||
|
if (this.labelRenderer) {
|
||
|
return this.labelRenderer(obj)
|
||
|
}
|
||
|
return obj._str
|
||
|
},
|
||
|
|
||
|
renderHeaderLabel(obj) {
|
||
|
if (this.headerLabelRenderer) {
|
||
|
return this.headerLabelRenderer(obj)
|
||
|
}
|
||
|
return this.renderLabel(obj)
|
||
|
},
|
||
|
|
||
|
renderParentHeaderLabel(obj) {
|
||
|
if (this.parentHeaderLabelRenderer) {
|
||
|
return this.parentHeaderLabelRenderer(obj)
|
||
|
}
|
||
|
return this.renderLabel(obj)
|
||
|
},
|
||
|
|
||
|
renderRowLabel(row) {
|
||
|
if (this.rowLabelRenderer) {
|
||
|
return this.rowLabelRenderer(row)
|
||
|
}
|
||
|
return row._str
|
||
|
},
|
||
|
|
||
|
fetch(uuid) {
|
||
|
this.$http.get(this.getApiObjectUrl() + uuid).then(response => {
|
||
|
this.record = response.data.data
|
||
|
this.$emit('refresh', this.record)
|
||
|
if (this.hasRows) {
|
||
|
this.fetchRows(uuid)
|
||
|
}
|
||
|
}, response => {
|
||
|
if (response.status == 403) { // forbidden; redirect to model index
|
||
|
this.$buefy.toast.open({
|
||
|
message: "You do not have permission to access that page.",
|
||
|
type: 'is-danger',
|
||
|
position: 'is-bottom',
|
||
|
})
|
||
|
this.$router.push(this.getModelPathPrefix() + '/')
|
||
|
} else {
|
||
|
this.$buefy.toast.open({
|
||
|
message: "Failed to fetch page data!",
|
||
|
type: 'is-danger',
|
||
|
position: 'is-bottom',
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
|
||
|
},
|
||
|
|
||
|
fetchRows(uuid) {
|
||
|
let params = {
|
||
|
filters: this.rowFilters(uuid),
|
||
|
orderBy: 'modified',
|
||
|
ascending: 0,
|
||
|
}
|
||
|
this.$http.get(this.getApiRowsUrl(), {params: params}).then(response => {
|
||
|
this.rows = response.data.data
|
||
|
|
||
|
}, response => {
|
||
|
if (response.status == 403) { // forbidden; redirect to home page
|
||
|
this.$buefy.toast.open({
|
||
|
message: "You do not have permission to access that page.",
|
||
|
type: 'is-danger',
|
||
|
position: 'is-bottom',
|
||
|
})
|
||
|
this.$router.push('/')
|
||
|
} else {
|
||
|
this.$buefy.toast.open({
|
||
|
message: "Failed to fetch page data!",
|
||
|
type: 'is-danger',
|
||
|
position: 'is-bottom',
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
},
|
||
|
|
||
|
save() {
|
||
|
let url = this.getApiIndexUrl()
|
||
|
if (this.mode != 'creating') {
|
||
|
url = this.getApiObjectUrl() + this.record.uuid
|
||
|
}
|
||
|
this.$emit('save', url)
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
</script>
|