Implement opening record page in a modal
This commit is contained in:
parent
18248a2376
commit
7aded0c977
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<b-container
|
||||
fluid
|
||||
class="bg-white shadow border-top p-3"
|
||||
:class="{'shadow border-top': !showRecordModal}"
|
||||
class="bg-white p-3"
|
||||
>
|
||||
<b-row
|
||||
no-gutters
|
||||
@ -19,10 +20,10 @@
|
||||
@click.prevent="$emit('back')"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'chevron-left']"
|
||||
:icon="['fas', showRecordModal ? 'times' : 'chevron-left']"
|
||||
class="back-icon"
|
||||
/>
|
||||
{{ labels.back || $t('label.back') }}
|
||||
{{ showRecordModal ? $t('label.close') : labels.back || $t('label.back') }}
|
||||
</b-button>
|
||||
</div>
|
||||
|
||||
@ -173,6 +174,11 @@ export default {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
|
||||
showRecordModal: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
@ -594,6 +594,7 @@ import { components, url } from '@cortezaproject/corteza-vue'
|
||||
import draggable from 'vuedraggable'
|
||||
import RecordListFilter from 'corteza-webapp-compose/src/components/Common/RecordListFilter'
|
||||
import ColumnPicker from 'corteza-webapp-compose/src/components/Admin/Module/Records/ColumnPicker'
|
||||
|
||||
const { CInputSearch } = components
|
||||
|
||||
export default {
|
||||
@ -1150,8 +1151,14 @@ export default {
|
||||
query: null,
|
||||
}
|
||||
|
||||
if (this.options.openInNewTab) {
|
||||
if (this.options.recordDisplayOption === 'newTab') {
|
||||
window.open(this.$router.resolve(route).href)
|
||||
} else if (this.options.recordDisplayOption === 'modal') {
|
||||
this.$root.$emit('show-record-modal', {
|
||||
moduleID: this.recordListModule.moduleID,
|
||||
recordPageID: this.recordPageID,
|
||||
recordID,
|
||||
})
|
||||
} else {
|
||||
this.$router.push(route)
|
||||
}
|
||||
|
||||
@ -250,12 +250,20 @@
|
||||
<b-form-checkbox v-model="options.selectable">
|
||||
{{ $t('recordList.selectable') }}
|
||||
</b-form-checkbox>
|
||||
<b-form-checkbox
|
||||
v-model="options.openInNewTab"
|
||||
>
|
||||
{{ $t('recordList.record.openInNewTab') }}
|
||||
</b-form-checkbox>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group
|
||||
:label="$t('recordList.record.recordDisplayOptions')"
|
||||
:label-cols="3"
|
||||
breakpoint="md"
|
||||
horizontal
|
||||
>
|
||||
<b-form-select
|
||||
v-model="options.recordDisplayOption"
|
||||
:options="recordDisplayOptions"
|
||||
/>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group
|
||||
horizontal
|
||||
:label-cols="3"
|
||||
@ -324,6 +332,14 @@ export default {
|
||||
pages: 'page/set',
|
||||
}),
|
||||
|
||||
recordDisplayOptions () {
|
||||
return [
|
||||
{ value: 'sameTab', text: this.$t('recordList.record.openInSameTab') },
|
||||
{ value: 'newTab', text: this.$t('recordList.record.openInNewTab') },
|
||||
{ value: 'modal', text: this.$t('recordList.record.openInModal') },
|
||||
]
|
||||
},
|
||||
|
||||
moduleOptions () {
|
||||
return [
|
||||
{ moduleID: NoID, name: this.$t('general.label.none') },
|
||||
|
||||
123
client/web/compose/src/components/Public/Record/Modal.vue
Normal file
123
client/web/compose/src/components/Public/Record/Modal.vue
Normal file
@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<b-modal
|
||||
id="record-modal"
|
||||
v-model="showRecordModal"
|
||||
scrollable
|
||||
body-class="p-0"
|
||||
footer-class="p-0"
|
||||
size="xl"
|
||||
@hidden="hideModal"
|
||||
>
|
||||
<template #modal-title>
|
||||
<portal-target
|
||||
name="record-modal-header"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<view-record
|
||||
:namespace="namespace"
|
||||
:page="page"
|
||||
:module="module"
|
||||
:record-i-d="recordID"
|
||||
:show-record-modal="showRecordModal"
|
||||
/>
|
||||
|
||||
<template #modal-footer>
|
||||
<portal-target
|
||||
name="record-modal-footer"
|
||||
class="w-100 m-0"
|
||||
/>
|
||||
</template>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import record from 'corteza-webapp-compose/src/mixins/record'
|
||||
import { compose } from '@cortezaproject/corteza-js'
|
||||
import ViewRecord from 'corteza-webapp-compose/src/views/Public/Pages/Records/View'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
namespaces: 'block',
|
||||
},
|
||||
|
||||
name: 'RecordModal',
|
||||
|
||||
components: {
|
||||
ViewRecord,
|
||||
},
|
||||
|
||||
mixins: [
|
||||
record,
|
||||
],
|
||||
|
||||
props: {
|
||||
namespace: {
|
||||
type: compose.Namespace,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
showRecordModal: false,
|
||||
recordID: null,
|
||||
module: null,
|
||||
page: null,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getModuleByID: 'module/getByID',
|
||||
getPageByID: 'page/getByID',
|
||||
}),
|
||||
},
|
||||
|
||||
created () {
|
||||
this.$root.$on('show-record-modal', this.showModal)
|
||||
this.showModal(this.$route.query)
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
this.$root.$off('show-record-modal')
|
||||
},
|
||||
|
||||
methods: {
|
||||
showModal ({ recordID, moduleID, recordPageID }) {
|
||||
if (recordID && moduleID && recordPageID) {
|
||||
this.recordID = recordID
|
||||
this.module = this.getModuleByID(moduleID)
|
||||
this.page = this.getPageByID(recordPageID)
|
||||
|
||||
this.showRecordModal = true
|
||||
|
||||
// persist the modal in the url
|
||||
this.$router.replace({
|
||||
query: {
|
||||
recordID,
|
||||
moduleID,
|
||||
recordPageID: this.page.pageID,
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
hideModal () {
|
||||
this.$router.replace({ query: { } })
|
||||
this.recordID = null
|
||||
this.module = null
|
||||
this.page = null
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#record-modal .modal-dialog {
|
||||
height: 100%;
|
||||
max-width: 90vw;
|
||||
}
|
||||
</style>
|
||||
@ -153,6 +153,9 @@ export default {
|
||||
.then(() => {
|
||||
if (this.record.valueErrors.set) {
|
||||
this.toastWarning(this.$t('notification:record.validationWarnings'))
|
||||
} else if (this.showRecordModal) {
|
||||
this.inEditing = false
|
||||
this.inCreating = false
|
||||
} else {
|
||||
this.$router.push({ name: route, params: { ...this.$route.params, recordID: this.record.recordID } })
|
||||
}
|
||||
|
||||
@ -30,13 +30,6 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
title () {
|
||||
const { name, handle } = this.module
|
||||
return this.$t('page:public.record.create.title', { name: name || handle, interpolation: { escapeValue: false } })
|
||||
},
|
||||
},
|
||||
|
||||
created () {
|
||||
this.record = new compose.Record(this.module, { values: this.values })
|
||||
|
||||
|
||||
@ -13,13 +13,6 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
title () {
|
||||
const { name, handle } = this.module
|
||||
return this.$t('page:public.record.edit.title', { name: name || handle, interpolation: { escapeValue: false } })
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleBack () {
|
||||
this.$router.push({ name: 'page.record', params: { recordID: this.recordID, pageID: this.page.pageID } })
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<div class="d-flex flex-grow-1 w-100">
|
||||
<div
|
||||
:class="{ 'flex-column': showRecordModal }"
|
||||
class="d-flex flex-grow-1 w-100 h-100"
|
||||
>
|
||||
<b-alert
|
||||
v-if="isDeleted"
|
||||
show
|
||||
@ -8,7 +11,9 @@
|
||||
{{ $t('record.recordDeleted') }}
|
||||
</b-alert>
|
||||
|
||||
<portal to="topbar-title">
|
||||
<portal
|
||||
:to="portalTopbarTitle"
|
||||
>
|
||||
{{ title }}
|
||||
</portal>
|
||||
|
||||
@ -20,7 +25,9 @@
|
||||
@reload="loadRecord()"
|
||||
/>
|
||||
|
||||
<portal to="toolbar">
|
||||
<portal
|
||||
:to="portalRecordToolbar"
|
||||
>
|
||||
<record-toolbar
|
||||
:module="module"
|
||||
:record="record"
|
||||
@ -32,6 +39,7 @@
|
||||
:in-editing="inEditing"
|
||||
:hide-clone="inCreating"
|
||||
:hide-add="inCreating"
|
||||
:show-record-modal="showRecordModal"
|
||||
@add="handleAdd()"
|
||||
@clone="handleClone()"
|
||||
@edit="handleEdit()"
|
||||
@ -87,6 +95,11 @@ export default {
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
// Open record in a modal
|
||||
showRecordModal: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
|
||||
data () {
|
||||
@ -97,6 +110,14 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
portalTopbarTitle () {
|
||||
return this.showRecordModal ? 'record-modal-header' : 'topbar-title'
|
||||
},
|
||||
|
||||
portalRecordToolbar () {
|
||||
return this.showRecordModal ? 'record-modal-footer' : 'toolbar'
|
||||
},
|
||||
|
||||
newRouteParams () {
|
||||
// Remove recordID and values from route params
|
||||
const { recordID, values, ...params } = this.$route.params
|
||||
@ -119,7 +140,9 @@ export default {
|
||||
|
||||
title () {
|
||||
const { name, handle } = this.module
|
||||
return this.$t('page:public.record.view.title', { name: name || handle, interpolation: { escapeValue: false } })
|
||||
const titlePrefix = this.inCreating ? 'create' : this.inEditing ? 'edit' : 'view'
|
||||
|
||||
return this.$t(`page:public.record.${titlePrefix}.title`, { name: name || handle, interpolation: { escapeValue: false } })
|
||||
},
|
||||
},
|
||||
|
||||
@ -183,19 +206,42 @@ export default {
|
||||
* Not the best way since we can not always know where we
|
||||
* came from (and "were" is back).
|
||||
*/
|
||||
this.$router.back()
|
||||
if (this.showRecordModal) {
|
||||
this.inEditing = false
|
||||
this.inCreating = false
|
||||
this.$bvModal.hide('record-modal')
|
||||
} else {
|
||||
this.$router.back()
|
||||
}
|
||||
},
|
||||
|
||||
handleAdd () {
|
||||
this.$router.push({ name: 'page.record.create', params: this.newRouteParams })
|
||||
if (this.showRecordModal) {
|
||||
this.inEditing = true
|
||||
this.inCreating = true
|
||||
this.record = new compose.Record(this.module, { values: this.values })
|
||||
} else {
|
||||
this.$router.push({ name: 'page.record.create', params: this.newRouteParams })
|
||||
}
|
||||
},
|
||||
|
||||
handleClone () {
|
||||
this.$router.push({ name: 'page.record.create', params: { pageID: this.page.pageID, values: this.record.values } })
|
||||
if (this.showRecordModal) {
|
||||
this.inEditing = true
|
||||
this.inCreating = true
|
||||
this.record = new compose.Record(this.module, { values: this.record.values })
|
||||
} else {
|
||||
this.$router.push({ name: 'page.record.create', params: { pageID: this.page.pageID, values: this.record.values } })
|
||||
}
|
||||
},
|
||||
|
||||
handleEdit () {
|
||||
this.$router.push({ name: 'page.record.edit', params: this.$route.params })
|
||||
if (this.showRecordModal) {
|
||||
this.inCreating = false
|
||||
this.inEditing = true
|
||||
} else {
|
||||
this.$router.push({ name: 'page.record.edit', params: this.$route.params })
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -62,6 +62,10 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<record-modal
|
||||
:namespace="namespace"
|
||||
/>
|
||||
|
||||
<attachment-modal />
|
||||
</div>
|
||||
</template>
|
||||
@ -69,6 +73,7 @@
|
||||
import { mapActions } from 'vuex'
|
||||
import Grid from 'corteza-webapp-compose/src/components/Public/Page/Grid'
|
||||
import AttachmentModal from 'corteza-webapp-compose/src/components/Public/Page/Attachment/Modal'
|
||||
import RecordModal from 'corteza-webapp-compose/src/components/Public/Record/Modal'
|
||||
import PageTranslator from 'corteza-webapp-compose/src/components/Admin/Page/PageTranslator'
|
||||
import { compose, NoID } from '@cortezaproject/corteza-js'
|
||||
|
||||
@ -80,6 +85,7 @@ export default {
|
||||
components: {
|
||||
Grid,
|
||||
AttachmentModal,
|
||||
RecordModal,
|
||||
PageTranslator,
|
||||
},
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@ interface Options {
|
||||
hideRecordPermissionsButton: boolean;
|
||||
allowExport: boolean;
|
||||
perPage: number;
|
||||
recordDisplayOption: string;
|
||||
|
||||
fullPageNavigation: boolean;
|
||||
showTotalCount: boolean;
|
||||
@ -38,6 +39,7 @@ interface Options {
|
||||
linkToParent: boolean;
|
||||
|
||||
// Should records be opened in a new tab
|
||||
// legacy field that has been removed but we keep it for backwards compatibility
|
||||
openInNewTab: boolean;
|
||||
|
||||
// Are table rows selectable
|
||||
@ -66,6 +68,7 @@ const defaults: Readonly<Options> = Object.freeze({
|
||||
hideRecordPermissionsButton: true,
|
||||
allowExport: false,
|
||||
perPage: 20,
|
||||
recordDisplayOption: 'sameTab',
|
||||
|
||||
fullPageNavigation: true,
|
||||
showTotalCount: true,
|
||||
@ -100,7 +103,7 @@ export class PageBlockRecordList extends PageBlock {
|
||||
if (!o) return
|
||||
|
||||
Apply(this.options, o, CortezaID, 'moduleID')
|
||||
Apply(this.options, o, String, 'prefilter', 'presort', 'selectMode', 'positionField', 'refField')
|
||||
Apply(this.options, o, String, 'prefilter', 'presort', 'selectMode', 'positionField', 'refField', 'recordDisplayOption')
|
||||
Apply(this.options, o, Number, 'perPage')
|
||||
|
||||
if (o.fields) {
|
||||
@ -111,6 +114,10 @@ export class PageBlockRecordList extends PageBlock {
|
||||
this.options.editFields = o.editFields
|
||||
}
|
||||
|
||||
if (o.openInNewTab) {
|
||||
this.options.recordDisplayOption = 'newTab'
|
||||
}
|
||||
|
||||
Apply(this.options, o, Boolean,
|
||||
'hideHeader',
|
||||
'hideAddButton',
|
||||
@ -129,7 +136,6 @@ export class PageBlockRecordList extends PageBlock {
|
||||
'hideRecordPermissionsButton',
|
||||
'editable',
|
||||
'draggable',
|
||||
'openInNewTab',
|
||||
'linkToParent',
|
||||
)
|
||||
|
||||
|
||||
@ -350,7 +350,9 @@ recordList:
|
||||
presortLabel: Presort records
|
||||
presortPlaceholder: field1 DESC, field2 ASC
|
||||
showTotalCount: Show total record count
|
||||
openInSameTab: Open records in the same tab
|
||||
openInNewTab: Open records in a new tab
|
||||
openInModal: Open records in a modal
|
||||
linkToParent: Link to parent record
|
||||
tooltip:
|
||||
clone: Clone record
|
||||
@ -358,6 +360,7 @@ recordList:
|
||||
undelete: Undelete record
|
||||
reminder: Reminder
|
||||
view: View record
|
||||
recordDisplayOptions: Record display options
|
||||
recordPage: record page
|
||||
refField:
|
||||
footnote: Field that links records with the parent record
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user