Add option for reference on record block

This commit is contained in:
Kelani Tolulope
2023-04-06 11:12:04 +01:00
parent f42da32145
commit 7e3020dd7d
5 changed files with 192 additions and 23 deletions
@@ -11,7 +11,7 @@
</div>
<div
v-else-if="module"
v-else-if="fieldModule"
class="mt-3"
>
<div
@@ -46,6 +46,7 @@
<field-viewer
v-bind="{ ...$props, field }"
:extra-options="options"
:record="fieldRecord"
/>
</div>
<i
@@ -60,7 +61,8 @@
</wrap>
</template>
<script>
import { NoID } from '@cortezaproject/corteza-js'
import { compose, NoID } from '@cortezaproject/corteza-js'
import { mapActions } from 'vuex'
import base from './base'
import FieldViewer from 'corteza-webapp-compose/src/components/ModuleFields/Viewer'
import Hint from 'corteza-webapp-compose/src/components/Common/Hint.vue'
@@ -84,27 +86,42 @@ export default {
conditionalFields,
],
data () {
return {
referenceRecord: undefined,
referenceModule: undefined,
}
},
computed: {
fields () {
if (!this.module) {
if (!this.fieldModule) {
// No module, no fields
return []
}
if (!this.options.fields || this.options.fields.length === 0) {
// No fields defined in the options, show all (buy system)
return this.module.fields
return this.fieldModule.fields
}
// Show filtered & ordered list of fields
return this.module.filterFields(this.options.fields).map(f => {
return this.fieldModule.filterFields(this.options.fields).map(f => {
f.label = f.isSystem ? this.$t(`field:system.${f.name}`) : f.label || f.name
return f
})
},
fieldModule () {
return this.options.referenceField ? this.referenceModule : this.module
},
fieldRecord () {
return this.options.referenceField ? this.referenceRecord : this.record
},
processing () {
return !this.record || this.evaluating
return !this.fieldRecord || this.evaluating
},
},
@@ -124,10 +141,73 @@ export default {
if (recordID !== NoID) {
this.fetchUsers(this.fields, [this.record])
}
if (this.options.referenceModuleID) {
this.fetchReferenceModule(this.options.referenceModuleID)
}
},
},
options: {
deep: true,
handler (options) {
if (options.referenceModuleID) {
this.fetchReferenceModule(options.referenceModuleID)
}
},
},
},
methods: {
...mapActions({
findModuleByID: 'module/findByID',
}),
fetchReferenceModule (moduleID) {
if (!moduleID) {
this.referenceModule = undefined
return
}
this.findModuleByID({ namespace: this.namespace.namespaceID, moduleID: this.options.referenceModuleID })
.then(module => {
this.referenceModule = new compose.Module({ ...module })
if (this.options.referenceField) {
this.loadRecord(this.referenceModule)
}
})
},
loadRecord (module) {
if (!module) return
const { namespaceID, moduleID } = module
const { referenceField } = this.options
const field = this.module.fields.find(({ fieldID }) => fieldID === referenceField)
const recordID = this.record.values[field.name]
if (!recordID || !field) {
this.referenceRecord = new compose.Record(this.fieldModule, {})
return
}
if (field.isMulti) {
this.referenceRecord = new compose.Record(this.fieldModule, {})
return
}
this.$ComposeAPI.recordRead({ namespaceID, moduleID, recordID })
.then(record => {
this.referenceRecord = new compose.Record(this.fieldModule, { ...record })
})
.catch((e) => {
this.referenceRecord = new compose.Record(this.fieldModule, {})
this.toastErrorHandler(this.$t('notification:record.loadFailed'))(e)
})
},
},
}
</script>
<style lang="scss">
@@ -2,28 +2,58 @@
<b-tab
:title="$t('record.label')"
>
<fieldset
class="form-group"
>
<label>
{{ $t('general.module') }}
</label>
<input
v-if="module"
v-model="module.name"
class="form-control"
type="text"
readonly
<b-row>
<b-col
cols="12"
md="6"
>
</fieldset>
<fieldset
class="form-group"
>
<label>
{{ $t('general.module') }}
</label>
<input
v-if="module"
v-model="module.name"
class="form-control"
type="text"
readonly
>
</fieldset>
</b-col>
<b-col
cols="12"
md="6"
>
<b-form-group
:label="$t('record.referenceRecordField')"
:description="$t('record.referenceRecordFieldDescription')"
label-class="text-primary"
>
<vue-select
v-model="options.referenceField"
:options="recordSelectorFields"
:get-option-label="getFieldLabel"
:placeholder="$t('record.referenceRecordFieldPlaceholder')"
:reduce="field => field.fieldID"
:calculate-position="calculateDropdownPosition"
append-to-body
class="bg-white"
@input="updateReferenceModule($event, [])"
/>
</b-form-group>
</b-col>
</b-row>
<b-form-group
:label="$t('module:general.fields')"
>
<field-picker
v-if="module"
:module="module"
:module="fieldModule"
:fields.sync="options.fields"
style="max-height: 52vh;"
/>
@@ -160,6 +190,8 @@
import base from './base'
import FieldPicker from 'corteza-webapp-compose/src/components/Common/FieldPicker'
import { VueSelect } from 'vue-select'
import { mapActions } from 'vuex'
import { compose } from '@cortezaproject/corteza-js'
export default {
i18nOptions: {
@@ -175,6 +207,12 @@ export default {
extends: base,
data () {
return {
referenceModule: undefined,
}
},
computed: {
documentationURL () {
// eslint-disable-next-line no-undef
@@ -193,9 +231,26 @@ export default {
{ value: 'modal', text: this.$t('record.openInModal') },
]
},
recordSelectorFields () {
return this.module.fields.filter(f => f.kind === 'Record' && !f.isMulti)
},
fieldModule () {
return (this.options.referenceField && this.referenceModule) ? this.referenceModule : this.module
},
},
created () {
if (this.options.referenceField) {
this.updateReferenceModule(this.options.referenceField, this.options.fields)
}
},
methods: {
...mapActions({
findModuleByID: 'module/findByID',
}),
addRule () {
this.options.fieldConditions.push({
field: undefined,
@@ -214,6 +269,30 @@ export default {
getOptionLabel (option) {
return option.label || option.name
},
getFieldLabel ({ name, label }) {
return label || name
},
updateReferenceModule (fieldID, fields) {
if (!fieldID) {
this.block.options.fields = []
this.block.options.referenceModuleID = undefined
return
}
const field = this.recordSelectorFields.find(f => f.fieldID === fieldID)
const moduleID = field && field.options && field.options.moduleID
if (moduleID) {
this.findModuleByID({ namespace: this.namespace.namespaceID, moduleID })
.then(module => {
this.block.options.fields = fields
this.block.options.referenceModuleID = module.moduleID
this.referenceModule = new compose.Module({ ...module })
})
}
},
},
}
</script>
@@ -96,6 +96,10 @@ function GetComponent ({ block, mode = defaultMode }) {
const { kind } = block
for (mode of uniq([capitalize(mode), defaultMode])) {
if (mode === 'Editor' && block.options.referenceField && block.options.referenceModuleID) {
mode = 'Base'
}
const cmpName = kind + mode
if (Object.hasOwnProperty.call(Registry, cmpName)) {
return Registry[cmpName]
@@ -13,7 +13,8 @@ interface Options {
fieldConditions: FieldCondition[];
magnifyOption: string;
recordSelectorDisplayOption: string;
referenceField?: string;
referenceModuleID?: string;
}
const defaults: Readonly<Options> = Object.freeze({
@@ -21,6 +22,8 @@ const defaults: Readonly<Options> = Object.freeze({
fieldConditions: [],
magnifyOption: '',
recordSelectorDisplayOption: 'sameTab',
referenceField: '',
referenceModuleID: undefined
})
export class PageBlockRecord extends PageBlock {
@@ -36,7 +39,7 @@ export class PageBlockRecord extends PageBlock {
applyOptions (o?: Partial<Options>): void {
if (!o) return
Apply(this.options, o, String, 'magnifyOption', 'recordSelectorDisplayOption')
Apply(this.options, o, String, 'magnifyOption', 'recordSelectorDisplayOption', 'referenceField', 'referenceModuleID')
if (o.fields) {
this.options.fields = o.fields
@@ -214,6 +214,9 @@ metric:
valueLabel: Value style
label: Metric
record:
referenceRecordField: Reference record field
referenceRecordFieldPlaceholder: Select reference record selector
referenceRecordFieldDescription: Multi value record selector fields are not available
confirmDelete: Are you sure you want to delete this record?
deleteFailed: Could not delete record
deleteRecord: Delete record