3
0

Implement opening record page in a modal

This commit is contained in:
yonkov 2022-11-08 13:00:10 +02:00 committed by Atanas Yonkov
parent 18248a2376
commit 7aded0c977
11 changed files with 235 additions and 33 deletions

View File

@ -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: {

View File

@ -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)
}

View File

@ -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') },

View 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>

View File

@ -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 } })
}

View File

@ -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 })

View File

@ -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 } })

View File

@ -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 })
}
},
},
}

View File

@ -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,
},

View File

@ -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',
)

View File

@ -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