1
0
mirror of https://github.com/PanJiaChen/vue-element-admin.git synced 2025-08-10 20:39:48 +08:00

feat: Remove context (#508)

* Change definition for v-model of fields using reactive store

* change custom validateValue to custom and overwrite parsedValue.

* Delete unused parameters.

* Add queue for persistence

* fix: Create entity.

* Add return value as array for persistence

* Add multiple commit for panel

* remove commnets

* Change context session to preference.

* fix: Load window.

* Add support to seekrecord for panel

* Set default value to isActive columnName.

* set default values.

* Separate template mobile and panel desktop with mixin.

* set values into panel with first load of records.

* fix lookups value and display value.

* change `DisplayColumn_${columnName}` to `displayColumnName` property.

* fix create entity with default values.

* Set default values and fix browser search.

* fix context values from SmartBrowser.

* fix: Associated process.

* set context values to process associated.

* fix set values.

* fix style field components.

* fix send values to server.

Co-authored-by: Yamel Senih <ysenih@erpya.com>
This commit is contained in:
Edwin Betancourt 2020-06-12 12:07:24 -04:00 committed by GitHub
parent d21b7f3f89
commit 0800511177
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 5489 additions and 4945 deletions

View File

@ -6,10 +6,10 @@ import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js'
* @param {string} tableName
* @param {array} attributesList
*/
export function createEntity({ tableName, attributesList }) {
export function createEntity({ tableName, attributes }) {
return Instance.call(this).requestCreateEntity({
tableName,
attributesList
attributesList: attributes
})
}
@ -20,12 +20,12 @@ export function createEntity({ tableName, attributesList }) {
* @param {string} recordUuid
* @param {array} attributesList
*/
export function updateEntity({ tableName, recordId, recordUuid, attributesList }) {
export function updateEntity({ tableName, recordId, recordUuid, attributes }) {
return Instance.call(this).requestUpdateEntity({
tableName,
recordId,
recordUuid,
attributesList
attributesList: attributes
})
}

View File

@ -8,7 +8,7 @@ import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js'
* @param {string} directQuery
* @param {string|number} value
*/
export function getLookup({
export function requestLookup({
tableName,
directQuery,
value
@ -25,16 +25,21 @@ export function getLookup({
* The main attributes that function hope are:
* @param {string} tableName
* @param {string} query
* @param {Array<String>|<Number>} valuesList
* @param {string} pageToken
* @param {number} pageSize
*/
export function getLookupList({
export function requestLookupList({
tableName,
query,
valuesList = [],
pageToken,
pageSize
}) {
return Instance.call(this).requestListLookupFromReference({
tableName,
query,
valuesList,
pageToken,
pageSize
})

View File

@ -139,7 +139,7 @@ export const contextMixin = {
})
return value.map(fieldItem => {
if (fieldItem.componentPath === 'FieldSelect') {
return 'DisplayColumn_' + fieldItem.columnName
return fieldItem.displayColumnName
}
return fieldItem.columnName
})
@ -174,7 +174,7 @@ export const contextMixin = {
},
getOldRouteOfWindow() {
if (this.panelType === 'window') {
const oldRoute = this.$store.state.windowControl.windowOldRoute
const oldRoute = this.$store.state.window.windowOldRoute
if (!this.isEmptyValue(oldRoute.query.action) && oldRoute.query.action !== 'create-new' && this.$route.query.action === 'create-new') {
return oldRoute
}
@ -234,7 +234,7 @@ export const contextMixin = {
actionContextMenu(event) {
switch (event.srcKey) {
case 'f2':
this.$store.dispatch('resetPanelToNew', {
this.$store.dispatch('setDefaultValues', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
recordUuid: this.recordUuid,
@ -395,14 +395,15 @@ export const contextMixin = {
if (action.type === 'process') {
// Add context from view open in process to opening
if (action.parentUuidAssociated || action.containerUuidAssociated) {
const contextValues = this.$store.getters.getContextView({
const attributes = this.$store.getters.getValuesView({
parentUuid: action.parentUuidAssociated,
containerUuid: action.containerUuidAssociated
})
if (!this.isEmptyValue(contextValues)) {
this.$store.dispatch('setMultipleContextView', {
if (!this.isEmptyValue(attributes)) {
this.$store.dispatch('updateValuesOfContainer', {
containerUuid: action.uuid,
values: contextValues
attributes
})
}
}
@ -437,7 +438,7 @@ export const contextMixin = {
containerUuid: this.containerUuid,
recordUuid: this.recordUuid,
panelType: this.panelType,
isNewRecord: action.action === 'resetPanelToNew',
isNewRecord: action.action === 'setDefaultValues',
tableName: action.tableName,
recordId: action.recordId
})

View File

@ -186,7 +186,7 @@
:in-table="true"
:metadata-field="{
...fieldAttributes,
displayColumn: scope.row['DisplayColumn_' + fieldAttributes.columnName],
displayColumn: scope.row[fieldAttributes.displayColumnName],
tableIndex: scope.$index,
rowKey: scope.row[getterPanel.keyColumn],
keyColumn: getterPanel.keyColumn,
@ -470,22 +470,21 @@ export default {
isPanelWindow() {
return Boolean(this.panelType === 'window')
},
getterContextClientId() {
preferenceClientId() {
if (this.isPanelWindow) {
return this.$store.getters.getContextClientId
return this.$store.getters.getPreferenceClientId
}
return undefined
},
isReadOnlyParent() {
if (this.isPanelWindow) {
if (this.$store.getters.getContextIsActive(this.parentUuid) === false) {
if (!this.$store.getters.getContainerIsActive(this.parentUuid)) {
return true
}
if (this.$store.getters.getContextProcessing(this.parentUuid) === true ||
this.$store.getters.getContextProcessing(this.parentUuid) === 'Y') {
if (this.$store.getters.getContainerProcessing(this.parentUuid)) {
return true
}
if (this.$store.getters.getContextProcessed(this.parentUuid)) {
if (this.$store.getters.getContainerProcessed(this.parentUuid)) {
return true
}
}
@ -617,7 +616,7 @@ export default {
*/
displayedValue(row, field) {
if (typeof row[field.columnName] === 'boolean') {
// replace boolean true-false value for 'Yes' or 'Not'
// replace boolean true-false value for 'Yes' or 'Not' ('Si' or 'No' for spanish)
return row[field.columnName] ? this.$t('components.switchActiveText') : this.$t('components.switchInactiveText')
} else if (field.componentPath === 'FieldDate' || field.componentPath === 'FieldTime') {
let cell = row[field.columnName]
@ -634,10 +633,12 @@ export default {
displayType: field.displayType,
number: row[field.columnName]
})
} else if (field.componentPath === 'FieldSelect' && this.isEmptyValue(row['DisplayColumn_' + field.columnName]) && row[field.columnName] === 0) {
} else if (field.componentPath === 'FieldSelect' &&
this.isEmptyValue(row[field.displayColumnName]) &&
row[field.columnName] === 0) {
return field.defaultValue
}
return row['DisplayColumn_' + field.columnName] || row[field.columnName]
return row[field.displayColumnName] || row[field.columnName]
},
rowCanBeEdited(record, fieldAttributes) {
if (!this.isParent) {
@ -663,28 +664,19 @@ export default {
},
isReadOnlyRow(row, field) {
// evaluate context
if (this.getterContextClientId !== parseInt(row.AD_Client_ID, 10)) {
if (this.preferenceClientId !== parseInt(row.AD_Client_ID, 10)) {
return true
}
if (fieldIsDisplayed(field)) {
// const fieldReadOnlyAllForm = FIELDS_READ_ONLY_FORM.filter(item => {
// return item.isChangedAllForm &&
// Object.prototype.hasOwnProperty.call(row, item.columnName)
// })
// // columnName: Processed, Processing
// if (fieldReadOnlyAllForm.length) {
// const isReadOnlyAllRow = Boolean(fieldReadOnlyAllForm.find(item => row[item.columnName] === item.valueIsReadOnlyForm))
// return isReadOnlyAllRow
// }
// columnName: IsActive
const fieldReadOnlyForm = FIELDS_READ_ONLY_FORM.find(item => {
return !item.isChangedAllForm &&
// columnName: IsActive, Processed, Processing
Object.prototype.hasOwnProperty.call(row, item.columnName)
})
if (fieldReadOnlyForm) {
const isReadOnlyRow = row[fieldReadOnlyForm.columnName] === fieldReadOnlyForm.valueIsReadOnlyForm && field.columnName !== fieldReadOnlyForm.columnName
return isReadOnlyRow
return field.columnName !== fieldReadOnlyForm.columnName &&
row[fieldReadOnlyForm.columnName] === fieldReadOnlyForm.valueIsReadOnlyForm
}
}
return false
@ -1078,8 +1070,7 @@ export default {
}
}
}
</style>
<style>
.el-table .warning-row {
background: rgba(161, 250, 223, 0.945);
}

View File

@ -86,14 +86,13 @@ export const menuTableMixin = {
},
isReadOnlyParent() {
if (this.isPanelWindow) {
if (this.$store.getters.getContextIsActive(this.parentUuid) === false) {
if (!this.$store.getters.getContainerIsActive(this.parentUuid)) {
return true
}
if (this.$store.getters.getContextProcessing(this.parentUuid) === true ||
this.$store.getters.getContextProcessing(this.parentUuid) === 'Y') {
if (this.$store.getters.getContainerProcessing(this.parentUuid)) {
return true
}
if (this.$store.getters.getContextProcessed(this.parentUuid)) {
if (this.$store.getters.getContainerProcessed(this.parentUuid)) {
return true
}
}
@ -146,7 +145,7 @@ export const menuTableMixin = {
})
return value.map(fieldItem => {
if (fieldItem.componentPath === 'FieldSelect') {
return 'DisplayColumn_' + fieldItem.columnName
return fieldItem.displayColumnName
}
return fieldItem.columnName
})

View File

@ -86,10 +86,10 @@ export default {
return 50
},
isVisibleDialog() {
return this.$store.state.processControl.isVisibleDialog
return this.$store.state.process.isVisibleDialog
},
modalMetadata() {
return this.$store.state.processControl.metadata
return this.$store.state.process.metadata
},
windowRecordSelected() {
return this.$store.state.window.recordSelected

View File

@ -6,7 +6,7 @@
:on-remove="handleRemove"
:on-success="handleSuccess"
:on-error="handleError"
:class="'image-uploader ' + metadata.cssClassName"
:class="cssClassStyle"
action="https://jsonplaceholder.typicode.com/posts/"
:disabled="isDisabled"
@change="preHandleChange"
@ -21,21 +21,14 @@
</template>
<script>
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
export default {
name: 'FieldBinary',
mixins: [fieldMixin],
watch: {
valueModel(value) {
if (this.metadata.inTable) {
this.value = value
}
},
'metadata.value'(value) {
if (!this.metadata.inTable) {
this.value = value
}
computed: {
cssClassStyle() {
return this.metadata.cssClassName + ' image-uploader'
}
},
methods: {

View File

@ -8,22 +8,14 @@
</template>
<script>
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import fieldMixinText from '@/components/ADempiere/Field/mixin/mixinFieldText.js'
export default {
name: 'FieldButton',
mixins: [fieldMixin],
watch: {
valueModel(value) {
if (this.metadata.inTable) {
this.value = String(value)
}
},
'metadata.value'(value) {
if (!this.metadata.inTable) {
this.value = String(value)
}
}
}
mixins: [
fieldMixin,
fieldMixinText
]
}
</script>

View File

@ -4,34 +4,20 @@
v-model="value"
show-alpha
:disabled="isDisabled"
:class="metadata.cssClassName"
:class="cssClassStyle"
@change="preHandleChange"
/>
</template>
<script>
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import fieldMixinText from '@/components/ADempiere/Field/mixin/mixinFieldText.js'
export default {
name: 'FieldColor',
mixins: [fieldMixin],
watch: {
valueModel(value) {
if (this.metadata.inTable) {
if (this.isEmptyValue(value)) {
value = ''
}
this.value = String(value)
}
},
'metadata.value'(value) {
if (!this.metadata.inTable) {
if (this.isEmptyValue(value)) {
value = ''
}
this.value = String(value)
}
}
}
mixins: [
fieldMixin,
fieldMixinText
]
}
</script>

View File

@ -10,7 +10,7 @@
:start-placeholder="$t('components.dateStartPlaceholder')"
:end-placeholder="$t('components.dateEndPlaceholder')"
unlink-panels
:class="'date-base ' + metadata.cssClassName"
:class="cssClassStyle"
:readonly="Boolean(metadata.readonly)"
:disabled="isDisabled"
:picker-options="pickerOptions"
@ -23,20 +23,14 @@
</template>
<script>
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import { DATE_PLUS_TIME } from '@/utils/ADempiere/references'
export default {
name: 'FieldDate',
mixins: [fieldMixin],
data() {
// value render
let value = this.metadata.value
if (this.metadata.inTable) {
value = this.valueModel
}
return {
value: this.parsedDateValue(value),
pickerOptionsDate: {
shortcuts: [{
text: this.$t('components.date.Today'),
@ -117,6 +111,9 @@ export default {
}
return picker
},
cssClassStyle() {
return this.metadata.cssClassName + ' custom-field-date'
},
/**
* Parse the date format to be compatible with element-ui
*/
@ -149,22 +146,53 @@ export default {
return this.pickerOptionsDateRange
}
return this.pickerOptionsDate
}
},
watch: {
valueModel(value) {
if (this.metadata.inTable) {
this.value = this.parsedDateValue(value)
}
},
'metadata.value'(value) {
if (!this.metadata.inTable) {
this.value = this.parsedDateValue(value)
value: {
get() {
let value = this.$store.getters.getValueOfField({
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName
})
if (!this.metadata.isRange) {
return this.parseValue(value)
}
const valueTo = this.$store.getters.getValueOfField({
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnNameTo
})
value = this.parseValue([value, valueTo])
return value
},
set(value) {
let startValue = value
if (Array.isArray(value)) {
startValue = value[0]
}
this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName,
value: startValue
})
if (!this.metadata.isRange) {
return
}
const endValue = value[1]
this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnNameTo,
value: endValue
})
}
}
},
methods: {
parsedDateValue(value) {
parseValue(value) {
// not return undefined to v-model
if (this.isEmptyValue(value)) {
if (['IN', 'NOT_IN'].includes(this.metadata.operator) && this.metadata.isAdvancedQuery) {
@ -198,7 +226,11 @@ export default {
// generate range value
if (this.metadata.isRange && !this.metadata.inTable) {
let valueTo = this.metadata.valueTo
let valueTo // = this.metadata.valueTo
if (Array.isArray(value)) {
valueTo = value[1]
value = value[0]
}
if (typeof valueTo === 'number') {
valueTo = new Date(valueTo).toUTCString()
}
@ -206,6 +238,9 @@ export default {
valueTo = undefined
}
value = [value, valueTo]
if (this.isEmptyValue(value[0]) || this.isEmptyValue(value[1])) {
value = []
}
}
return value
@ -219,7 +254,7 @@ export default {
if (Array.isArray(value)) {
value = value.map(itemValue => new Date(itemValue))
}
this.handleChange(value)
this.handleFieldChange({ value })
return
}
@ -238,14 +273,17 @@ export default {
endValue = new Date(endValue)
}
this.handleChange(startValue, endValue)
this.handleFieldChange({
value: startValue,
valueTo: endValue
})
}
}
}
</script>
<style scoped>
.date-base {
.custom-field-date {
width: 100% !important;
}
</style>

View File

@ -6,7 +6,7 @@
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
:disabled="isDisabled"
:class="'avatar-uploader ' + metadata.cssClassName"
:class="cssClassStyle"
>
<img v-if="value" :src="value" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
@ -14,33 +14,21 @@
</template>
<script>
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
export default {
name: 'FieldImage',
mixins: [fieldMixin],
data() {
return {
value: ''
}
},
watch: {
valueModel(value) {
if (this.metadata.inTable) {
this.value = value
}
},
'metadata.value'(value) {
if (!this.metadata.inTable) {
this.value = value
}
computed: {
cssClassStyle() {
return this.metadata.cssClassName + ' custom-field-image'
}
},
methods: {
handleAvatarSuccess(res, file) {
this.value = URL.createObjectURL(file.raw)
// TODO: define one method to control change value
this.handleChange(this.value)
this.handleFieldChange({ value: this.value })
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg'
@ -58,8 +46,8 @@ export default {
}
</script>
<style>
.avatar-uploader .el-upload {
<style scoped>
.custom-field-image .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
@ -67,7 +55,7 @@ export default {
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
.custom-field-image .el-upload:hover {
border-color: #409EFF;
}

View File

@ -17,7 +17,7 @@
</template>
<script>
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import { getLocatorList } from '@/api/ADempiere/field/locator'
export default {
@ -25,7 +25,6 @@ export default {
mixins: [fieldMixin],
data() {
return {
value: [],
options: [],
props: {
// checkStrictly: true,
@ -59,7 +58,7 @@ export default {
if (Array.isArray(value)) {
selected = value[value.length - 1]
}
this.handleChange(selected)
this.handleFieldChange({ value: selected })
this.value = value
},
searchLocatorByWarehouse(node, resolve) {

View File

@ -11,7 +11,7 @@
:precision="precision"
:controls="isShowControls"
:controls-position="controlsPosition"
:class="'display-type-amount ' + metadata.cssClassName"
:class="cssClassStyle"
@change="preHandleChange"
@blur="focusLost"
@focus="focusGained"
@ -22,21 +22,14 @@
</template>
<script>
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import { FIELDS_DECIMALS } from '@/utils/ADempiere/references'
export default {
name: 'FieldNumber',
mixins: [fieldMixin],
data() {
// value render
let value = this.metadata.value
if (this.metadata.inTable) {
value = this.valueModel
}
value = this.validateValue(value)
return {
value: value,
showControls: true,
operation: '',
expression: /[\d\/.()%\*\+\-]/gim,
@ -45,6 +38,9 @@ export default {
}
},
computed: {
cssClassStyle() {
return this.metadata.cssClassName + ' custom-field-number'
},
maxValue() {
if (this.isEmptyValue(this.metadata.valueMax)) {
return Infinity
@ -83,22 +79,9 @@ export default {
return 'right'
}
},
watch: {
// enable to dataTable records
valueModel(value) {
if (this.metadata.inTable) {
this.value = this.validateValue(value)
}
},
'metadata.value'(value) {
if (!this.metadata.inTable) {
this.value = this.validateValue(value)
}
}
},
methods: {
validateValue(value) {
if (this.isEmptyValue(value) || isNaN(value)) {
parseValue(value) {
if (this.isEmptyValue(value)) {
return undefined
}
return Number(value)
@ -120,7 +103,7 @@ export default {
const newValue = String(this.value).slice(0, -1)
const result = this.calculationValue(newValue, event)
if (!this.isEmptyValue(result)) {
this.value = this.validateValue(result)
this.value = this.parseValue(result)
this.valueToDisplay = result
this.isShowed = true
} else {
@ -134,7 +117,7 @@ export default {
const newValue = String(this.value).slice(-1)
const result = this.calculationValue(newValue, event)
if (!this.isEmptyValue(result)) {
this.value = this.validateValue(result)
this.value = this.parseValue(result)
this.valueToDisplay = result
this.isShowed = true
} else {
@ -148,7 +131,7 @@ export default {
},
changeValue() {
if (!this.isEmptyValue(this.valueToDisplay) && this.valueToDisplay !== '...') {
const result = this.validateValue(this.valueToDisplay)
const result = this.parseValue(this.valueToDisplay)
this.preHandleChange(result)
}
this.clearVariables()
@ -158,14 +141,14 @@ export default {
}
</script>
<style lang="scss">
/* if is controls width 100% in container */
<style lang="scss" scoped>
/* Show input width 100% in container */
.el-input-number, .el-input {
width: 100% !important; /* ADempiere Custom */
}
/** Amount reference **/
.display-type-amount {
/** Align text in right input **/
.custom-field-number {
text-align: right !important;
input, .el-input__inner {
text-align: right !important;

View File

@ -6,7 +6,7 @@
:placeholder="metadata.help"
:loading="isLoading"
value-key="key"
:class="classStyle + ' ' + metadata.cssClassName"
:class="cssClassStyle"
clearable
:multiple="isSelectMultiple"
:allow-create="metadata.isSelectCreated"
@ -17,7 +17,7 @@
@clear="clearLookup"
>
<el-option
v-for="(option, key) in options"
v-for="(option, key) in optionsList"
:key="key"
:value="option.key"
:label="option.label"
@ -26,7 +26,8 @@
</template>
<script>
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import { convertBooleanToString } from '@/utils/ADempiere/valueUtils.js'
/**
* This component is a lookup type field, use as a replacement for fields:
@ -36,23 +37,24 @@ import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
*
* TODO: ALL: Although in the future these will have different components, and
* are currently not supported is also displayed as a substitute for fields:
* - Locator (WH)
* - Search Field
*/
export default {
name: 'FieldSelect',
mixins: [fieldMixin],
data() {
// label with '' value is assumed to be undefined non-existent
const label = ' '
return {
isLoading: false,
options: [{
label: ' ',
optionsList: [{
label,
key: undefined
}],
blankValues: [null, undefined, -1],
blankOption: {
// label with '' value is assumed to be undefined non-existent
label: ' ',
label,
key: undefined
}
}
@ -67,8 +69,8 @@ export default {
isSelectMultiple() {
return ['IN', 'NOT_IN'].includes(this.metadata.operator) && this.metadata.isAdvancedQuery
},
classStyle() {
let styleClass = 'custom-field-select'
cssClassStyle() {
let styleClass = this.metadata.cssClassName + ' custom-field-select'
if (this.isSelectMultiple) {
styleClass += ' custom-field-select-multiple'
}
@ -96,11 +98,60 @@ export default {
value: this.value
})
// sets the value to blank when the lookupList or lookupItem have no
// values, or if only lookupItem does have a value
if (this.isEmptyValue(allOptions) || (allOptions.length &&
(!this.blankValues.includes(allOptions[0].key)))) {
allOptions.unshift(this.blankOption)
}
return allOptions
},
value: {
get() {
const value = this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName
})
let label = this.findLabel(value)
if (!label) {
label = this.displayColumn
/* eslint-disable */
this.optionsList.push({
key: value,
label
})
/* eslint-disable */
}
return value
},
set(value) {
this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName,
value
})
}
},
displayColumn: {
get() {
return this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
// DisplayColumn_'ColumnName'
columnName: this.metadata.displayColumnName
})
},
set(value) {
this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
// DisplayColumn_'ColumnName'
columnName: this.metadata.displayColumnName,
value
})
}
}
},
watch: {
@ -114,27 +165,23 @@ export default {
} else {
if (Array.isArray(this.value)) {
if (this.value.length) {
// set first value
this.value = this.value[0]
} else {
this.value = undefined
this.value = this.blankOption.key
}
}
}
},
valueModel(value) {
if (this.metadata.inTable) {
this.value = value
}
},
/*
'metadata.value'(value) {
if (!this.metadata.inTable) {
if (typeof value === 'boolean') {
value = value ? 'Y' : 'N'
}
value = this.parseValue(value)
if (this.metadata.displayed) {
if (!this.options.some(option => option.key === value) &&
if (!this.optionsList.some(option => option.key === value) &&
!this.isEmptyValue(this.metadata.displayColumn)) {
this.options.push({
this.optionsList.push({
key: value,
label: this.metadata.displayColumn
})
@ -154,7 +201,7 @@ export default {
if (!this.isEmptyValue(value)) {
// verify if exists to add
if (!this.findLabel(this.value)) {
this.options.push({
this.optionsList.push({
key: this.value,
label: value
})
@ -162,24 +209,31 @@ export default {
}
}
}
},
}
*/
'metadata.displayed'(value) {
if (value) {
this.changeBlankOption()
this.options = this.getterLookupAll
// if is field showed, search into store all options to list
this.optionsList = this.getterLookupAll
}
}
},
created() {
this.changeBlankOption()
},
beforeMount() {
if (this.metadata.displayed) {
this.changeBlankOption()
this.options = this.getterLookupAll
if (!this.isEmptyValue(this.value) && !this.metadata.isAdvancedQuery) {
if (!this.findLabel(this.value)) {
this.optionsList = this.getterLookupAll
const value = this.value
if (!this.isEmptyValue(value) && !this.metadata.isAdvancedQuery) {
const label = this.findLabel(value)
if (label) {
this.displayColumn = label
} else {
if (!this.isEmptyValue(this.metadata.displayColumn)) {
// verify if exists to add
this.options.push({
key: this.value,
this.optionsList.push({
key: value,
label: this.metadata.displayColumn
})
} else {
@ -194,26 +248,28 @@ export default {
}
},
methods: {
parseValue(value) {
if (typeof value === 'boolean') {
// value ? 'Y' : 'N'
value = convertBooleanToString(value)
}
return value
},
changeBlankOption() {
if (Number(this.metadata.defaultValue) === -1) {
this.blankOption = {
label: ' ',
key: -1
}
}
if (this.value === undefined || this.value === null) {
this.blankOption = {
label: ' ',
key: undefined
}
this.blankOption.key = -1
}
},
preHandleChange(value) {
const label = this.findLabel(this.value)
this.handleChange(value, undefined, label)
this.displayColumn = label
this.handleFieldChange({
value,
label
})
},
findLabel(value) {
const selected = this.options.find(item => item.key === value)
const selected = this.optionsList.find(item => item.key === value)
if (selected) {
return selected.label
}
@ -230,20 +286,11 @@ export default {
containerUuid: this.metadata.containerUuid,
tableName: this.metadata.reference.tableName,
directQuery: this.metadata.reference.directQuery,
value: this.metadata.value
value: this.value
})
.then(responseLookupItem => {
if (this.isPanelWindow) {
this.$store.dispatch('changeFieldAttribure', {
containerUuid: this.metadata.containerUuid,
isAdvancedQuery: this.metadata.isAdvancedQuery,
columnName: this.metadata.columnName,
attributeName: 'displayColumn',
attributeValue: responseLookupItem.label
})
}
this.changeBlankOption()
this.options = this.getterLookupAll
this.displayColumn = responseLookupItem.label
this.optionsList = this.getterLookupAll
})
.finally(() => {
this.isLoading = false
@ -261,26 +308,33 @@ export default {
}
}
},
async remoteMethod() {
if (this.isEmptyValue(this.metadata.reference.query)) {
return
}
remoteMethod() {
this.isLoading = true
this.$store.dispatch('getLookupListFromServer', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
tableName: this.metadata.reference.tableName,
query: this.metadata.reference.query
query: this.metadata.reference.query,
isAddBlankValue: true,
blankValue: this.blankOption.key
})
.then(responseLookupList => {
this.changeBlankOption()
this.options = this.getterLookupAll
if (!this.isEmptyValue(responseLookupList)) {
this.optionsList = responseLookupList
} else {
this.optionsList = this.getterLookupAll
}
})
.finally(() => {
this.isLoading = false
})
},
clearLookup() {
// set empty list and empty option
this.optionsList = [
this.blankOption
]
this.$store.dispatch('deleteLookupList', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
@ -290,12 +344,6 @@ export default {
value: this.value
})
// set empty list and empty option
this.changeBlankOption()
const list = []
list.push(this.blankOption)
this.options = list
// set empty value
this.value = this.blankOption.key
}
@ -303,7 +351,7 @@ export default {
}
</script>
<style lang="scss">
<style lang="scss" scoped>
.custom-field-select {
width: 100%;
}

View File

@ -17,18 +17,13 @@
</template>
<script>
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
/**
* This component is a list type field, for IN and NOT IN search with advanced query
*/
export default {
name: 'FieldSelectMultiple',
mixins: [fieldMixin],
methods: {
preHandleChange(value) {
this.handleChange(value)
}
}
mixins: [fieldMixin]
}
</script>

View File

@ -4,7 +4,7 @@
v-model="value"
:pattern="pattern"
:rows="rows"
:class="metadata.cssClassName"
:class="cssClassStyle"
:type="typeTextBox"
:placeholder="metadata.help"
:readonly="Boolean(metadata.readonly)"
@ -22,12 +22,16 @@
</template>
<script>
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import fieldMixinText from '@/components/ADempiere/Field/mixin/mixinFieldText.js'
import { TEXT } from '@/utils/ADempiere/references'
export default {
name: 'FieldText',
mixins: [fieldMixin],
mixins: [
fieldMixin,
fieldMixinText
],
props: {
inTable: {
type: Boolean,
@ -70,40 +74,6 @@ export default {
}
return undefined
}
},
watch: {
valueModel(value) {
if (this.metadata.inTable) {
if (this.isEmptyValue(value)) {
value = ''
}
this.value = String(value)
}
},
'metadata.value'(value) {
if (!this.metadata.inTable) {
if (this.isEmptyValue(value)) {
value = ''
}
this.value = String(value)
}
}
},
methods: {
validateUrl(e) {
// Entry pattern, in this case only accepts numbers and letters
const _Pattern = /^(http[s]?:\/\/(www\.)?|ftp:\/\/(www\.)?|www\.){1}([0-9A-Za-z-\.@:%_\+~#=]+)+((\.[a-zA-Z]{1,5})+)(\/(.)*)?(\?(.)*)?/g
var rex = RegExp(_Pattern)
var value = e.target.value
if (rex.test(value) && value.trim() !== '') {
console.log('url good format')
} else if (value.trim() === '') {
console.log('url empty')
} else {
// e.target.focus()
console.log('url wrong')
}
}
}
}
</script>

View File

@ -1,5 +1,8 @@
<template>
<div :id="id" :class="classDisable + ' ' + metadata.cssClassName" />
<div
:id="id"
:class="cssClassStyle"
/>
</template>
<script>
@ -10,11 +13,15 @@ import 'codemirror/lib/codemirror.css' // codemirror
import Editor from 'tui-editor'
import { getLanguage } from '@/lang'
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import fieldMixinText from '@/components/ADempiere/Field/mixin/mixinFieldText.js'
export default {
name: 'FieldTextLong',
mixins: [fieldMixin],
mixins: [
fieldMixin,
fieldMixinText
],
props: {
id: {
type: String,
@ -32,11 +39,12 @@ export default {
}
},
computed: {
classDisable() {
cssClassStyle() {
let styleClass = this.metadata.cssClassName
if (this.isDisabled) {
return 'isdisable'
styleClass += ' custom-field-text-long-disable'
}
return ''
return styleClass
},
language() {
// https://github.com/nhnent/tui.editor/tree/master/src/js/langs
@ -59,22 +67,6 @@ export default {
}
},
watch: {
valueModel(value, oldValue) {
if (this.metadata.inTable) {
if (this.isEmptyValue(value)) {
value = ''
}
this.value = String(value)
}
},
'metadata.value'(value, oldValue) {
if (!this.metadata.inTable) {
if (this.isEmptyValue(value)) {
value = ''
}
this.value = String(value)
}
},
value(newValue, oldValue) {
if (this.isDisabled) {
// not changed value
@ -159,8 +151,9 @@ export default {
}
}
</script>
<style>
.isdisable {
<style scoped>
.custom-field-text-long-disable {
background: #F5F7FA;
}
</style>

View File

@ -9,7 +9,7 @@
:is-range="isPickerRange"
range-separator="-"
:placeholder="$t('components.timePlaceholder')"
:class="'time-base ' + metadata.cssClassName"
:class="cssClassStyle"
:readonly="Boolean(metadata.readonly)"
:disabled="isDisabled"
@change="preHandleChange"
@ -21,7 +21,7 @@
</template>
<script>
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
export default {
name: 'FieldTime',
@ -44,22 +44,13 @@ export default {
return Number(this.metadata.valueMin)
}
return -Infinity
}
},
watch: {
valueModel(value) {
if (this.metadata.inTable) {
this.value = this.parsedDateValue(value)
}
},
'metadata.value'(value) {
if (!this.metadata.inTable) {
this.value = this.parsedDateValue(value)
}
cssClassStyle() {
return this.metadata.cssClassName + ' custom-field-time'
}
},
methods: {
parsedDateValue(value) {
parseValue(value) {
if (typeof value === 'number') {
value = new Date(value).toUTCString()
}
@ -73,7 +64,7 @@ export default {
</script>
<style scoped>
.time-base {
.custom-field-time {
width: 100% !important;
}
</style>

View File

@ -4,7 +4,7 @@
v-model="value"
:inactive-text="$t('components.switchInactiveText')"
:active-text="$t('components.switchActiveText')"
:class="'custom-field-yes-no ' + metadata.cssClassName"
:class="cssClassStyle"
:true-value="true"
:false-value="false"
:disabled="isDisabled"
@ -17,7 +17,8 @@
<script>
import { fieldIsDisplayed } from '@/utils/ADempiere'
import { FIELDS_READ_ONLY_FORM } from '@/utils/ADempiere/references'
import { fieldMixin } from '@/components/ADempiere/Field/FieldMixin'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import { convertStringToBoolean } from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'FieldYesNo',
@ -32,33 +33,17 @@ export default {
]
}
},
watch: {
valueModel(value) {
if (this.metadata.inTable) {
this.value = Boolean(value)
}
},
'metadata.value'(value) {
if (!this.metadata.inTable) {
this.value = Boolean(value)
}
},
value(value, oldValue) {
if (typeof value !== 'boolean') {
if (value === 'N' || value === 'n') {
value = false
}
this.value = Boolean(value)
}
this.preHandleChange('NotSend')
computed: {
cssClassStyle() {
return this.metadata.cssClassName + ' custom-field-yes-no'
}
},
mounted() {
this.preHandleChange('NotSend') // activate logics
},
methods: {
parseValue(value) {
return convertStringToBoolean(value)
},
preHandleChange(value) {
this.handleChange(value)
this.handleFieldChange({ value })
if (!this.metadata.inTable && !this.metadata.isAdvancedQuery) {
this.isReadOnlyForm(this.value)
}
@ -87,7 +72,7 @@ export default {
}
</script>
<style>
<style scoped>
.custom-field-yes-no {
max-height: 34px;
}

View File

@ -59,27 +59,11 @@ export default {
}
},
watch: {
valueModel(value, oldValue) {
if (this.metadata.inTable) {
if (this.isEmptyValue(value)) {
value = ''
}
this.value = String(value)
}
},
clean(value) {
if (value) {
this.editor.setValue('')
}
},
'metadata.value'(value, oldValue) {
if (!this.metadata.inTable) {
if (this.isEmptyValue(value)) {
value = ''
}
this.value = String(value)
}
},
value(newValue, oldValue) {
if (this.isDisabled) {
// not changed value

View File

@ -213,10 +213,7 @@ export default {
if (this.field.isAlwaysUpdateable) {
return false
}
if (this.field.isProcessingContext) {
return true
}
if (this.field.isProcessedContext) {
if (this.field.isProcessingContext || this.field.isProcessedContext) {
return true
}
@ -227,7 +224,8 @@ export default {
isWithRecord = !this.isEmptyValue(this.field.recordUuid)
}
return (!this.field.isUpdateable && isWithRecord) || (isUpdateableAllFields || this.field.isReadOnlyFromForm)
return (!this.field.isUpdateable && isWithRecord) ||
(isUpdateableAllFields || this.field.isReadOnlyFromForm)
} else if (this.field.panelType === 'browser') {
if (this.inTable) {
// browser result
@ -247,8 +245,8 @@ export default {
},
isSelectCreated() {
return this.isAdvancedQuery &&
!['FieldBinary', 'FieldDate', 'FieldSelect', 'FieldYesNo'].includes(this.field.componentPath) &&
['IN', 'NOT_IN'].includes(this.field.operator)
['IN', 'NOT_IN'].includes(this.field.operator) &&
!['FieldBinary', 'FieldDate', 'FieldSelect', 'FieldYesNo'].includes(this.field.componentPath)
},
getWidth() {
return this.$store.getters.getWidthLayout
@ -343,7 +341,8 @@ export default {
if (!this.isAdvancedQuery) {
return false
}
return (this.field.contextInfo && this.field.contextInfo.isActive) || (this.field.reference && this.field.reference.windowsList.length)
return (this.field.contextInfo && this.field.contextInfo.isActive) ||
(this.field.reference && this.field.reference.windowsList.length)
}
},
watch: {
@ -388,6 +387,7 @@ export default {
font-weight: bold;
float: left;
}
/**
* Separation between elements (item) of the form
*/
@ -396,6 +396,7 @@ export default {
margin-left: 10px;
margin-right: 10px;
}
/**
* Reduce the spacing between the form element and its label
*/

View File

@ -1,5 +1,5 @@
export const fieldMixin = {
export default {
props: {
metadata: {
type: Object,
@ -13,26 +13,48 @@ export const fieldMixin = {
},
data() {
// value render
let value = this.metadata.value
let value1 = this.metadata.value
if (this.metadata.inTable) {
value = this.valueModel
value1 = this.valueModel
}
value1 = this.parseValue(value1)
return {
value
value1
}
},
computed: {
isDisabled() {
return Boolean(this.metadata.readonly || this.metadata.disabled)
},
cssClassStyle() {
return this.metadata.cssClassName
},
value: {
get() {
return this.$store.getters.getValueOfField({
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName
})
},
set(value) {
this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName,
value
})
}
}
},
async created() {
if (this.metadata.isSQLValue && (this.isEmptyValue(this.metadata.value) || this.metadata.value.isSQL || isNaN(this.metadata.value))) {
if (this.metadata.isSQLValue && (this.isEmptyValue(this.metadata.value) || this.metadata.value.isSQL)) {
const value = await this.$store.dispatch('getValueBySQL', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
query: this.metadata.defaultValue
})
// set value and change into store
this.preHandleChange(value)
}
},
@ -41,7 +63,27 @@ export const fieldMixin = {
this.requestFocus()
}
},
watch: {
// valueModel(value) {
// if (this.metadata.inTable) {
// this.value = this.parseValue(value)
// }
// },
// 'metadata.value'(value) {
// if (!this.metadata.inTable) {
// this.value = this.parseValue(value)
// }
// }
},
methods: {
/**
* Parse the value to a new value if required for element-ui component
* compatibility where this method is overwritten
* @param {mixed} value
*/
parseValue(value) {
return value
},
/**
* Set focus if handle focus attribute is true
*/
@ -56,7 +98,7 @@ export const fieldMixin = {
* @param {mixed} value
*/
preHandleChange(value) {
this.handleChange(value)
this.handleFieldChange({ value })
},
focusGained(value) {
if (this.metadata.handleContentSelection) {
@ -119,43 +161,17 @@ export const fieldMixin = {
* @param {mixed} valueTo, used in end value in range
* @param {string} label, or displayColumn to show in select
*/
handleChange(value, valueTo = undefined, label = undefined) {
let newValue = value
let isSendCallout = true
let isSendToServer = true
let isChangedOldValue = false
if (value === 'NotSend') {
newValue = this.value
if (this.componentPath === 'FieldYesNo') {
isChangedOldValue = true
newValue = Boolean(newValue)
}
isSendToServer = false
isSendCallout = false
}
if (this.metadata.isAdvancedQuery) {
isSendCallout = false
}
const sendParameters = {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
field: this.metadata,
panelType: this.metadata.panelType,
columnName: this.metadata.columnName,
newValue,
valueTo,
isAdvancedQuery: this.metadata.isAdvancedQuery,
isSendToServer,
isSendCallout,
isChangedOldValue
}
handleFieldChange({
value,
valueTo,
label
}) {
// Global Action performed
if (this.metadata.handleActionPerformed) {
this.$store.dispatch('notifyActionPerformed', {
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName,
value: newValue
value
})
}
@ -163,20 +179,10 @@ export const fieldMixin = {
if (this.metadata.isCustomField) {
return
}
if (this.metadata.inTable) {
this.$store.dispatch('notifyCellTableChange', {
...sendParameters,
keyColumn: this.metadata.keyColumn,
tableIndex: this.metadata.tableIndex,
rowKey: this.metadata.rowKey
})
} else {
this.$store.dispatch('notifyFieldChange', {
...sendParameters,
displayColumn: label
})
}
this.$store.dispatch('notifyFieldChange', {
containerUuid: this.metadata.containerUuid,
field: this.metadata
})
}
}
}

View File

@ -0,0 +1,29 @@
export default {
computed: {
value: {
get() {
const value = this.$store.getters.getValueOfField({
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName
})
const valueTo = this.$store.getters.getValueOfField({
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName
})
return [
value,
valueTo
]
},
set(value) {
this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName,
value
})
}
}
}
}

View File

@ -0,0 +1,10 @@
export default {
methods: {
parseValue(value) {
if (this.isEmptyValue(value)) {
value = ''
}
return String(value)
}
}
}

View File

@ -235,33 +235,33 @@ export default {
}
},
changeValue() {
const newValue = Number(this.valueToDisplay)
let isSendCallout = true
const isSendToServer = true
const isChangedOldValue = false
if (this.fieldAttributes.isAdvancedQuery) {
isSendCallout = false
}
const sendParameters = {
parentUuid: this.fieldAttributes.parentUuid,
containerUuid: this.fieldAttributes.containerUuid,
field: this.fieldAttributes,
panelType: this.fieldAttributes.panelType,
columnName: this.fieldAttributes.columnName,
newValue,
isAdvancedQuery: this.fieldAttributes.isAdvancedQuery,
isSendToServer,
isSendCallout,
isChangedOldValue
}
this.$store.dispatch('notifyFieldChange', {
...sendParameters
})
.finally(() => {
this.clearVariables()
this.$children[0].visible = false
})
// const newValue = Number(this.valueToDisplay)
// let isSendCallout = true
// const isSendToServer = true
// const isChangedOldValue = false
// if (this.fieldAttributes.isAdvancedQuery) {
// isSendCallout = false
// }
//
// const sendParameters = {
// parentUuid: this.fieldAttributes.parentUuid,
// containerUuid: this.fieldAttributes.containerUuid,
// field: this.fieldAttributes,
// panelType: this.fieldAttributes.panelType,
// columnName: this.fieldAttributes.columnName,
// newValue,
// isAdvancedQuery: this.fieldAttributes.isAdvancedQuery,
// isSendToServer,
// isSendCallout,
// isChangedOldValue
// }
// this.$store.dispatch('notifyFieldChange', {
// ...sendParameters
// })
// .finally(() => {
// this.clearVariables()
// this.$children[0].visible = false
// })
},
spanMethod({ row, column, rowIndex, columnIndex }) {
if (rowIndex === 1) {

View File

@ -108,13 +108,13 @@ export default {
}
},
documentActionChange(value) {
this.$store.dispatch('notifyFieldChange', {
parentUuid: this.field.parentUuid,
containerUuid: this.field.containerUuid,
columnName: 'DocAction',
isSendToServer: true,
newValue: value
})
// this.$store.dispatch('notifyFieldChange', {
// parentUuid: this.field.parentUuid,
// containerUuid: this.field.containerUuid,
// columnName: 'DocAction',
// isSendToServer: true,
// newValue: value
// })
const actionProcess = this.$store.getters.getOrders
this.$store.dispatch('startProcess', {

View File

@ -66,22 +66,21 @@ export default {
* @param {string} label, or displayColumn to show in select
*/
handleChange(value) {
const sendParameters = {
parentUuid: this.fieldAttributes.parentUuid,
containerUuid: this.fieldAttributes.containerUuid,
field: this.fieldAttributes,
panelType: this.fieldAttributes.panelType,
columnName: this.fieldAttributes.columnName,
newValue: value === 'NotSend' ? this.value : value,
isAdvancedQuery: true,
isSendToServer: !(value === 'NotSend'),
isSendCallout: false
}
this.$store.dispatch('notifyFieldChange', {
...sendParameters,
isChangedOldValue: this.fieldAttributes.componentPath === 'FieldYesNo' && Boolean(value === 'NotSend')
})
// const sendParameters = {
// parentUuid: this.fieldAttributes.parentUuid,
// containerUuid: this.fieldAttributes.containerUuid,
// field: this.fieldAttributes,
// panelType: this.fieldAttributes.panelType,
// columnName: this.fieldAttributes.columnName,
// newValue: value === 'NotSend' ? this.value : value,
// isAdvancedQuery: true,
// isSendToServer: !(value === 'NotSend'),
// isSendCallout: false
// }
// this.$store.dispatch('notifyFieldChange', {
// ...sendParameters,
// isChangedOldValue: this.fieldAttributes.componentPath === 'FieldYesNo' && Boolean(value === 'NotSend')
// })
}
}
}

View File

@ -139,12 +139,12 @@ export default {
// Set value for one field from panel
// use example: setValue('ProductName', 'Patio Fun')
setValue(columnName, value) {
this.$store.dispatch('notifyFieldChange', {
containerUuid: this.metadata.containerUuid,
panelType: this.metadata.panelType,
columnName,
newValue: value
})
// this.$store.dispatch('notifyFieldChange', {
// containerUuid: this.metadata.containerUuid,
// panelType: this.metadata.panelType,
// columnName,
// newValue: value
// })
},
// Set values for all list of columns
// Use example: setValues(values)

View File

@ -1,199 +1,19 @@
<template>
<div class="wrapper">
<el-form
v-if="isLoadPanel"
key="panel-loaded"
v-model="dataRecords"
label-position="top"
label-width="200px"
>
<template
v-if="firstGroup && firstGroup.groupFinal === ''"
>
<div v-show="firstGroup.activeFields" class="cards-not-group">
<div
v-if="(groupTab.groupType == 'T' && groupTab.groupName == firstGroup.groupFinal)
|| (groupTab.groupType !== 'T' && firstGroup.typeGroup !== 'T')"
class="card"
>
<div class="select-filter">
<span>
{{ firstGroup.groupFinal }}
</span>
<filter-fields
:container-uuid="containerUuid"
:panel-type="panelType"
:group-field="firstGroup.groupFinal"
:is-advanced-query="isAdvancedQuery"
/>
</div>
<el-card
:shadow="shadowGroup"
:body-style="{ padding: '10px' }"
>
<el-row>
<template v-for="(fieldAttributes, subKey) in firstGroup.metadataFields">
<field-definition
:ref="fieldAttributes.columnName"
:key="subKey"
:metadata-field="{
...fieldAttributes,
isShowedRecordNavigation,
isProcessingContext: getterContextProcessing,
isProcessedContext: getterContextProcessed,
optionCRUD,
recordUuid: uuidRecord
}"
:record-data-fields="isAdvancedQuery ? undefined : dataRecords[fieldAttributes.columnName]"
:in-group="!isShowedRecordNavigation"
:is-advanced-query="isAdvancedQuery"
/>
</template>
</el-row>
</el-card>
</div>
</div>
</template>
<div :class="classCards">
<draggable
v-if="!isMobile"
key="draggable-loaded"
:list="fieldGroups"
v-bind="$attrs"
:set-data="setData"
>
<template v-for="(item, key) in fieldGroups">
<el-row :key="key">
<el-col :key="key" :span="24">
<div
v-if="item.groupFinal !== ''
&& (groupTab.groupType == 'T' && groupTab.groupName == item.groupFinal)
|| (groupTab.groupType !== 'T' && item.typeGroup !== 'T')"
:key="key"
class="card"
>
<el-card
:shadow="shadowGroup"
:body-style="{ padding: '10px' }"
>
<div slot="header" class="clearfix">
<span>
{{ item.groupFinal }}
</span>
<div class="select-filter-header">
<filter-fields
:container-uuid="containerUuid"
:panel-type="panelType"
:group-field="item.groupFinal"
:is-first-group="false"
:is-advanced-query="isAdvancedQuery"
/>
</div>
</div>
<el-row>
<template v-for="(fieldAttributes, subKey) in item.metadataFields">
<field-definition
:ref="fieldAttributes.columnName"
:key="subKey"
:metadata-field="{
...fieldAttributes,
isShowedRecordNavigation,
isProcessingContext: getterContextProcessing,
isProcessedContext: getterContextProcessed,
optionCRUD,
recordUuid: uuidRecord
}"
:record-data-fields="isAdvancedQuery ? undefined : dataRecords[fieldAttributes.columnName]"
:in-group="isPanelWindow && fieldGroups.length > 1"
:is-advanced-query="isAdvancedQuery"
/>
</template>
</el-row>
</el-card>
</div>
</el-col>
</el-row>
</template>
</draggable>
<template v-else>
<template v-for="(item, key) in fieldGroups">
<el-row :key="key">
<el-col :key="key" :span="24">
<div
v-if="item.groupFinal !== ''
&& (groupTab.groupType == 'T' && groupTab.groupName == item.groupFinal)
|| (groupTab.groupType !== 'T' && item.typeGroup !== 'T')"
:key="key"
class="card"
>
<el-card
:shadow="shadowGroup"
:body-style="{ padding: '10px' }"
>
<div slot="header" class="clearfix">
<span>
{{ item.groupFinal }}
</span>
<div v-if="!isAdvancedQuery" class="select-filter-header">
<filter-fields
:container-uuid="containerUuid"
:panel-type="panelType"
:group-field="item.groupFinal"
:is-first-group="false"
/>
</div>
</div>
<el-row>
<template v-for="(fieldAttributes, subKey) in item.metadataFields">
<field-definition
:ref="fieldAttributes.columnName"
:key="subKey"
:metadata-field="{
...fieldAttributes,
isShowedRecordNavigation,
isProcessingContext: getterContextProcessing,
isProcessedContext: getterContextProcessed,
optionCRUD,
recordUuid: uuidRecord
}"
:record-data-fields="isAdvancedQuery ? undefined : dataRecords[fieldAttributes.columnName]"
:in-group="isPanelWindow && fieldGroups.length > 1"
/>
</template>
</el-row>
</el-card>
</div>
</el-col>
</el-row>
</template>
</template>
</div>
</el-form>
<div
v-else
key="panel-loading"
v-loading="!isLoadPanel"
:element-loading-text="$t('notifications.loading')"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.8)"
class="loading-panel"
/>
</div>
<component
:is="templateDevice"
:parent-uuid="parentUuid"
:container-uuid="containerUuid"
:metadata="metadata"
:group-tab="groupTab"
:panel-type="panelType"
:is-advanced-query="isAdvancedQuery"
:is-showed-record-navigation="isShowedRecordNavigation"
/>
</template>
<script>
import FieldDefinition from '@/components/ADempiere/Field'
import FilterFields from '@/components/ADempiere/Panel/filterFields'
import draggable from 'vuedraggable'
import { fieldIsDisplayed, parsedValueComponent } from '@/utils/ADempiere'
export default {
name: 'MainPanel',
components: {
FieldDefinition,
FilterFields,
draggable
},
props: {
parentUuid: {
type: String,
@ -228,563 +48,20 @@ export default {
default: false
}
},
data() {
return {
fieldList: [],
dataRecords: {},
isLoadPanel: false,
isLoadRecord: false,
uuidRecord: this.$route.query.action,
fieldGroups: [],
firstGroup: {},
groupsView: 0,
tagTitle: {
base: this.$route.meta.title,
action: ''
}
}
},
computed: {
shadowGroup() {
if (this.isMobile) {
return 'never'
}
return 'hover'
},
optionCRUD() {
return this.isEmptyValue(this.uuidRecord) ? 'create-new' : this.uuidRecord
},
isPanelWindow() {
return this.panelType === 'window'
},
getterContextProcessing() {
if (this.panelType === 'window' && !this.isAdvancedQuery) {
const processing = this.$store.getters.getContextProcessing(this.parentUuid)
if (processing === true || processing === 'Y') {
return true
}
}
return false
},
getterContextProcessed() {
if (this.panelType === 'window' && !this.isAdvancedQuery) {
const processed = this.$store.getters.getContextProcessed(this.parentUuid)
if (processed === true || processed === 'Y') {
return true
}
}
return false
},
getterPanel() {
return this.$store.getters.getPanel(this.containerUuid, this.isAdvancedQuery)
},
getterFieldList() {
if (this.getterPanel) {
return this.getterPanel.fieldList
}
return undefined
},
isMobile() {
return this.$store.state.app.device === 'mobile'
},
getterDataStore() {
if (this.isPanelWindow) {
return this.$store.getters.getDataRecordAndSelection(this.containerUuid)
templateDevice() {
if (this.isMobile) {
return () => import('@/components/ADempiere/Panel/mainPanelMobile')
}
return {
recordCount: 0,
isLoaded: false,
record: []
}
},
getterIsLoadedRecord() {
return this.getterDataStore.isLoaded
},
classCards() {
if (this.isMobile || this.fieldGroups.length < 2 || this.isShowedRecordNavigation) {
return 'cards-not-group'
}
return 'cards-in-group'
}
},
watch: {
// used only panel modal (process associated in browser or window)
containerUuid() {
if (['report', 'process'].includes(this.panelType)) {
this.generatePanel(this.metadata.fieldList)
}
},
'$route.query.action'(newValue, oldValue) {
// used in field, if uuid record or different create-new, field is read only
this.uuidRecord = newValue
if (newValue !== oldValue && this.isPanelWindow) {
this.changePanelRecord(newValue)
}
},
isLoadPanel(value) {
if (value) {
this.readParameters()
}
}
},
created() {
// get fields with uuid
this.getPanel()
},
methods: {
/**
* Get the tab object with all its attributes as well as the fields it contains
*/
getPanel() {
const fieldsList = this.getterFieldList
if (fieldsList && Array.isArray(fieldsList)) {
this.generatePanel(fieldsList)
} else {
this.$store.dispatch('getPanelAndFields', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
panelType: this.panelType,
panelMetadata: this.metadata,
isAdvancedQuery: this.isAdvancedQuery
}).then(() => {
this.generatePanel(this.getterFieldList)
}).catch(error => {
console.warn(`Field Load Error: ${error.message}. Code: ${error.code}.`)
})
}
},
generatePanel(fieldsList) {
// order and assign groups
this.fieldList = fieldsList
if (fieldsList.length) {
this.fieldGroups = this.sortAndGroup(fieldsList)
}
let firstGroup
if (this.fieldGroups[0] && this.fieldGroups[0].groupFinal === '') {
firstGroup = this.fieldGroups[0]
this.fieldGroups.shift()
}
this.firstGroup = firstGroup
this.isLoadPanel = true
},
/**
* TODO: Delete route parameters after reading them
*/
readParameters() {
const parameters = {
isLoadAllRecords: true,
isReference: false,
isNewRecord: false,
isWindow: true,
criteria: {}
}
const route = this.$route
if (this.isPanelWindow) {
// TODO: use action notifyPanelChange with isShowedField in true
this.getterFieldList.forEach(fieldItem => {
if (Object.prototype.hasOwnProperty.call(route.query, fieldItem.columnName) && !fieldItem.isAdvancedQuery) {
fieldItem.isShowedFromUser = true
fieldItem.value = parsedValueComponent({
fieldType: fieldItem.componentPath,
value: route.query[fieldItem.columnName],
displayType: fieldItem.displayType,
isIdentifier: fieldItem.columnName.includes('_ID')
})
if (String(route.query.isAdvancedQuery) === String(fieldItem.isAdvancedQuery)) {
fieldItem.value = parsedValueComponent({
fieldType: fieldItem.componentPath,
value: route.query[fieldItem.columnName],
displayType: fieldItem.displayType,
isIdentifier: fieldItem.columnName.includes('_ID')
})
if (fieldItem.isRange && this.$route.query[`${fieldItem.columnName}_To`]) {
fieldItem.valueTo = parsedValueComponent({
fieldType: fieldItem.componentPath,
value: route.query[`${fieldItem.columnName}_To`],
displayType: fieldItem.displayType,
isIdentifier: fieldItem.columnName.includes('_ID')
})
}
}
}
})
if (route.query.action && route.query.action === 'reference') {
const referenceInfo = this.$store.getters.getReferencesInfo({
windowUuid: this.parentUuid,
recordUuid: route.query.recordUuid,
referenceUuid: route.query.referenceUuid
})
route.params.isReadParameters = true
parameters.isLoadAllRecords = false
parameters.isReference = true
parameters.referenceUuid = referenceInfo.uuid
parameters.referenceWhereClause = referenceInfo.whereClause
} else if (route.query.action && route.query.action === 'create-new') {
parameters.isNewRecord = true
} else if (route.query.action && route.query.action === 'criteria') {
route.params.isReadParameters = true
Object.keys(route.params).forEach(param => {
if (!this.isEmptyValue(route.params[param])) {
parameters.criteria[param] = route.params[param]
}
})
} else if (route.query.action && route.query.action === 'listRecords') {
parameters.isLoadAllRecords = true
route.params.isReadParameters = true
} else if (!this.isEmptyValue(route.query.action) &&
!['create-new', 'reference', 'advancedQuery', 'criteria', 'listRecords'].includes(route.query.action)) {
parameters.isLoadAllRecords = false
parameters.value = route.query.action
parameters.tableName = this.metadata.tableName
parameters.columnName = 'UUID'
route.params.isReadParameters = true
}
// Only call get data if panel type is window
if (!Object.prototype.hasOwnProperty.call(route.params, 'isReadParameters') || route.params.isReadParameters) {
this.getData(parameters)
}
let viewTitle = ''
if (route.query && !this.isEmptyValue(route.query.action)) {
viewTitle = route.query.action
}
this.setTagsViewTitle(viewTitle)
} else {
if (this.panelType === 'table' && route.query.action === 'advancedQuery') {
// TODO: use action notifyPanelChange with isShowedField in true
this.fieldList.forEach(fieldItem => {
if (Object.prototype.hasOwnProperty.call(route.query, fieldItem.columnName) && fieldItem.isAdvancedQuery) {
fieldItem.isShowedFromUser = true
if (route.query.action === 'advancedQuery' && fieldItem.isAdvancedQuery) {
this.dataRecords[fieldItem.columnName] = parsedValueComponent({
fieldType: fieldItem.componentPath,
value: route.query[fieldItem.columnName],
isIdentifier: fieldItem.columnName.includes('_ID')
})
if (fieldItem.isRange && route.query[`${fieldItem.columnName}_To`]) {
this.dataRecords[fieldItem.columnName] = parsedValueComponent({
fieldType: fieldItem.componentPath,
value: route.query[`${fieldItem.columnName}_To`],
isIdentifier: fieldItem.columnName.includes('_ID')
})
}
}
}
})
parameters.isWindow = false
this.$store.dispatch('notifyPanelChange', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
isAdvancedQuery: route.query.action === 'advancedQuery',
newValues: this.dataRecords,
isSendToServer: true,
isSendCallout: false,
fieldList: this.fieldList,
panelType: this.panelType
})
} else if (['process', 'browser'].includes(this.panelType)) {
if (!this.isEmptyValue(route.query)) {
this.$store.dispatch('notifyPanelChange', {
containerUuid: this.containerUuid,
newValues: route.query,
isShowedField: true,
isSendCallout: false,
panelType: this.panelType
})
parameters.isWindow = false
}
}
}
},
/**
* @param {object} parameters parameters to condition the data query
*/
getData(parameters) {
if (parameters.isWindow && this.isPanelWindow && !this.getterIsLoadedRecord) {
this.$store.dispatch('getDataListTab', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
isLoadAllRecords: parameters.isLoadAllRecords,
isReference: parameters.isReference,
referenceWhereClause: parameters.referenceWhereClause,
columnName: parameters.columnName,
value: parameters.value,
criteria: parameters.criteria
})
.then(response => {
if (response.length && !parameters.isNewRecord) {
this.dataRecords = response[0]
const recordId = this.dataRecords[`${this.metadata.tableName}_ID`]
if (this.$route.query.action === 'criteria') {
this.$router.push({
name: this.$route.name,
query: {
...this.$route.query,
action: this.dataRecords.UUID
},
params: {
...this.$route.params,
tableName: this.metadata.tableName,
recordId
}
}).catch(error => {
console.info(`Panel Component: ${error.name}, ${error.message}`)
})
this.$store.dispatch('notifyPanelChange', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
newValues: this.dataRecords,
isSendToServer: false,
isSendCallout: false,
fieldList: this.fieldList,
panelType: this.panelType
})
} else if (this.$route.query.action === 'reference') {
this.$router.push({
name: this.$route.name,
query: {
...this.$route.query
},
params: {
...this.$route.params,
tableName: this.metadata.tableName,
recordId
}
}).catch(error => {
console.info(`Panel Component: ${error.name}, ${error.message}`)
})
this.$store.dispatch('notifyPanelChange', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
newValues: this.dataRecords,
isSendToServer: false,
isSendCallout: false,
fieldList: this.fieldList,
panelType: this.panelType
})
} else {
this.$router.push({
query: {
...this.$route.query,
action: this.dataRecords.UUID
},
params: {
...this.$route.params,
tableName: this.metadata.tableName,
recordId
}
}).catch(error => {
console.info(`Panel Component: ${error.name}, ${error.message}`)
})
this.$store.dispatch('notifyPanelChange', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
newValues: this.dataRecords,
isSendToServer: false,
isSendCallout: false,
fieldList: this.fieldList,
panelType: this.panelType
})
}
let viewTitle = ''
if (this.$route.query && !this.isEmptyValue(this.$route.query.action)) {
viewTitle = this.$route.query.action
}
this.setTagsViewTitle(viewTitle)
this.isLoadRecord = true
} else {
this.$router.push({
query: {
...this.$route.query,
action: 'create-new'
}
}).catch(error => {
console.info(`Panel Component: ${error.name}, ${error.message}`)
})
}
})
.catch(error => {
console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`)
})
}
},
/**
* Group the arrangement into groups of columns that they contain, it must
* be grouped after having the order
* @param {array} fieldsList
* @return {array} groupsList
*/
sortAndGroup(fieldsList) {
if (this.isEmptyValue(fieldsList)) {
return
}
let groupsList = [{
groupFinal: '',
metadataFields: fieldsList
}]
// reduce, create array with number groupAssigned element comun
if (this.isPanelWindow) {
groupsList = fieldsList
.reduce((groupsList, currentValue) => {
if (!groupsList.includes(currentValue.groupAssigned)) {
groupsList.push(currentValue.groupAssigned)
}
return groupsList
}, [])
.map(itemGroup => {
return {
groupFinal: itemGroup,
metadataFields: fieldsList.filter(itemField => {
return itemField.groupAssigned === itemGroup
})
}
})
}
// count and add the field numbers according to your group
groupsList.forEach(groupFields => {
const typeG = groupFields.metadataFields[0].typeGroupAssigned
groupFields.typeGroup = typeG
const fieldsDisplayed = groupFields.metadataFields.filter(field => {
return fieldIsDisplayed(field)
})
if ((this.groupTab.groupType === 'T' && this.groupTab.groupName === groupFields.groupFinal) ||
(this.groupTab.groupType !== 'T' && groupFields.typeGroup !== 'T')) {
this.groupsView = this.groupsView + 1
}
groupFields.activeFields = fieldsDisplayed.length
})
return groupsList
},
setTagsViewTitle(actionValue) {
if (actionValue !== 'create-new' && !this.isEmptyValue(actionValue) && this.getterPanel.isDocument && this.getterDataStore.isLoaded) {
this.$store.dispatch('listWorkflows', this.metadata.tableName)
this.$store.dispatch('listDocumentStatus', {
recordUuid: this.$route.query.action,
tableName: this.metadata.tableName
})
}
if (actionValue === 'create-new' || this.isEmptyValue(actionValue)) {
this.tagTitle.action = this.$t('tagsView.newRecord')
} else if (actionValue === 'advancedQuery') {
this.tagTitle.action = this.$t('tagsView.advancedQuery')
} else {
const { identifierColumns } = this.getterPanel
if (!this.isEmptyValue(identifierColumns)) {
if (this.dataRecords[identifierColumns[0]]) {
this.tagTitle.action = this.dataRecords[identifierColumns[0]]
} else {
const field = this.fieldList.find(fieldItem => fieldItem.isIdentifier)
this.tagTitle.action = field.value
}
} else {
this.tagTitle.action = this.$t('tagsView.seeRecord')
}
}
if (this.isPanelWindow) {
this.$store.dispatch('tagsView/updateVisitedView', {
...this.$route,
title: `${this.tagTitle.base} - ${this.tagTitle.action}`
})
}
},
setData(dataTransfer) {
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
},
changePanelRecord(uuidRecord) {
if (!['create-new', 'reference', 'advancedQuery', 'criteria', 'listRecords'].includes(uuidRecord)) {
const recordSelected = this.getterDataStore.record.find(record => record.UUID === uuidRecord)
if (recordSelected) {
this.dataRecords = recordSelected
this.$store.dispatch('notifyPanelChange', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
newValues: this.dataRecords,
isSendToServer: false,
isSendCallout: false,
fieldList: this.fieldList,
panelType: this.panelType
}).then(() => {
if (this.getterPanel.isTabsChildren) {
// delete records tabs children when change record uuid
this.$store.dispatch('deleteRecordContainer', {
viewUuid: this.parentUuid,
withOut: [this.containerUuid]
})
}
})
}
}
this.setTagsViewTitle(uuidRecord)
if (this.$route.query && this.$route.query.action === 'create-new') {
this.setFocus()
}
const currentRecord = this.getterDataStore.record.find(record => record.UUID === uuidRecord)
this.$store.dispatch('currentRecord', currentRecord)
},
async setFocus() {
return new Promise(resolve => {
const fieldFocus = this.getterFieldList.find(itemField => {
if (itemField.handleRequestFocus) {
return true
}
if (Object.prototype.hasOwnProperty.call(this.$refs, itemField.columnName)) {
if (fieldIsDisplayed(itemField) && !itemField.isReadOnly && itemField.isUpdateable && itemField.componentPath !== 'FieldSelect') {
return true
}
}
})
if (fieldFocus) {
this.$refs[fieldFocus.columnName][0].focusField()
}
resolve()
return
})
return () => import('@/components/ADempiere/Panel/mainPanelDesktop')
}
}
}
</script>
<style scoped>
.loading-panel {
padding: 100px;
height: 100%;
}
.cards-in-group {
column-count: 2; /*numbers of columns */
column-gap: 1em;
}
.cards-not-group {
column-count: 1; /* numbers of columns */
column-gap: 1em;
margin-bottom: 5px;
}
.card {
/* padding: 10px; */
width: 100% !important;
transition: all 100ms ease-in-out;
display: inline-block;
perspective: 1000;
backface-visibility: hidden;
}
.el-card {
width: 100% !important;
}
</style>
<style>
.select-filter {
width: 280px !important;

View File

@ -0,0 +1,170 @@
<template>
<div class="wrapper">
<el-form
v-if="isLoadPanel"
key="panel-loaded"
v-model="dataRecords"
label-position="top"
label-width="200px"
>
<template
v-if="firstGroup && firstGroup.groupFinal === ''"
>
<div v-show="firstGroup.activeFields" class="cards-not-group">
<div
v-if="(groupTab.groupType == 'T' && groupTab.groupName == firstGroup.groupFinal)
|| (groupTab.groupType !== 'T' && firstGroup.typeGroup !== 'T')"
class="card"
>
<div class="select-filter">
<span>
{{ firstGroup.groupFinal }}
</span>
<filter-fields
:container-uuid="containerUuid"
:panel-type="panelType"
:group-field="firstGroup.groupFinal"
:is-advanced-query="isAdvancedQuery"
/>
</div>
<el-card
:shadow="shadowGroup"
:body-style="{ padding: '10px' }"
>
<el-row>
<template v-for="(fieldAttributes, subKey) in firstGroup.metadataFields">
<field-definition
:ref="fieldAttributes.columnName"
:key="subKey"
:metadata-field="{
...fieldAttributes,
...panelAttributes
}"
:record-data-fields="isAdvancedQuery ? undefined : dataRecords[fieldAttributes.columnName]"
:in-group="!isShowedRecordNavigation"
:is-advanced-query="isAdvancedQuery"
/>
</template>
</el-row>
</el-card>
</div>
</div>
</template>
<div :class="classCards">
<draggable
key="draggable-loaded"
:list="fieldGroups"
v-bind="$attrs"
:set-data="setData"
>
<template v-for="(item, key) in fieldGroups">
<el-row :key="key">
<el-col :key="key" :span="24">
<div
v-if="item.groupFinal !== ''
&& (groupTab.groupType == 'T' && groupTab.groupName == item.groupFinal)
|| (groupTab.groupType !== 'T' && item.typeGroup !== 'T')"
:key="key"
class="card"
>
<el-card
:shadow="shadowGroup"
:body-style="{ padding: '10px' }"
>
<div slot="header" class="clearfix">
<span>
{{ item.groupFinal }}
</span>
<div class="select-filter-header">
<filter-fields
:container-uuid="containerUuid"
:panel-type="panelType"
:group-field="item.groupFinal"
:is-first-group="false"
:is-advanced-query="isAdvancedQuery"
/>
</div>
</div>
<el-row>
<template v-for="(fieldAttributes, subKey) in item.metadataFields">
<field-definition
:ref="fieldAttributes.columnName"
:key="subKey"
:metadata-field="{
...fieldAttributes,
...panelAttributes
}"
:record-data-fields="isAdvancedQuery ? undefined : dataRecords[fieldAttributes.columnName]"
:in-group="isPanelWindow && fieldGroups.length > 1"
:is-advanced-query="isAdvancedQuery"
/>
</template>
</el-row>
</el-card>
</div>
</el-col>
</el-row>
</template>
</draggable>
</div>
</el-form>
<div
v-else
key="panel-loading"
v-loading="!isLoadPanel"
:element-loading-text="$t('notifications.loading')"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.8)"
class="loading-panel"
/>
</div>
</template>
<script>
import { mainPanelMixin } from '@/components/ADempiere/Panel/mainPanelMixin.js'
import draggable from 'vuedraggable'
export default {
name: 'MainPanelDesktop',
components: {
draggable
},
mixins: [mainPanelMixin],
methods: {
setData(dataTransfer) {
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
}
}
}
</script>
<style scoped>
.loading-panel {
padding: 100px;
height: 100%;
}
.cards-in-group {
column-count: 2; /*numbers of columns */
column-gap: 1em;
}
.cards-not-group {
column-count: 1; /* numbers of columns */
column-gap: 1em;
margin-bottom: 5px;
}
.card {
/* padding: 10px; */
width: 100% !important;
transition: all 100ms ease-in-out;
display: inline-block;
perspective: 1000;
backface-visibility: hidden;
}
.el-card {
width: 100% !important;
}
</style>

View File

@ -0,0 +1,542 @@
import FieldDefinition from '@/components/ADempiere/Field'
import FilterFields from '@/components/ADempiere/Panel/filterFields'
import { fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils.js'
import { parsedValueComponent } from '@/utils/ADempiere/valueUtils.js'
import { convertObjectToKeyValue } from '@/utils/ADempiere/valueFormat.js'
export const mainPanelMixin = {
name: 'MainPanelMixin',
components: {
FieldDefinition,
FilterFields
},
props: {
parentUuid: {
type: String,
default: undefined
},
containerUuid: {
type: String,
required: true
},
metadata: {
type: Object,
default: () => {}
},
// tab type group
groupTab: {
type: Object,
default: () => ({
groupType: '',
groupName: ''
})
},
panelType: {
type: String,
default: 'window'
},
isAdvancedQuery: {
type: Boolean,
default: false
},
isShowedRecordNavigation: {
type: Boolean,
default: false
}
},
data() {
return {
panelMetadata: {},
fieldList: [], // groups list of fields
dataRecords: {},
isLoadPanel: false,
isLoadRecord: false,
uuidRecord: this.$route.query.action,
fieldGroups: [],
firstGroup: {},
groupsView: 0,
tagTitle: {
base: this.$route.meta.title,
action: ''
}
}
},
computed: {
shadowGroup() {
if (this.isMobile) {
return 'never'
}
return 'hover'
},
optionCRUD() {
return this.isEmptyValue(this.uuidRecord) ? 'create-new' : this.uuidRecord
},
isPanelWindow() {
return this.panelType === 'window'
},
panelAttributes() {
return {
recordUuid: this.uuidRecord,
optionCRUD: this.optionCRUD,
isShowedRecordNavigation: this.isShowedRecordNavigation,
isProcessingContext: this.getContainerProcessing,
isProcessedContext: this.getContainerProcessed
}
},
getContainerProcessing() {
if (this.panelType === 'window' && !this.isAdvancedQuery) {
return this.$store.getters.getContainerProcessing(this.parentUuid)
}
return false
},
getContainerProcessed() {
if (this.panelType === 'window' && !this.isAdvancedQuery) {
return this.$store.getters.getContainerProcessed(this.parentUuid)
}
return false
},
getterPanel() {
return this.$store.getters.getPanel(this.containerUuid, this.isAdvancedQuery)
},
fieldsList() {
let panel = this.panelMetadata
if (!this.isEmptyValue(panel) && panel.fieldList) {
return panel.fieldList
}
panel = this.getterPanel
if (panel) {
return panel.fieldList
}
return undefined
},
isMobile() {
return this.$store.state.app.device === 'mobile'
},
getterDataStore() {
if (this.isPanelWindow) {
return this.$store.getters.getDataRecordAndSelection(this.containerUuid)
}
return {
recordCount: 0,
isLoaded: false,
record: []
}
},
getterIsLoadedRecord() {
return this.getterDataStore.isLoaded
},
classCards() {
if (this.isMobile || this.fieldGroups.length < 2 || this.isShowedRecordNavigation) {
return 'cards-not-group'
}
return 'cards-in-group'
}
},
watch: {
// used only panel modal (process associated in browser or window)
containerUuid() {
if (['report', 'process'].includes(this.panelType)) {
this.generatePanel(this.metadata.fieldList)
}
},
'$route.query.action'(newValue, oldValue) {
// used in field, if uuid record or different create-new, field is read only
this.uuidRecord = newValue
if (newValue !== oldValue && this.isPanelWindow) {
this.changePanelRecord(newValue)
}
},
isLoadPanel(value) {
if (value) {
this.readParameters()
}
}
},
created() {
// get fields with uuid
this.getPanel()
},
methods: {
/**
* Get the tab object with all its attributes as well as the fields it contains
*/
getPanel() {
const panel = this.getterPanel
if (!this.isEmptyValue(panel) && panel.fieldList) {
this.panelMetadata = panel
const fieldsList = panel.fieldList
if (fieldsList && Array.isArray(fieldsList)) {
this.generatePanel(fieldsList)
}
} else {
this.$store.dispatch('getPanelAndFields', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
panelType: this.panelType,
panelMetadata: this.metadata,
isAdvancedQuery: this.isAdvancedQuery
}).then(panelResponse => {
this.panelMetadata = panelResponse
this.generatePanel(panelResponse.fieldList)
}).catch(error => {
console.warn(`Field Load Error: ${error.message}. Code: ${error.code}.`)
})
}
},
generatePanel(fieldsList) {
// order and assign groups
this.fieldList = fieldsList
if (fieldsList.length) {
this.fieldGroups = this.sortAndGroup(fieldsList)
}
let firstGroup
if (this.fieldGroups[0] && this.fieldGroups[0].groupFinal === '') {
firstGroup = this.fieldGroups[0]
this.fieldGroups.shift()
}
this.firstGroup = firstGroup
this.isLoadPanel = true
},
/**
* TODO: Delete route parameters after reading them
*/
readParameters() {
const parameters = {
isLoadAllRecords: true,
isReference: false,
isNewRecord: false,
isWindow: true,
criteria: {}
}
const route = this.$route
if (this.isPanelWindow) {
// TODO: use action notifyPanelChange with isShowedField in true
this.fieldsList.forEach(fieldItem => {
if (Object.prototype.hasOwnProperty.call(route.query, fieldItem.columnName) && !fieldItem.isAdvancedQuery) {
fieldItem.isShowedFromUser = true
fieldItem.value = parsedValueComponent({
componentPath: fieldItem.componentPath,
columnName: fieldItem.columnName,
value: route.query[fieldItem.columnName],
displayType: fieldItem.displayType,
isIdentifier: fieldItem.columnName.includes('_ID')
})
if (String(route.query.isAdvancedQuery) === String(fieldItem.isAdvancedQuery)) {
fieldItem.value = parsedValueComponent({
componentPath: fieldItem.componentPath,
columnName: fieldItem.columnName,
value: route.query[fieldItem.columnName],
displayType: fieldItem.displayType,
isIdentifier: fieldItem.columnName.includes('_ID')
})
if (fieldItem.isRange && this.$route.query[`${fieldItem.columnName}_To`]) {
fieldItem.valueTo = parsedValueComponent({
componentPath: fieldItem.componentPath,
columnName: fieldItem.componentPath,
value: route.query[`${fieldItem.columnName}_To`],
displayType: fieldItem.displayType,
isIdentifier: fieldItem.columnName.includes('_ID')
})
}
}
}
})
if (route.query.action && route.query.action === 'reference') {
const referenceInfo = this.$store.getters.getReferencesInfo({
windowUuid: this.parentUuid,
recordUuid: route.query.recordUuid,
referenceUuid: route.query.referenceUuid
})
route.params.isReadParameters = true
parameters.isLoadAllRecords = false
parameters.isReference = true
parameters.referenceUuid = referenceInfo.uuid
parameters.referenceWhereClause = referenceInfo.whereClause
} else if (route.query.action && route.query.action === 'create-new') {
parameters.isNewRecord = true
} else if (route.query.action && route.query.action === 'criteria') {
route.params.isReadParameters = true
Object.keys(route.params).forEach(param => {
if (!this.isEmptyValue(route.params[param])) {
parameters.criteria[param] = route.params[param]
}
})
} else if (route.query.action && route.query.action === 'listRecords') {
parameters.isLoadAllRecords = true
route.params.isReadParameters = true
} else if (!this.isEmptyValue(route.query.action) &&
!['create-new', 'reference', 'advancedQuery', 'criteria', 'listRecords'].includes(route.query.action)) {
parameters.isLoadAllRecords = false
parameters.value = route.query.action
parameters.tableName = this.metadata.tableName
parameters.columnName = 'UUID'
route.params.isReadParameters = true
}
// Only call get data if panel type is window
if (!Object.prototype.hasOwnProperty.call(route.params, 'isReadParameters') || route.params.isReadParameters) {
this.getData(parameters)
}
let viewTitle = ''
if (route.query && !this.isEmptyValue(route.query.action)) {
viewTitle = route.query.action
}
this.setTagsViewTitle(viewTitle)
} else {
if (this.panelType === 'table' && route.query.action === 'advancedQuery') {
// TODO: use action notifyPanelChange with isShowedField in true
this.fieldList.forEach(fieldItem => {
if (Object.prototype.hasOwnProperty.call(route.query, fieldItem.columnName) && fieldItem.isAdvancedQuery) {
fieldItem.isShowedFromUser = true
if (route.query.action === 'advancedQuery' && fieldItem.isAdvancedQuery) {
this.dataRecords[fieldItem.columnName] = parsedValueComponent({
componentPath: fieldItem.componentPath,
columnName: fieldItem.columnName,
value: route.query[fieldItem.columnName],
isIdentifier: fieldItem.columnName.includes('_ID')
})
if (fieldItem.isRange && route.query[`${fieldItem.columnName}_To`]) {
this.dataRecords[fieldItem.columnName] = parsedValueComponent({
componentPath: fieldItem.componentPath,
columnName: fieldItem.columnName,
value: route.query[`${fieldItem.columnName}_To`],
isIdentifier: fieldItem.columnName.includes('_ID')
})
}
}
}
})
parameters.isWindow = false
this.$store.dispatch('notifyPanelChange', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
isAdvancedQuery: route.query.action === 'advancedQuery',
newValues: this.dataRecords,
isSendToServer: true,
isSendCallout: false,
fieldList: this.fieldList,
panelType: this.panelType
})
} else if (['process', 'browser'].includes(this.panelType)) {
if (!this.isEmptyValue(route.query)) {
this.$store.dispatch('notifyPanelChange', {
containerUuid: this.containerUuid,
newValues: route.query,
isShowedField: true,
isSendCallout: false,
panelType: this.panelType
})
parameters.isWindow = false
}
}
}
},
/**
* @param {object} parameters parameters to condition the data query
*/
getData(parameters) {
if (parameters.isWindow && this.isPanelWindow && !this.getterIsLoadedRecord) {
this.$store.dispatch('getDataListTab', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
isLoadAllRecords: parameters.isLoadAllRecords,
isReference: parameters.isReference,
referenceWhereClause: parameters.referenceWhereClause,
columnName: parameters.columnName,
value: parameters.value,
criteria: parameters.criteria
})
.then(response => {
let action = 'create-new'
let params = this.$route.params
if (response.length && !parameters.isNewRecord) {
this.dataRecords = response[0]
const recordId = this.dataRecords[`${this.metadata.tableName}_ID`]
params = {
...params,
tableName: this.metadata.tableName,
recordId
}
if (this.$route.query.action === 'reference') {
action = 'reference'
} else {
// 'criteria'
action = this.dataRecords.UUID
}
let viewTitle = ''
if (this.$route.query && !this.isEmptyValue(this.$route.query.action)) {
viewTitle = this.$route.query.action
}
this.setTagsViewTitle(viewTitle)
this.isLoadRecord = true
}
this.$router.push({
name: this.$route.name,
params,
query: {
...this.$route.query,
action
}
}).catch(error => {
console.info(`Panel Component: ${error.name}, ${error.message}`)
})
if (action === 'create-new') {
this.$store.dispatch('setDefaultValues', {
panelType: this.panelType,
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
isNewRecord: true
})
} else {
const attributes = convertObjectToKeyValue({
object: this.dataRecords
})
this.$store.dispatch('notifyPanelChange', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
attributes
})
}
})
.catch(error => {
console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`)
})
}
},
/**
* Group the arrangement into groups of columns that they contain, it must
* be grouped after having the order
* @param {array} fieldsList
* @return {array} groupsList
* TODO: Save into store to dont regenerate
*/
sortAndGroup(fieldsList) {
if (this.isEmptyValue(fieldsList)) {
return
}
let groupsList = [{
groupFinal: '',
metadataFields: fieldsList
}]
// reduce, create array with number groupAssigned element comun
if (this.isPanelWindow) {
groupsList = fieldsList
.reduce((groupsList, currentValue) => {
if (!groupsList.includes(currentValue.groupAssigned)) {
groupsList.push(currentValue.groupAssigned)
}
return groupsList
}, [])
.map(itemGroup => {
return {
groupFinal: itemGroup,
metadataFields: fieldsList.filter(itemField => {
return itemField.groupAssigned === itemGroup
})
}
})
}
// count and add the field numbers according to your group
groupsList.forEach(groupFields => {
const typeG = groupFields.metadataFields[0].typeGroupAssigned
groupFields.typeGroup = typeG
const fieldsDisplayed = groupFields.metadataFields.filter(field => {
return fieldIsDisplayed(field)
})
if ((this.groupTab.groupType === 'T' && this.groupTab.groupName === groupFields.groupFinal) ||
(this.groupTab.groupType !== 'T' && groupFields.typeGroup !== 'T')) {
this.groupsView = this.groupsView + 1
}
groupFields.activeFields = fieldsDisplayed.length
})
return groupsList
},
setTagsViewTitle(actionValue) {
if (actionValue !== 'create-new' && !this.isEmptyValue(actionValue) && this.panelMetadata.isDocument && this.getterDataStore.isLoaded) {
this.$store.dispatch('listWorkflows', this.metadata.tableName)
this.$store.dispatch('listDocumentStatus', {
recordUuid: this.$route.query.action,
tableName: this.metadata.tableName
})
}
if (actionValue === 'create-new' || this.isEmptyValue(actionValue)) {
this.tagTitle.action = this.$t('tagsView.newRecord')
} else if (actionValue === 'advancedQuery') {
this.tagTitle.action = this.$t('tagsView.advancedQuery')
} else {
const { identifierColumns } = this.panelMetadata
if (!this.isEmptyValue(identifierColumns)) {
if (this.dataRecords[identifierColumns[0]]) {
this.tagTitle.action = this.dataRecords[identifierColumns[0]]
} else {
const field = this.fieldList.find(fieldItem => fieldItem.isIdentifier)
this.tagTitle.action = field.value
}
} else {
this.tagTitle.action = this.$t('tagsView.seeRecord')
}
}
if (this.isPanelWindow) {
this.$store.dispatch('tagsView/updateVisitedView', {
...this.$route,
title: `${this.tagTitle.base} - ${this.tagTitle.action}`
})
}
},
changePanelRecord(uuidRecord) {
if (!['create-new', 'reference', 'advancedQuery', 'criteria', 'listRecords'].includes(uuidRecord)) {
this.$store.dispatch('seekRecord', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
recordUuid: uuidRecord
}).then(() => {
if (this.panelMetadata.isTabsChildren) {
// delete records tabs children when change record uuid
this.$store.dispatch('deleteRecordContainer', {
viewUuid: this.parentUuid,
withOut: [this.containerUuid]
})
}
})
}
this.setTagsViewTitle(uuidRecord)
if (this.$route.query && this.$route.query.action === 'create-new') {
this.setFocus()
}
const currentRecord = this.getterDataStore.record.find(record => record.UUID === uuidRecord)
this.$store.dispatch('currentRecord', currentRecord)
},
async setFocus() {
return new Promise(resolve => {
const fieldFocus = this.fieldsList.find(itemField => {
if (itemField.handleRequestFocus) {
return true
}
if (Object.prototype.hasOwnProperty.call(this.$refs, itemField.columnName)) {
if (fieldIsDisplayed(itemField) &&
!itemField.isReadOnly &&
itemField.isUpdateable &&
itemField.componentPath !== 'FieldSelect') {
return true
}
}
})
if (fieldFocus) {
this.$refs[fieldFocus.columnName][0].focusField()
}
resolve()
return
})
}
}
}

View File

@ -0,0 +1,150 @@
<template>
<div class="wrapper">
<el-form
v-if="isLoadPanel"
key="panel-loaded"
v-model="dataRecords"
label-position="top"
label-width="200px"
>
<template
v-if="firstGroup && firstGroup.groupFinal === ''"
>
<div v-show="firstGroup.activeFields" class="cards-not-group">
<div
v-if="(groupTab.groupType == 'T' && groupTab.groupName == firstGroup.groupFinal)
|| (groupTab.groupType !== 'T' && firstGroup.typeGroup !== 'T')"
class="card"
>
<div class="select-filter">
<span>
{{ firstGroup.groupFinal }}
</span>
<filter-fields
:container-uuid="containerUuid"
:panel-type="panelType"
:group-field="firstGroup.groupFinal"
:is-advanced-query="isAdvancedQuery"
/>
</div>
<el-card
:shadow="shadowGroup"
:body-style="{ padding: '10px' }"
>
<el-row>
<template v-for="(fieldAttributes, subKey) in firstGroup.metadataFields">
<field-definition
:ref="fieldAttributes.columnName"
:key="subKey"
:metadata-field="{
...fieldAttributes,
...panelAttributes
}"
:record-data-fields="isAdvancedQuery ? undefined : dataRecords[fieldAttributes.columnName]"
:in-group="!isShowedRecordNavigation"
:is-advanced-query="isAdvancedQuery"
/>
</template>
</el-row>
</el-card>
</div>
</div>
</template>
<div :class="classCards">
<template v-for="(item, key) in fieldGroups">
<el-row :key="key">
<el-col :key="key" :span="24">
<div
v-if="item.groupFinal !== ''
&& (groupTab.groupType == 'T' && groupTab.groupName == item.groupFinal)
|| (groupTab.groupType !== 'T' && item.typeGroup !== 'T')"
:key="key"
class="card"
>
<el-card
:shadow="shadowGroup"
:body-style="{ padding: '10px' }"
>
<div slot="header" class="clearfix">
<span>
{{ item.groupFinal }}
</span>
<div v-if="!isAdvancedQuery" class="select-filter-header">
<filter-fields
:container-uuid="containerUuid"
:panel-type="panelType"
:group-field="item.groupFinal"
:is-first-group="false"
/>
</div>
</div>
<el-row>
<template v-for="(fieldAttributes, subKey) in item.metadataFields">
<field-definition
:ref="fieldAttributes.columnName"
:key="subKey"
:metadata-field="{
...fieldAttributes,
...panelAttributes
}"
:record-data-fields="isAdvancedQuery ? undefined : dataRecords[fieldAttributes.columnName]"
:in-group="isPanelWindow && fieldGroups.length > 1"
/>
</template>
</el-row>
</el-card>
</div>
</el-col>
</el-row>
</template>
</div>
</el-form>
<div
v-else
key="panel-loading"
v-loading="!isLoadPanel"
:element-loading-text="$t('notifications.loading')"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.8)"
class="loading-panel"
/>
</div>
</template>
<script>
import { mainPanelMixin } from '@/components/ADempiere/Panel/mainPanelMixin'
export default {
name: 'MainPanelMobile',
mixins: [mainPanelMixin]
}
</script>
<style scoped>
.loading-panel {
padding: 100px;
height: 100%;
}
.cards-in-group {
column-count: 2; /*numbers of columns */
column-gap: 1em;
}
.cards-not-group {
column-count: 1; /* numbers of columns */
column-gap: 1em;
margin-bottom: 5px;
}
.card {
/* padding: 10px; */
width: 100% !important;
transition: all 100ms ease-in-out;
display: inline-block;
perspective: 1000;
backface-visibility: hidden;
}
.el-card {
width: 100% !important;
}
</style>

View File

@ -177,35 +177,35 @@ export default {
}
},
documentActionChange(value) {
this.$store.dispatch('notifyFieldChange', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
columnName: 'DocAction',
isSendToServer: true,
newValue: value
})
.then(response => {
const actionProcess = this.$store.getters.getOrders
this.$store.dispatch('startProcess', {
action: {
uuid: actionProcess.uuid,
id: actionProcess.id,
name: actionProcess.name
}, // process metadata
tableName: this.$route.params.tableName,
recordId: this.$route.params.recordId,
recordUuid: this.$route.query.action,
parametersList: [{
columnName: 'DocAction',
value: this.valueActionDocument
}],
isActionDocument: true,
parentUuid: this.parentUuid,
panelType: this.panelType,
containerUuid: this.containerUuid// determinate if get table name and record id (window) or selection (browser)
})
this.valueActionDocument = ''
})
// this.$store.dispatch('notifyFieldChange', {
// parentUuid: this.parentUuid,
// containerUuid: this.containerUuid,
// columnName: 'DocAction',
// isSendToServer: true,
// newValue: value
// })
// .then(response => {
// const actionProcess = this.$store.getters.getOrders
// this.$store.dispatch('startProcess', {
// action: {
// uuid: actionProcess.uuid,
// id: actionProcess.id,
// name: actionProcess.name
// }, // process metadata
// tableName: this.$route.params.tableName,
// recordId: this.$route.params.recordId,
// recordUuid: this.$route.query.action,
// parametersList: [{
// columnName: 'DocAction',
// value: this.valueActionDocument
// }],
// isActionDocument: true,
// parentUuid: this.parentUuid,
// panelType: this.panelType,
// containerUuid: this.containerUuid// determinate if get table name and record id (window) or selection (browser)
// })
// this.valueActionDocument = ''
// })
}
}
}

View File

@ -203,7 +203,7 @@ export default {
this.$store.dispatch('setWindowOldRoute')
}
this.$store.dispatch('resetPanelToNew', {
this.$store.dispatch('setDefaultValues', {
parentUuid,
containerUuid,
panelType: view.meta.type,

View File

@ -1,192 +1,171 @@
import { getBrowser as getBrowserMetadata } from '@/api/ADempiere/dictionary'
import { showMessage } from '@/utils/ADempiere/notification'
import { getBrowserSearch } from '@/api/ADempiere/browser'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils'
import { generateField } from '@/utils/ADempiere/dictionaryUtils'
import router from '@/router'
import { parseContext } from '@/utils/ADempiere/contextUtils'
import { showMessage } from '@/utils/ADempiere/notification'
import { fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils'
import language from '@/lang'
const browser = {
state: {
browser: []
},
mutations: {
addBrowser(state, payload) {
state.browser.push(payload)
},
dictionaryResetCacheBrowser(state) {
state.browser = []
},
changeBrowserAttribute(state, payload) {
let value = payload.attributeValue
if (payload.attributeNameControl) {
value = payload.browser[payload.attributeNameControl]
}
payload.browser[payload.attributeName] = value
}
},
const browserControl = {
actions: {
getBrowserFromServer({ commit, dispatch }, {
browserActionPerformed({ dispatch, getters }, {
containerUuid,
browserId,
routeToDelete
field,
value
}) {
return new Promise(resolve => {
getBrowserMetadata({
uuid: containerUuid,
id: browserId
const fieldsEmpty = getters.getFieldListEmptyMandatory({
containerUuid,
fieldsList: getters.getFieldsListFromPanel(containerUuid)
})
if (!isEmptyValue(fieldsEmpty)) {
showMessage({
message: language.t('notifications.mandatoryFieldMissing') + fieldsEmpty,
type: 'info'
})
.then(browserResponse => {
const panelType = 'browser'
const additionalAttributes = {
containerUuid,
panelType,
isEvaluateValueChanges: true
}
const {
query,
whereClause,
process
} = browserResponse
// Convert from gRPC
const fieldsRangeList = []
let isShowedCriteria = false
let awaitForValues = 0
let fieldsList = browserResponse.fieldsList.map((fieldItem, index) => {
const someAttributes = {
...additionalAttributes,
fieldListIndex: index
}
const field = generateField({
fieldToGenerate: fieldItem,
moreAttributes: someAttributes,
isSOTrxMenu: routeToDelete.meta.isSOTrx
})
// Add new field if is range number
if (field.isRange && field.componentPath === 'FieldNumber') {
const fieldRange = generateField({
fieldToGenerate: fieldItem,
moreAttributes: someAttributes,
typeRange: true
})
if (!isEmptyValue(fieldRange.value)) {
fieldRange.isShowedFromUser = true
}
fieldsRangeList.push(fieldRange)
}
// Only isQueryCriteria fields with values, displayed in main panel
if (field.isQueryCriteria) {
if (field.isSQLValue) {
isShowedCriteria = true
field.isShowedFromUser = true
awaitForValues++
}
if (query.includes(`@${field.columnName}@`) ||
query.includes(`@${field.columnName}_To@`) ||
whereClause.includes(`@${field.columnName}@`) ||
whereClause.includes(`@${field.columnName}_To@`)) {
field.isMandatory = true
field.isMandatoryFromLogic = true
field.isShowedFromUser = true
}
if (isEmptyValue(field.value)) {
// isMandatory params to showed search criteria
if (field.isMandatory || field.isMandatoryFromLogic) {
isShowedCriteria = true
}
} else {
// with value
field.isShowedFromUser = true
}
}
return field
})
fieldsList = fieldsList.concat(fieldsRangeList)
// Panel for save on store
const newBrowser = {
...browserResponse,
containerUuid,
fieldList: fieldsList,
panelType,
// app attributes
awaitForValues, // control to values
awaitForValuesToQuery: awaitForValues, // get values from request search
isShowedCriteria,
isShowedTotals: true
}
commit('addBrowser', newBrowser)
dispatch('addPanel', newBrowser)
resolve(newBrowser)
// Convert from gRPC process list
const actions = []
if (process) {
actions.push({
type: 'process',
panelType: 'process',
uuid: process.uuid,
name: process.name,
description: process.description,
isReport: process.isReport,
isDirectPrint: process.isDirectPrint,
containerUuidAssociated: containerUuid,
panelTypeAssociated: panelType
})
// TODO: No list of parameters
// // add process associated in vuex store
// dispatch('addProcessAssociated', {
// processToGenerate: process,
// containerUuidAssociated: containerUuid
// })
}
// Add process menu
dispatch('setContextMenu', {
containerUuid,
actions
})
})
.catch(error => {
router.push({ path: '/dashboard' })
dispatch('tagsView/delView', routeToDelete)
showMessage({
message: language.t('login.unexpectedError'),
type: 'error'
})
console.warn(`Dictionary Browser - Error ${error.code}: ${error.message}.`)
})
})
},
changeBrowserAttribute({ commit, getters }, {
containerUuid,
browser,
attributeName,
attributeNameControl,
attributeValue
}) {
if (isEmptyValue(browser)) {
browser = getters.getBrowser(containerUuid)
return
}
commit('changeBrowserAttribute', {
browser,
attributeName,
attributeValue,
attributeNameControl
// Validate if a field is called and visible
if (fieldIsDisplayed(field)) {
let isReadyForQuery = true
if (field.isSQLValue) {
const panel = getters.getPanel(containerUuid)
let awaitForValuesToQuery = panel.awaitForValuesToQuery
awaitForValuesToQuery--
dispatch('changeBrowserAttribute', {
containerUuid,
attributeName: 'awaitForValuesToQuery',
attributeValue: awaitForValuesToQuery
})
if (awaitForValuesToQuery === 0) {
if (panel.isShowedCriteria) {
dispatch('changeBrowserAttribute', {
containerUuid,
attributeName: 'isShowedCriteria',
attributeValue: false
})
}
} else if (awaitForValuesToQuery > 0) {
isReadyForQuery = false
}
}
if (isReadyForQuery && !field.dependentFieldsList.length) {
dispatch('getBrowserSearch', {
containerUuid,
isClearSelection: true
})
}
}
},
// Search with query criteria
getBrowserSearch({ dispatch, rootGetters }, {
containerUuid,
isClearSelection = false
}) {
showMessage({
title: language.t('notifications.loading'),
message: language.t('notifications.searching'),
type: 'info'
})
}
},
getters: {
getBrowser: (state) => (browserUuid) => {
return state.browser.find(
item => item.uuid === browserUuid
)
const allData = rootGetters.getDataRecordAndSelection(containerUuid)
// deletes the data from the container to replace it and to report the searches in the table
dispatch('deleteRecordContainer', {
viewUuid: containerUuid
})
const browser = rootGetters.getBrowser(containerUuid)
// parameters isQueryCriteria
const parametersList = rootGetters.getParametersToServer({
containerUuid,
fieldList: browser.fieldList
})
let parsedQuery = browser.query
if (!isEmptyValue(parsedQuery) && parsedQuery.includes('@')) {
parsedQuery = parseContext({
containerUuid,
value: parsedQuery,
isBooleanToString: true
}).value
}
let parsedWhereClause = browser.whereClause
if (!isEmptyValue(parsedWhereClause) && parsedWhereClause.includes('@')) {
parsedWhereClause = parseContext({
containerUuid,
value: parsedWhereClause,
isBooleanToString: true
}).value
}
let nextPageToken
if (!isEmptyValue(allData.nextPageToken)) {
nextPageToken = allData.nextPageToken + '-' + allData.pageNumber
}
// Add validation compare browserSearchQueryParameters
return getBrowserSearch({
uuid: containerUuid,
query: parsedQuery,
whereClause: parsedWhereClause,
orderByClause: browser.orderByClause,
parametersList,
nextPageToken: nextPageToken
})
.then(browserSearchResponse => {
const recordsList = browserSearchResponse.recordsList.map(itemRecord => {
return {
...itemRecord.values,
// datatables attributes
isNew: false,
isEdit: false,
isSelected: false,
isReadOnlyFromRow: false
}
})
let selection = allData.selection
if (isClearSelection) {
selection = []
}
let token = browserSearchResponse.nextPageToken
if (token !== undefined) {
token = token.slice(0, -2)
}
dispatch('setRecordSelection', {
containerUuid,
record: recordsList,
pageNumber: rootGetters.getPageNumber(containerUuid),
selection: selection,
recordCount: browserSearchResponse.recordCount,
nextPageToken: token
})
showMessage({
title: language.t('notifications.succesful'),
message: language.t('notifications.succcessSearch'),
type: 'success'
})
return recordsList
})
.catch(error => {
// Set default registry values so that the table does not say loading,
// there was already a response from the server
dispatch('setRecordSelection', {
containerUuid,
panelType: 'browser'
})
showMessage({
title: language.t('notifications.error'),
message: language.t('notifications.errorSearch'),
summary: error.message,
type: 'error'
})
console.warn(`Error getting browser search: ${error.message}. Code: ${error.code}.`)
})
}
}
}
export default browser
export default browserControl

View File

@ -1,125 +0,0 @@
import { getBrowserSearch } from '@/api/ADempiere/browser'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils'
import { parseContext } from '@/utils/ADempiere/contextUtils'
import { showMessage } from '@/utils/ADempiere/notification'
import language from '@/lang'
const browserControl = {
actions: {
/**
* Search with query criteria
* @param {string} containerUuid, browser to search record data
* @param {boolean} isClearSelection, clear selection after search
*/
getBrowserSearch({ dispatch, rootGetters }, {
containerUuid,
isClearSelection = false
}) {
showMessage({
title: language.t('notifications.loading'),
message: language.t('notifications.searching'),
type: 'info'
})
const allData = rootGetters.getDataRecordAndSelection(containerUuid)
// deletes the data from the container to replace it and to report the searches in the table
dispatch('deleteRecordContainer', {
viewUuid: containerUuid
})
const browser = rootGetters.getBrowser(containerUuid)
// parameters isQueryCriteria
const parametersList = rootGetters.getParametersToServer({
containerUuid,
fieldList: browser.fieldList
})
let parsedQuery = browser.query
if (!isEmptyValue(parsedQuery) && parsedQuery.includes('@')) {
parsedQuery = parseContext({
containerUuid,
value: parsedQuery,
isBooleanToString: true
}).value
}
let parsedWhereClause = browser.whereClause
if (!isEmptyValue(parsedWhereClause) && parsedWhereClause.includes('@')) {
parsedWhereClause = parseContext({
containerUuid,
value: parsedWhereClause,
isBooleanToString: true
}).value
}
let nextPageToken
if (!isEmptyValue(allData.nextPageToken)) {
nextPageToken = allData.nextPageToken + '-' + allData.pageNumber
}
// Add validation compare browserSearchQueryParameters
return getBrowserSearch({
uuid: containerUuid,
query: parsedQuery,
whereClause: parsedWhereClause,
orderByClause: browser.orderByClause,
parametersList,
nextPageToken: nextPageToken
})
.then(browserSearchResponse => {
const recordsList = browserSearchResponse.recordsList.map(itemRecord => {
return {
...itemRecord.values,
// datatables attributes
isNew: false,
isEdit: false,
isSelected: false,
isReadOnlyFromRow: false
}
})
let selection = allData.selection
if (isClearSelection) {
selection = []
}
let token = browserSearchResponse.nextPageToken
if (token !== undefined) {
token = token.slice(0, -2)
}
dispatch('setRecordSelection', {
containerUuid,
record: recordsList,
pageNumber: rootGetters.getPageNumber(containerUuid),
selection: selection,
recordCount: browserSearchResponse.recordCount,
nextPageToken: token
})
showMessage({
title: language.t('notifications.succesful'),
message: language.t('notifications.succcessSearch'),
type: 'success'
})
return recordsList
})
.catch(error => {
// Set default registry values so that the table does not say loading,
// there was already a response from the server
dispatch('setRecordSelection', {
containerUuid,
panelType: 'browser'
})
showMessage({
title: language.t('notifications.error'),
message: language.t('notifications.errorSearch'),
summary: error.message,
type: 'error'
})
console.warn(`Error getting browser search: ${error.message}. Code: ${error.code}.`)
})
}
}
}
export default browserControl

View File

@ -0,0 +1,198 @@
import { getBrowser as getBrowserMetadata } from '@/api/ADempiere/dictionary'
import { showMessage } from '@/utils/ADempiere/notification'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils'
import { generateField } from '@/utils/ADempiere/dictionaryUtils'
import router from '@/router'
import language from '@/lang'
const browser = {
state: {
browser: []
},
mutations: {
addBrowser(state, payload) {
state.browser.push(payload)
},
dictionaryResetCacheBrowser(state) {
state.browser = []
},
changeBrowserAttribute(state, payload) {
let value = payload.attributeValue
if (payload.attributeNameControl) {
value = payload.browser[payload.attributeNameControl]
}
payload.browser[payload.attributeName] = value
}
},
actions: {
/**
* Get Smart Browser metadata from server
* @param {string} containerUuid
* @param {number} browserId
* @param {object} routeToDelete, route to close in tagView when fail
*/
getBrowserFromServer({ commit, dispatch }, {
containerUuid,
browserId,
routeToDelete
}) {
return new Promise(resolve => {
getBrowserMetadata({
uuid: containerUuid,
id: browserId
})
.then(browserResponse => {
const panelType = 'browser'
const additionalAttributes = {
containerUuid,
panelType,
isEvaluateValueChanges: true
}
const {
query,
whereClause,
process
} = browserResponse
// Convert from gRPC
const fieldsRangeList = []
let isShowedCriteria = false
let awaitForValues = 0
let fieldsList = browserResponse.fieldsList.map((fieldItem, index) => {
const someAttributes = {
...additionalAttributes,
fieldListIndex: index
}
const field = generateField({
fieldToGenerate: fieldItem,
moreAttributes: someAttributes,
isSOTrxMenu: routeToDelete.meta.isSOTrx
})
// Add new field if is range number
if (field.isRange && field.componentPath === 'FieldNumber') {
const fieldRange = generateField({
fieldToGenerate: fieldItem,
moreAttributes: someAttributes,
typeRange: true
})
if (!isEmptyValue(fieldRange.value)) {
fieldRange.isShowedFromUser = true
}
fieldsRangeList.push(fieldRange)
}
// Only isQueryCriteria fields with values, displayed in main panel
if (field.isQueryCriteria) {
if (field.isSQLValue) {
isShowedCriteria = true
field.isShowedFromUser = true
awaitForValues++
}
if (query.includes(`@${field.columnName}@`) ||
query.includes(`@${field.columnName}_To@`) ||
whereClause.includes(`@${field.columnName}@`) ||
whereClause.includes(`@${field.columnName}_To@`)) {
field.isMandatory = true
field.isMandatoryFromLogic = true
field.isShowedFromUser = true
}
if (isEmptyValue(field.value)) {
// isMandatory params to showed search criteria
if (field.isMandatory || field.isMandatoryFromLogic) {
isShowedCriteria = true
}
} else {
// with value
field.isShowedFromUser = true
}
}
return field
})
fieldsList = fieldsList.concat(fieldsRangeList)
// Panel for save on store
const newBrowser = {
...browserResponse,
containerUuid,
fieldList: fieldsList,
panelType,
// app attributes
awaitForValues, // control to values
awaitForValuesToQuery: awaitForValues, // get values from request search
isShowedCriteria,
isShowedTotals: true
}
commit('addBrowser', newBrowser)
dispatch('addPanel', newBrowser)
resolve(newBrowser)
// Convert from gRPC process list
const actions = []
if (process) {
actions.push({
type: 'process',
panelType: 'process',
uuid: process.uuid,
name: process.name,
description: process.description,
isReport: process.isReport,
isDirectPrint: process.isDirectPrint,
containerUuidAssociated: containerUuid,
panelTypeAssociated: panelType
})
// TODO: No list of parameters
// // add process associated in vuex store
// dispatch('addProcessAssociated', {
// processToGenerate: process,
// containerUuidAssociated: containerUuid
// })
}
// Add process menu
dispatch('setContextMenu', {
containerUuid,
actions
})
})
.catch(error => {
router.push({ path: '/dashboard' })
dispatch('tagsView/delView', routeToDelete)
showMessage({
message: language.t('login.unexpectedError'),
type: 'error'
})
console.warn(`Dictionary Browser - Error ${error.code}: ${error.message}.`)
})
})
},
changeBrowserAttribute({ commit, getters }, {
containerUuid,
browser,
attributeName,
attributeNameControl,
attributeValue
}) {
if (isEmptyValue(browser)) {
browser = getters.getBrowser(containerUuid)
}
commit('changeBrowserAttribute', {
browser,
attributeName,
attributeValue,
attributeNameControl
})
}
},
getters: {
getBrowser: (state) => (browserUuid) => {
return state.browser.find(
item => item.uuid === browserUuid
)
}
}
}
export default browser

View File

@ -1,5 +1,6 @@
import { runCallOutRequest } from '@/api/ADempiere/rule'
import { showMessage } from '@/utils/ADempiere/notification'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils'
import language from '@/lang'
const callOutControl = {
@ -19,7 +20,7 @@ const callOutControl = {
* @param {String} valueType
* @return {Promise} values
*/
getCallout({ rootGetters, dispatch }, {
runCallout({ rootGetters, dispatch }, {
parentUuid,
containerUuid,
callout,
@ -32,6 +33,10 @@ const callOutControl = {
oldValue,
valueType
}) {
if (isEmptyValue(value) || isEmptyValue(callout)) {
return undefined
}
// Else
return new Promise((resolve, reject) => {
const window = rootGetters.getWindow(parentUuid)
const attributesList = rootGetters.getParametersToServer({

View File

@ -1,178 +0,0 @@
import Vue from 'vue'
// Delete when get global context and account context
import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js'
const context = {
state: {
context: {}
},
mutations: {
/**
* Set context in state
* @param {string} payload.parentUuid
* @param {string} payload.containerUuid
* @param {string} payload.columnName
* @param {mixed} payload.value
*/
setContext(state, payload) {
let key = ''
if (payload.parentUuid) {
key += payload.parentUuid + '|'
// set context for window
const keyParent = key + payload.columnName
Vue.set(state.context, keyParent, payload.value)
}
if (payload.containerUuid) {
key += payload.containerUuid + '|'
}
key += payload.columnName
// set property to object
Vue.set(state.context, key, payload.value)
},
setInitialContext(state, objectContext) {
Object.keys(objectContext).forEach(key => {
Vue.set(state.context, key, objectContext[key])
})
},
dictionaryResetCacheContext(state) {
state.context = {}
}
},
actions: {
setContext({ commit }, objectValue) {
commit('setContext', objectValue)
},
setMultipleContext({ commit }, valuesToSetter) {
valuesToSetter.forEach(itemToSetter => {
commit('setContext', itemToSetter)
})
},
setMultipleContextView({ commit }, {
parentUuid,
containerUuid,
values
}) {
Object.keys(values).forEach(key => {
commit('setContext', {
parentUuid,
containerUuid,
columnName: key,
value: values[key]
})
})
},
setMultipleContextObject({ commit }, valuesToSetter) {
Object.keys(valuesToSetter).forEach(key => {
commit('setContext', {
columnName: key,
value: valuesToSetter[key]
})
})
},
setMultipleContextMap({ commit }, valuesToSetter) {
return new Promise(resolve => {
valuesToSetter.forEach((value, key) => {
commit('setContext', {
columnName: key,
value: value
})
})
resolve()
})
},
setInitialContext({ commit }, otherContext = {}) {
commit('setInitialContext', otherContext)
}
},
getters: {
/**
* @param {string} parentUuid
* @param {string} containerUuid
* @param {string} columnName
*/
getContext: (state) => ({ parentUuid, containerUuid, columnName }) => {
let key = ''
if (parentUuid) {
key += parentUuid + '|'
// context for window
const keyParent = key + columnName
const valueParent = state.context[keyParent]
if (!isEmptyValue(valueParent)) {
return valueParent
}
}
if (containerUuid) {
key += containerUuid + '|'
}
key += columnName
return state.context[key]
},
/**
* @param {string} parentUuid
* @param {string} containerUuid
* @returns {object}
*/
getContextView: (state) => ({
parentUuid,
containerUuid
}) => {
// generate context with parent uuid or container uuid associated
const contextAllContainers = {}
Object.keys(state.context).forEach(key => {
if (key.includes(parentUuid) || key.includes(containerUuid)) {
contextAllContainers[key] = state.context[key]
}
})
// generate context only columnName
const contextContainer = {}
Object.keys(contextAllContainers).forEach(key => {
if (isEmptyValue(contextAllContainers[key])) {
return
}
let newKey
if (parentUuid) {
if (!key.includes(containerUuid)) {
newKey = key
.replace(`${parentUuid}|`, '')
.replace(`${containerUuid}|`, '')
// set window parent context
contextContainer[newKey] = contextAllContainers[key]
}
// next if is tab context
return
}
// set container context (smart browser, process/report)
newKey = key.replace(`${containerUuid}|`, '')
contextContainer[newKey] = contextAllContainers[key]
})
return contextContainer
},
getContextAll: (state) => {
return state.context
},
getContextClientId: (state) => {
return parseInt(state.context['#AD_Client_ID'], 10)
},
getContextOrgId: (state) => {
return parseInt(state.context['#AD_Org_ID'], 10)
},
// Using to read only in data tables
getContextIsActive: (state) => (parentUuid) => {
return state.context[`${parentUuid}|IsActive`]
},
getContextProcessing: (state) => (parentUuid) => {
return state.context[`${parentUuid}|Processing`]
},
getContextProcessed: (state) => (parentUuid) => {
return state.context[`${parentUuid}|Processed`]
}
}
}
export default context

View File

@ -1,4 +1,3 @@
import Vue from 'vue'
import { getEntity, getEntitiesList } from '@/api/ADempiere/persistence'
import { getDefaultValueFromServer, getContextInfoValueFromServer } from '@/api/ADempiere/values'
import { getPrivateAccessFromServer, lockPrivateAccessFromServer, unlockPrivateAccessFromServer } from '@/api/ADempiere/private-access'
@ -70,9 +69,6 @@ const data = {
addNewRow(state, payload) {
payload.data = payload.data.unshift(payload.values)
},
addDisplayColumn(state, payload) {
Vue.set(payload.row, payload.columnName, payload.displayColumn)
},
setContextInfoField(state, payload) {
state.contextInfoField.push(payload)
},
@ -202,7 +198,11 @@ const data = {
if (fieldList.length) {
fieldList
// TODO: Evaluate if is field is read only and FieldSelect
.filter(itemField => itemField.componentPath === 'FieldSelect' || String(values[itemField.columnName]) === '[object Object]' || itemField.isSQLValue)
.filter(itemField => {
return itemField.componentPath === 'FieldSelect' ||
String(values[itemField.columnName]) === '[object Object]' ||
itemField.isSQLValue
})
.map(async itemField => {
const { columnName, componentPath } = itemField
let valueGetDisplayColumn = values[columnName]
@ -210,7 +210,7 @@ const data = {
if (String(values[columnName]) === '[object Object]') {
if (componentPath === 'FieldSelect') {
values[columnName] = ' '
values[`DisplayColumn_${columnName}`] = ' '
values[itemField.displayColumnName] = ' '
} else if (componentPath === 'FieldNumber') {
values[columnName] = 0
}
@ -237,7 +237,9 @@ const data = {
}
}
if (!isEmptyValue(valueGetDisplayColumn) && String(valueGetDisplayColumn) === '[object Object]' && valueGetDisplayColumn.isSQL) {
if (!isEmptyValue(valueGetDisplayColumn) &&
String(valueGetDisplayColumn) === '[object Object]' &&
valueGetDisplayColumn.isSQL) {
// get value from Query
valueGetDisplayColumn = await dispatch('getValueBySQL', {
parentUuid,
@ -265,7 +267,7 @@ const data = {
const option = options.find(itemOption => itemOption.key === valueGetDisplayColumn)
// if there is a lookup option, assign the display column with the label
if (option) {
values[`DisplayColumn_${columnName}`] = option.label
values[itemField.displayColumnName] = option.label
// if (isEmptyValue(option.label) && !itemField.isMandatory) {
// values[columnName] = undefined
// }
@ -279,7 +281,7 @@ const data = {
columnName: 'Name'
})
if (!isEmptyValue(nameParent)) {
values[`DisplayColumn_${columnName}`] = nameParent
values[itemField.displayColumnName] = nameParent
return
}
}
@ -291,7 +293,7 @@ const data = {
directQuery: itemField.reference.directQuery,
value: valueGetDisplayColumn
})
values[`DisplayColumn_${columnName}`] = label
values[itemField.displayColumnName] = label
})
}
@ -308,26 +310,6 @@ const data = {
data: dataStore
})
},
/**
* Add or change display column in table of records
* @param {string} containerUuid
* @param {string} columnName
* @param {string} displayColumn
*/
addDisplayColumn({ commit, getters }, {
containerUuid,
columnName,
displayColumn
}) {
const dataStore = getters.getDataRecordsList(containerUuid)
const rowRecord = dataStore.find(itemData => itemData.isNew)
commit('addDisplayColumn', {
row: rowRecord,
displayColumn,
columnName: `DisplayColumn_${columnName}`
})
},
/**
* Is load context in true when panel is set context
* @param {string} containerUuid
@ -524,6 +506,7 @@ const data = {
defaultValues = rootGetters.getParsedDefaultValues({
parentUuid,
containerUuid,
formatToReturn: 'object',
isGetServer: false
})
}
@ -744,7 +727,7 @@ const data = {
if (isSendCallout && !withOutColumnNames.includes(field.columnName) &&
!isEmptyValue(newValue) && !isEmptyValue(field.callout)) {
withOutColumnNames.push(field.columnName)
dispatch('getCallout', {
dispatch('runCallout', {
parentUuid,
containerUuid,
tableName: field.tableName,

View File

@ -23,9 +23,11 @@
export const ACTION_PERFORMED = 1
export const FOCUS_GAINED = 2
export const FOCUS_LOST = 3
// Input actions
export const KEY_PRESSED = 4
export const KEY_RELEASED = 5
const event = {
state: {
fieldEvents: [],

View File

@ -0,0 +1,159 @@
import Vue from 'vue'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js'
import { convertStringToBoolean } from '@/utils/ADempiere/valueFormat.js'
const UUID_KEY = 'UUID'
const value = {
state: {
field: {}
},
mutations: {
resetStatevalue(state) {
state = {
field: {}
}
},
updateValueOfField(state, payload) {
// Only Parent
if (payload.parentUuid) {
const keyParent = payload.parentUuid + '_' + payload.columnName
if (payload.value !== state.field[keyParent]) {
Vue.set(state.field, keyParent, payload.value)
}
}
// Only Container
if (payload.containerUuid) {
const keyContainer = payload.containerUuid + '_' + payload.columnName
if (payload.value !== state.field[keyContainer]) {
Vue.set(state.field, keyContainer, payload.value)
}
}
},
updateValuesOfContainer(state, payload) {
payload.attributes.forEach(attribute => {
const { value, columnName } = attribute
// Only Parent
if (payload.parentUuid) {
const keyParent = payload.parentUuid + '_' + columnName
if (value !== state.field[keyParent]) {
Vue.set(state.field, keyParent, value)
}
}
// Only Container
if (payload.containerUuid) {
const keyContainer = payload.containerUuid + '_' + columnName
if (value !== state.field[keyContainer]) {
Vue.set(state.field, keyContainer, value)
}
}
})
}
},
actions: {
updateValuesOfContainer({ commit }, {
parentUuid,
containerUuid,
attributes = []
}) {
commit('updateValuesOfContainer', {
parentUuid,
containerUuid,
attributes
})
}
},
getters: {
getValueOfField: (state) => ({ containerUuid, columnName }) => {
return state.field[containerUuid + '_' + columnName]
},
getValueOfContainer: (state) => ({ parentUuid, containerUuid, columnName }) => {
// get in tab level
let value = state.field[containerUuid + '_' + columnName]
if (isEmptyValue(value) && parentUuid) {
// get in window level
value = state.field[parentUuid + '_' + columnName]
}
return value
},
/**
* Get values and column's name as key (without parent uuid or container
* uuid), from a view (container)
* @param {string} parentUuid
* @param {string} containerUuid
* @returns {object|array}
*/
getValuesView: (state) => ({
parentUuid,
containerUuid,
format = 'array'
}) => {
console.log(parentUuid, containerUuid)
// generate context with parent uuid or container uuid associated
const contextAllContainers = {}
Object.keys(state.field).forEach(key => {
if (key.includes(parentUuid) || key.includes(containerUuid)) {
contextAllContainers[key] = state.field[key]
}
})
// generate context only columnName
const objectValues = {}
const pairsValues = Object.keys(contextAllContainers).map(key => {
const value = contextAllContainers[key]
if (isEmptyValue(value)) {
return
}
let columnName
if (parentUuid) {
if (!key.includes(containerUuid)) {
columnName = key
.replace(`${parentUuid}_`, '')
.replace(`${containerUuid}_`, '')
// set window parent context
objectValues[columnName] = value
}
// next if is tab context
return {
columnName,
value
}
}
// set container context (smart browser, process/report, form)
columnName = key.replace(`${containerUuid}_`, '')
objectValues[columnName] = value
return {
columnName,
value
}
})
if (format === 'array') {
return pairsValues
}
return objectValues
},
getUuidOfContainer: (state) => (containerUuid) => {
return state.field[containerUuid + '_' + UUID_KEY]
},
// Using to read only in data tables in Window
getContainerIsActive: (state) => (parentUuid) => {
const valueIsActive = state.field[`${parentUuid}_IsActive`]
return convertStringToBoolean(valueIsActive)
},
getContainerProcessing: (state) => (parentUuid) => {
const valueProcessing = state.field[`${parentUuid}_Processing`]
return convertStringToBoolean(valueProcessing)
},
getContainerProcessed: (state) => (parentUuid) => {
const valueProcessed = state.field[`${parentUuid}_Processed`]
return convertStringToBoolean(valueProcessed)
}
}
}
export default value

View File

@ -1,4 +1,4 @@
import { getLookup, getLookupList } from '@/api/ADempiere/values'
import { requestLookup, requestLookupList } from '@/api/ADempiere/values.js'
import { getToken as getSession } from '@/utils/auth'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils'
import { parseContext } from '@/utils/ADempiere/contextUtils'
@ -55,7 +55,7 @@ const lookup = {
}).value
}
return getLookup({
return requestLookup({
tableName,
directQuery: parsedDirectQuery,
value
@ -73,7 +73,7 @@ const lookup = {
parsedDirectQuery: directQuery,
tableName,
sessionUuid: getSession(),
clientId: rootGetters.getContextClientId
clientId: rootGetters.getPreferenceClientId
})
return option
})
@ -83,16 +83,22 @@ const lookup = {
},
/**
* Get display column's list from lookup
* @param {string} parentUuid
* @param {string} containerUuid
* @param {string} tableName
* @param {string} query
* @param {string} parentUuid
* @param {string} containerUuid
* @param {string} tableName
* @param {string} query
* @param {boolean} isAddBlankValue
* @param {mixed} blankValue
* @param {Array<String>|<Number>} valuesList
*/
getLookupListFromServer({ commit, rootGetters }, {
parentUuid,
containerUuid,
tableName,
query
query,
isAddBlankValue = false,
blankValue,
valuesList = []
}) {
if (isEmptyValue(query)) {
return
@ -106,28 +112,38 @@ const lookup = {
isBooleanToString: true
}).value
}
return getLookupList({
return requestLookupList({
tableName,
query: parsedQuery
query: parsedQuery,
valuesList
})
.then(lookupListResponse => {
const list = []
lookupListResponse.recordsList.forEach(itemLookup => {
const key = itemLookup.values.KeyColumn
if (![null, -1, undefined].includes(key)) {
const {
KeyColumn: key,
DisplayColumn: label
} = itemLookup.values
if (!isEmptyValue(key)) {
list.push({
label: itemLookup.values.DisplayColumn,
label,
key
})
}
})
if (isAddBlankValue) {
list.unshift({
label: ' ',
key: blankValue
})
}
commit('addLoockupList', {
list,
tableName,
parsedQuery,
sessionUuid: getSession(),
clientId: rootGetters.getContextClientId
clientId: rootGetters.getPreferenceClientId
})
return list
})
@ -200,7 +216,7 @@ const lookup = {
return itemLookup.parsedDirectQuery === parsedDirectQuery &&
itemLookup.tableName === tableName &&
itemLookup.sessionUuid === getSession() &&
itemLookup.clientId === rootGetters.getContextClientId &&
itemLookup.clientId === rootGetters.getPreferenceClientId &&
itemLookup.value === value
})
if (lookupItem) {
@ -227,7 +243,7 @@ const lookup = {
return itemLookup.parsedQuery === parsedQuery &&
itemLookup.tableName === tableName &&
itemLookup.sessionUuid === getSession() &&
itemLookup.clientId === rootGetters.getContextClientId
itemLookup.clientId === rootGetters.getPreferenceClientId
})
if (lookupList) {
return lookupList.list

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
import { createEntity, updateEntity } from '@/api/ADempiere/persistence.js'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js'
const persistence = {
state: {
persistence: {}
},
mutations: {
resetStatepersistence(state) {
state = {
persistence: {}
}
},
addChangeToPersistenceQueue(state, {
containerUuid,
columnName,
valueType,
value
}) {
if (isEmptyValue(state.persistence[containerUuid])) {
state.persistence[containerUuid] = new Map()
}
// Set value
state.persistence[containerUuid].set(columnName, {
columnName,
valueType,
value
})
}
},
actions: {
flushPersistenceQueue({ getters }, {
containerUuid,
tableName,
recordUuid
}) {
return new Promise((resolve, reject) => {
let attributes = getters.getPersistenceAttributes(containerUuid)
if (attributes) {
if (recordUuid) {
// Update existing entity
updateEntity({
tableName,
recordUuid,
attributes
})
.then(response => resolve(response))
.catch(error => reject(error))
} else {
attributes = attributes.filter(itemAttribute => !isEmptyValue(itemAttribute.value))
// Create new entity
createEntity({
tableName,
attributes
})
.then(response => resolve(response))
.catch(error => reject(error))
}
}
})
}
},
getters: {
getPersistenceMap: (state) => (tableName) => {
return state.persistence[tableName]
},
getPersistenceAttributes: (state) => (containerUuid) => {
const attributesMap = state.persistence[containerUuid]
if (!isEmptyValue(attributesMap)) {
return [
...attributesMap.values()
]
}
return undefined
}
}
}
export default persistence

View File

@ -0,0 +1,158 @@
import Vue from 'vue'
// Delete when get global context and account context
import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js'
const preference = {
state: {
preference: {}
},
mutations: {
/**
* Set context in state
* @param {string} payload.parentUuid
* @param {string} payload.containerUuid
* @param {string} payload.columnName
* @param {mixed} payload.value
*/
setContext(state, payload) {
let key = ''
if (payload.parentUuid) {
key += payload.parentUuid + '|'
// set context for window
const keyParent = key + payload.columnName
Vue.set(state.preference, keyParent, payload.value)
}
if (payload.containerUuid) {
key += payload.containerUuid + '|'
}
key += payload.columnName
// set property to object
Vue.set(state.preference, key, payload.value)
},
setInitialContext(state, objectContext) {
Object.keys(objectContext).forEach(key => {
Vue.set(state.preference, key, objectContext[key])
})
},
setMultiplePreference(state, preferenceToSet) {
if (!isEmptyValue(state.preference)) {
// join and overwrite old values
preferenceToSet = {
...state.preference,
...preferenceToSet
}
}
state.preference = preferenceToSet
},
dictionaryResetCacheContext(state) {
state.preference = {}
}
},
actions: {
setContext({ commit }, objectValue) {
commit('setContext', objectValue)
},
setMultiplePreference({ dispatch }, {
parentUuid,
containerUuid,
values
}) {
let actionToDispatch = 'setMultiplePreferenceObject'
if (Object.prototype.toString.call(values) === '[object Map]') {
actionToDispatch = 'setMultiplePreferenceMap'
}
return dispatch(actionToDispatch, {
parentUuid,
containerUuid,
values
})
},
setMultiplePreferenceObject({ commit }, {
parentUuid,
containerUuid,
values
}) {
return new Promise(resolve => {
if (!isEmptyValue(containerUuid) || !isEmptyValue(parentUuid)) {
Object.keys(values).forEach(key => {
commit('setContext', {
parentUuid,
containerUuid,
columnName: key,
value: values[key]
})
})
} else {
commit('setMultiplePreference', values)
}
resolve()
})
},
setMultiplePreferenceMap({ commit }, {
parentUuid,
containerUuid,
values
}) {
return new Promise(resolve => {
if (!isEmptyValue(containerUuid) || !isEmptyValue(parentUuid)) {
values.forEach((value, key) => {
commit('setContext', {
parentUuid,
containerUuid,
columnName: key,
value
})
})
} else {
commit('setMultiplePreference', Object.fromEntries(values))
}
resolve()
})
}
},
getters: {
/**
* @param {string} parentUuid
* @param {string} containerUuid
* @param {string} columnName
*/
getPreference: (state) => ({
parentUuid,
containerUuid,
columnName
}) => {
let key = ''
if (parentUuid) {
key += parentUuid + '|'
// context for window
const keyParent = key + columnName
const valueParent = state.preference[keyParent]
if (!isEmptyValue(valueParent)) {
return valueParent
}
}
if (containerUuid) {
key += containerUuid + '|'
}
key += columnName
return state.preference[key]
},
getAllPreference: (state) => {
return state.preference
},
getPreferenceClientId: (state) => {
return parseInt(state.preference['#AD_Client_ID'], 10)
},
getPreferenceOrgId: (state) => {
return parseInt(state.preference['#AD_Org_ID'], 10)
}
}
}
export default preference

File diff suppressed because it is too large Load Diff

View File

@ -1,994 +0,0 @@
import {
runProcess,
requestListProcessesLogs
} from '@/api/ADempiere/process'
import { showNotification } from '@/utils/ADempiere/notification'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils'
import language from '@/lang'
import router from '@/router'
import { getToken } from '@/utils/auth'
const initStateProcessControl = {
inExecution: [], // process not response from server
isVisibleDialog: false,
reportObject: {},
reportList: [],
metadata: {},
process: [], // process to run finish
sessionProcess: [],
notificationProcess: [],
inRequestMetadata: [],
reportViewList: [],
totalResponse: 0,
totalRequest: 0,
totalSelection: 0,
errorSelection: 0,
successSelection: 0
}
const processControl = {
state: initStateProcessControl,
mutations: {
// Add process in execution
addInExecution(state, payload) {
state.inExecution.push(payload)
},
// Add process in notifation
addNotificationProcess(state, payload) {
state.notificationProcess.push(payload)
},
// Delete process in execution afther some response from server
deleteInExecution(state, payload) {
state.inExecution = state.inExecution.filter(item => item.containerUuid !== payload.containerUuid)
},
// Add process in request metadata from server
addInRequestMetadata(state, payload) {
state.inRequestMetadata.push(payload)
},
// Delete process in request metadata
deleteInRequestMetadata(state, payload) {
state.inRequestMetadata = state.inRequestMetadata.filter(item => item !== payload)
},
addStartedProcess(state, payload) {
state.process.push(payload)
},
resetStateProcessControl(state) {
state = initStateProcessControl
},
/**
*
* @param {object} state
* @param {boolean} payload, true or false value to change displayed dialog
*/
setShowDialog(state, payload) {
state.isVisibleDialog = payload
},
setMetadata(state, payload) {
state.metadata = payload
},
setReportValues(state, payload) {
state.reportObject = payload
if (state.reportList.some(report => report.instanceUuid === payload.instanceUuid)) {
const reportIndex = state.reportList.findIndex(report => report.instanceUuid === payload.instanceUuid)
state.reportList.splice(reportIndex, 1, payload)
} else {
state.reportList.push(payload)
}
},
setSessionProcess(state, payload) {
state.sessionProcess = payload.processList
},
changeFormatReport(state, payload) {
state.reportFormat = payload
},
setReportViewsList(state, payload) {
state.reportViewList.push(payload)
},
setTotalResponse(state, payload) {
state.totalResponse = payload
},
setTotalSelection(state, payload) {
state.totalSelection = payload
},
setSuccessSelection(state, payload) {
state.successSelection = payload
},
setErrorSelection(state, payload) {
state.errorSelection = payload
},
setTotalRequest(state, payload) {
state.totalRequest = payload
}
},
actions: {
// Supported Actions for it
startProcess({ commit, state, dispatch, getters, rootGetters }, {
parentUuid,
containerUuid,
panelType,
action,
parametersList,
reportFormat,
isProcessTableSelection,
isActionDocument,
tableNameUuidSelection,
recordUuidSelection,
menuParentUuid,
routeToDelete
}) {
return new Promise((resolve, reject) => {
// TODO: Add support to evaluate parameters list to send
// const samePocessInExecution = getters.getInExecution(containerUuid)
// exists some call to executed process with container uuid
// if (samePocessInExecution && !isProcessTableSelection) {
// return reject({
// error: 0,
// message: `In this process (${samePocessInExecution.name}) there is already an execution in progress.`
// })
// }
// additional attributes to send server, selection to browser, or table name and record id to window
let selection = []
let allData = {}
let tab, tableName, recordId
if (panelType) {
if (panelType === 'browser') {
allData = getters.getDataRecordAndSelection(containerUuid)
selection = rootGetters.getSelectionToServer({
containerUuid,
selection: allData.selection
})
if (selection.length < 1) {
showNotification({
title: language.t('data.selectionRequired'),
type: 'warning'
})
return reject({
error: 0,
message: `Required selection data record to run this process (${action.name})`
})
}
} else if (panelType === 'window') {
const contextMenu = getters.getRecordUuidMenu
tab = rootGetters.getTab(parentUuid, containerUuid)
if (isProcessTableSelection) {
tableName = tableNameUuidSelection
recordId = recordUuidSelection
} else {
if (contextMenu.processTable) {
tableName = contextMenu.tableName
recordId = contextMenu.valueRecord
} else {
tableName = tab.tableName
const field = rootGetters.getFieldFromColumnName({
containerUuid,
columnName: `${tableName}_ID`
})
recordId = field.value
}
}
}
}
// get info metadata process
const processDefinition = !isEmptyValue(isActionDocument) ? action : rootGetters.getProcess(action.uuid)
let reportType = reportFormat
const finalParameters = rootGetters.getParametersToServer({ containerUuid: processDefinition.uuid })
const isSession = !isEmptyValue(getToken())
let procesingMessage = {
close: () => false
}
if (isSession) {
procesingMessage = showNotification({
title: language.t('notifications.processing'),
message: processDefinition.name,
summary: processDefinition.description,
type: 'info'
})
}
const timeInitialized = (new Date()).getTime()
let processResult = {
// panel attributes from where it was executed
parentUuid,
containerUuid,
panelType,
lastRun: timeInitialized,
parametersList,
logs: [],
isError: false,
isProcessing: true,
summary: '',
resultTableName: '',
output: {
uuid: '',
name: '',
description: '',
fileName: '',
output: '',
outputStream: '',
reportType: ''
}
}
if (!isEmptyValue(isActionDocument)) {
processResult = {
...processResult,
processUuid: action.uuid,
processId: action.id,
processName: 'Procesar Orden',
parameters: parametersList
}
} else {
// Run process on server and wait for it for notify
// uuid of process
processResult = {
...processResult,
menuParentUuid,
processIdPath: routeToDelete.path,
printFormatUuid: action.printFormatUuid,
// process attributes
action: processDefinition.name,
name: processDefinition.name,
description: processDefinition.description,
instanceUuid: '',
processUuid: processDefinition.uuid,
processId: processDefinition.id,
processName: processDefinition.processName,
parameters: finalParameters,
isReport: processDefinition.isReport
}
}
commit('addInExecution', processResult)
if (panelType === 'window') {
reportType = 'pdf'
} else if (panelType === 'browser') {
if (allData.record.length <= 100) {
// close view if is browser.
router.push({ path: '/dashboard' })
dispatch('tagsView/delView', routeToDelete)
// delete data associate to browser
dispatch('deleteRecordContainer', {
viewUuid: containerUuid
})
}
} else {
// close view if is process, report.
router.push({ path: '/dashboard' })
dispatch('tagsView/delView', routeToDelete)
// reset panel and set defalt isShowedFromUser
if (!processDefinition.isReport) {
dispatch('resetPanelToNew', {
containerUuid,
panelType
})
}
}
if (isProcessTableSelection) {
const windowSelectionProcess = getters.getProcessSelect
windowSelectionProcess.selection.forEach(selection => {
Object.assign(processResult, {
selection: selection.UUID,
record: selection[windowSelectionProcess.tableName]
})
const countRequest = state.totalRequest + 1
commit('setTotalRequest', countRequest)
if (!windowSelectionProcess.finish) {
runProcess({
uuid: processDefinition.uuid,
id: processDefinition.id,
reportType,
parametersList: isEmptyValue(finalParameters) ? parametersList : finalParameters,
selectionsList: selection,
tableName: windowSelectionProcess.tableName,
recordId: selection[windowSelectionProcess.tableName]
})
.then(runProcessResponse => {
const { instanceUuid, output } = runProcessResponse
let logList = []
if (runProcessResponse.logsList) {
logList = runProcessResponse.logsList
}
let link = {
href: undefined,
download: undefined
}
if (processDefinition.isReport) {
const blob = new Blob(
[output.outputStream],
{ type: output.mimeType }
)
link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = output.fileName
if (reportType !== 'pdf' && reportType !== 'html') {
link.click()
}
// Report views List to context menu
const reportViewList = {
name: language.t('views.reportView'),
type: 'summary',
action: '',
childs: [],
option: 'reportView'
}
reportViewList.childs = getters.getReportViewList(processResult.processUuid)
if (reportViewList && isEmptyValue(reportViewList.childs)) {
dispatch('requestReportViews', {
processUuid: processResult.processUuid,
instanceUuid,
processId: processDefinition.id,
tableName: output.tableName,
printFormatUuid: output.printFormatUuid,
reportViewUuid: output.reportViewUuid // TODO: Change to uuid
})
.then(responseReportView => {
reportViewList.childs = responseReportView
if (reportViewList.childs.length) {
// Get contextMenu metadata and concat print report views with contextMenu actions
const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid)
contextMenuMetadata.actions.push(reportViewList)
}
})
}
// Print formats to context menu
const printFormatList = {
name: language.t('views.printFormat'),
type: 'summary',
action: '',
childs: [],
option: 'printFormat'
}
printFormatList.childs = rootGetters.getPrintFormatList(processResult.processUuid)
if (printFormatList && isEmptyValue(printFormatList.childs.length)) {
dispatch('requestPrintFormats', {
processUuid: processResult.processUuid,
instanceUuid,
processId: processDefinition.id,
tableName: output.tableName,
printFormatUuid: output.printFormatUuid,
reportViewUuid: output.reportViewUuid
})
.then(printFormarResponse => {
printFormatList.childs = printFormarResponse
if (printFormatList.childs.length) {
// Get contextMenu metadata and concat print Format List with contextMenu actions
const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid)
contextMenuMetadata.actions.push(printFormatList)
}
})
}
// Drill Tables to context menu
const drillTablesList = {
name: language.t('views.drillTable'),
type: 'summary',
action: '',
childs: [],
option: 'drillTable'
}
if (!isEmptyValue(output.tableName)) {
drillTablesList.childs = rootGetters.getDrillTablesList(processResult.processUuid)
if (drillTablesList && isEmptyValue(drillTablesList.childs)) {
dispatch('requestDrillTables', {
processUuid: processResult.processUuid,
instanceUuid,
processId: processDefinition.id,
tableName: output.tableName,
printFormatUuid: output.printFormatUuid,
reportViewUuid: output.reportViewUuid
})
.then(drillTablesResponse => {
drillTablesList.childs = drillTablesResponse
if (drillTablesList.childs.length) {
// Get contextMenu metadata and concat drill tables list with contextMenu actions
const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid)
contextMenuMetadata.actions.push(drillTablesList)
}
})
}
}
}
// assign new attributes
Object.assign(processResult, {
...runProcessResponse,
url: link.href,
download: link.download,
logs: logList,
output
})
if (!isEmptyValue(processResult.output)) {
dispatch('setReportTypeToShareLink', processResult.output.reportType)
}
commit('addNotificationProcess', processResult)
resolve(processResult)
})
.catch(error => {
Object.assign(processResult, {
isError: true,
message: error.message,
isProcessing: false
})
console.warn(`Error running the process ${error}`)
reject(error)
})
.finally(() => {
if (processResult.isError) {
const countError = state.errorSelection + 1
commit('setErrorSelection', countError)
} else {
const countSuccess = state.successSelection + 1
commit('setSuccessSelection', countSuccess)
}
const countResponse = state.totalResponse + 1
commit('setTotalResponse', countResponse)
if (state.totalResponse === state.totalRequest) {
if (isSession) {
showNotification({
title: language.t('notifications.succesful'),
message: language.t('notifications.totalProcess') + countResponse + language.t('notifications.error') + state.errorSelection + language.t('notifications.succesful') + state.successSelection + language.t('notifications.processExecuted'),
type: 'success'
})
}
commit('setTotalRequest', 0)
commit('setTotalResponse', 0)
commit('setSuccessSelection', 0)
commit('setErrorSelection', 0)
}
dispatch('setProcessSelect', {
selection: 0,
finish: true,
tableName: ''
})
commit('addNotificationProcess', processResult)
commit('addStartedProcess', processResult)
commit('deleteInExecution', {
containerUuid
})
})
}
})
} else {
runProcess({
uuid: processDefinition.uuid,
id: processDefinition.id,
reportType,
parametersList: isEmptyValue(finalParameters) ? parametersList : finalParameters,
selectionsList: selection,
tableName,
recordId
})
.then(runProcessResponse => {
const { instanceUuid, output } = runProcessResponse
let logList = []
if (!isEmptyValue(runProcessResponse.logsList)) {
logList = runProcessResponse.logsList
}
let link = {
href: undefined,
download: undefined
}
if (runProcessResponse.isReport || processDefinition.isReport) {
const blob = new Blob(
[output.outputStream],
{ type: output.mimeType }
)
link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = output.fileName
if (reportType !== 'pdf' && reportType !== 'html') {
link.click()
}
const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid)
// Report views List to context menu
const reportViewList = {
name: language.t('views.reportView'),
type: 'summary',
action: '',
childs: [],
option: 'reportView'
}
reportViewList.childs = getters.getReportViewList(processResult.processUuid)
if (reportViewList && !reportViewList.childs.length) {
dispatch('requestReportViews', {
processUuid: processResult.processUuid,
instanceUuid,
processId: processDefinition.id,
tableName: output.tableName,
printFormatUuid: output.printFormatUuid,
reportViewUuid: output.reportViewUuid
})
.then(responseReportView => {
reportViewList.childs = responseReportView
if (reportViewList.childs.length) {
// Get contextMenu metadata and concat print report views with contextMenu actions
contextMenuMetadata.actions.push(reportViewList)
}
})
}
// Print formats to context menu
const printFormatList = {
name: language.t('views.printFormat'),
type: 'summary',
action: '',
childs: [],
option: 'printFormat'
}
printFormatList.childs = rootGetters.getPrintFormatList(processResult.processUuid)
if (printFormatList && !printFormatList.childs.length) {
dispatch('requestPrintFormats', {
processUuid: processResult.processUuid,
instanceUuid,
processId: processDefinition.id,
tableName: output.tableName,
printFormatUuid: output.printFormatUuid,
reportViewUuid: output.reportViewUuid
})
.then(printFormarResponse => {
printFormatList.childs = printFormarResponse
if (printFormatList.childs.length) {
// Get contextMenu metadata and concat print Format List with contextMenu actions
contextMenuMetadata.actions.push(printFormatList)
}
})
} else {
const index = contextMenuMetadata.actions.findIndex(action => action.option === 'printFormat')
if (index !== -1) {
contextMenuMetadata.actions[index] = printFormatList
}
}
// Drill Tables to context menu
const drillTablesList = {
name: language.t('views.drillTable'),
type: 'summary',
action: '',
childs: [],
option: 'drillTable'
}
if (!isEmptyValue(output.tableName)) {
drillTablesList.childs = rootGetters.getDrillTablesList(processResult.processUuid)
if (drillTablesList && isEmptyValue(drillTablesList.childs)) {
dispatch('requestDrillTables', {
processUuid: processResult.processUuid,
instanceUuid,
processId: processDefinition.id,
tableName: output.tableName,
printFormatUuid: output.printFormatUuid,
reportViewUuid: output.reportViewUuid
})
.then(drillTablesResponse => {
drillTablesList.childs = drillTablesResponse
if (drillTablesList.childs.length) {
// Get contextMenu metadata and concat print Format List with contextMenu actions
contextMenuMetadata.actions.push(drillTablesList)
}
})
}
}
}
// assign new attributes
Object.assign(processResult, {
...runProcessResponse,
url: link.href,
download: link.download,
logs: logList,
output
})
resolve(processResult)
if (!isEmptyValue(processResult.output)) {
dispatch('setReportTypeToShareLink', processResult.output.reportType)
}
})
.catch(error => {
Object.assign(processResult, {
isError: true,
message: error.message,
isProcessing: false
})
console.warn(`Error running the process ${error.message}. Code: ${error.code}.`)
reject(error)
})
.finally(() => {
if (!processResult.isError) {
if (panelType === 'window') {
// TODO: Add conditional to indicate when update record
dispatch('updateRecordAfterRunProcess', {
parentUuid,
containerUuid,
tab
})
} else if (panelType === 'browser') {
if (allData.record.length >= 100) {
dispatch('getBrowserSearch', {
containerUuid
})
}
}
}
commit('addNotificationProcess', processResult)
dispatch('finishProcess', {
processOutput: processResult,
procesingMessage,
routeToDelete
})
commit('deleteInExecution', {
containerUuid
})
dispatch('setProcessTable', {
valueRecord: 0,
tableName: '',
processTable: false
})
dispatch('setProcessSelect', {
finish: true
})
})
}
})
},
// Supported to process selection
selectionProcess({ commit, state, dispatch, getters, rootGetters }, {
parentUuid,
containerUuid,
panelType,
action,
isProcessTableSelection,
menuParentUuid,
routeToDelete
}) {
// get info metadata process
const processDefinition = rootGetters.getProcess(action.uuid)
const reportType = 'pdf'
const finalParameters = rootGetters.getParametersToServer({ containerUuid: processDefinition.uuid })
const isSession = !isEmptyValue(getToken())
if (isSession) {
showNotification({
title: language.t('notifications.processing'),
message: processDefinition.name,
summary: processDefinition.description,
type: 'info'
})
}
const timeInitialized = (new Date()).getTime()
// Run process on server and wait for it for notify
if (isProcessTableSelection) {
const windowSelectionProcess = getters.getProcessSelect
windowSelectionProcess.selection.forEach(selection => {
const processResult = {
// panel attributes from where it was executed
parentUuid,
containerUuid,
panelType,
menuParentUuid,
processIdPath: routeToDelete.path,
// process attributes
lastRun: timeInitialized,
action: processDefinition.name,
name: processDefinition.name,
description: processDefinition.description,
instanceUuid: '',
processUuid: processDefinition.uuid,
processId: processDefinition.id,
processName: processDefinition.processName,
parameters: finalParameters,
isError: false,
isProcessing: true,
isReport: processDefinition.isReport,
summary: '',
resultTableName: '',
logs: [],
selection: selection.UUID,
record: selection[windowSelectionProcess.tableName],
output: {
uuid: '',
name: '',
description: '',
fileName: '',
output: '',
outputStream: '',
reportType: ''
}
}
const countRequest = state.totalRequest + 1
commit('addInExecution', processResult)
commit('setTotalRequest', countRequest)
if (!windowSelectionProcess.finish) {
return runProcess({
uuid: processDefinition.uuid,
id: processDefinition.id,
reportType,
parametersList: finalParameters,
selectionsList: selection,
tableName: windowSelectionProcess.tableName,
recordId: selection[windowSelectionProcess.tableName]
})
.then(response => {
let output = {
uuid: '',
name: '',
description: '',
fileName: '',
mimeType: '',
output: '',
outputStream: '',
reportType: ''
}
if (isEmptyValue(response.output)) {
const responseOutput = response.output
output = {
uuid: responseOutput.uuid,
name: responseOutput.name,
description: responseOutput.description,
fileName: responseOutput.filename,
mimeType: responseOutput.mimeType,
output: responseOutput.output,
outputStream: responseOutput.outputstream,
reportType: responseOutput.reporttype
}
}
let logList = []
if (response.getLogsList) {
logList = response.getLogsList.map(itemLog => {
return {
log: itemLog.log,
recordId: itemLog.recordid
}
})
}
// assign new attributes
Object.assign(processResult, {
instanceUuid: response.instanceUuid,
isError: response.isError,
isProcessing: response.isProcessing,
summary: response.summary,
ResultTableName: response.resulttablename,
lastRun: response.lastRun,
logs: logList,
output
})
dispatch('setReportTypeToShareLink', processResult.output.reportType)
if (processResult.isError) {
const countError = state.errorSelection + 1
commit('setErrorSelection', countError)
} else {
const countSuccess = state.successSelection + 1
commit('setSuccessSelection', countSuccess)
}
const countResponse = state.totalResponse + 1
commit('setTotalResponse', countResponse)
if (state.totalResponse === state.totalRequest) {
if (isSession) {
showNotification({
title: language.t('notifications.succesful'),
message: language.t('notifications.totalProcess') + countResponse + language.t('notifications.error') + state.errorSelection + language.t('notifications.succesful') + state.successSelection + language.t('notifications.processExecuted'),
type: 'success'
})
}
commit('setTotalRequest', 0)
commit('setTotalResponse', 0)
commit('setSuccessSelection', 0)
commit('setErrorSelection', 0)
}
dispatch('setProcessSelect', {
selection: 0,
finish: true,
tableName: ''
})
commit('addNotificationProcess', processResult)
commit('addStartedProcess', processResult)
commit('deleteInExecution', {
containerUuid
})
})
.catch(error => {
Object.assign(processResult, {
isError: true,
message: error.message,
isProcessing: false
})
console.warn(`Error running the process. Code ${error.code}: ${error.message}.`)
})
}
})
}
},
/**
* TODO: Add date time in which the process/report was executed
*/
getSessionProcessFromServer({ commit, dispatch, getters, rootGetters }, parameters) {
// process Activity
const { pageToken, pageSize } = parameters
return requestListProcessesLogs({ pageToken, pageSize })
.then(processActivityResponse => {
const responseList = processActivityResponse.processLogsList.map(processLogItem => {
const processMetadata = rootGetters.getProcess(processLogItem.uuid)
// if no exists metadata process in store and no request progess
if (processMetadata === undefined && getters.getInRequestMetadata(processLogItem.uuid) === undefined) {
commit('addInRequestMetadata', processLogItem.uuid)
dispatch('getProcessFromServer', {
containerUuid: processLogItem.uuid
})
.finally(() => {
commit('deleteInRequestMetadata', processLogItem.uuid)
})
}
const process = {
...processLogItem,
processUuid: processLogItem.uuid
}
return process
})
const processResponseList = {
recordCount: processActivityResponse.recordCount,
processList: responseList,
nextPageToken: processActivityResponse.nextPageToken
}
commit('setSessionProcess', processResponseList)
return processResponseList
})
.catch(error => {
showNotification({
title: language.t('notifications.error'),
message: error.message,
type: 'error'
})
console.warn(`Error getting process activity: ${error.message}. Code: ${error.code}.`)
})
},
/**
* Show modal dialog with process/report, tab (sequence) metadata
* @param {String} type of panel or panelType ('process', 'report', 'window')
* @param {Object} action
*/
setShowDialog({ state, commit, dispatch, rootGetters }, {
type,
action
}) {
const panels = ['process', 'report', 'window']
if (action && (panels.includes(type) || panels.includes(action.panelType))) {
// show some process loaded in store
if (state.metadata && !isEmptyValue(state.metadata.containerUuid) &&
state.metadata.containerUuid === action.containerUuid) {
commit('setShowDialog', true)
return
}
const panel = rootGetters.getPanel(action.containerUuid)
if (panel === undefined) {
dispatch('getPanelAndFields', {
parentUuid: action.parentUuid,
containerUuid: isEmptyValue(action.uuid) ? action.containerUuid : action.uuid,
panelType: action.panelType
})
.then(response => {
commit('setMetadata', response)
commit('setShowDialog', true)
})
} else {
commit('setMetadata', panel)
commit('setShowDialog', true)
}
return
}
commit('setShowDialog', false)
},
finishProcess({ commit }, {
processOutput,
routeToDelete,
procesingMessage
}) {
const processMessage = {
name: processOutput.processName,
title: language.t('notifications.succesful'),
message: language.t('notifications.processExecuted'),
type: 'success',
logs: processOutput.logs,
summary: processOutput.summary
}
const errorMessage = !isEmptyValue(processOutput.message) ? processOutput.message : language.t('notifications.error')
// TODO: Add isReport to type always 'success'
if (processOutput.isError || isEmptyValue(processOutput.processId) || isEmptyValue(processOutput.instanceUuid)) {
processMessage.title = language.t('notifications.error')
processMessage.message = errorMessage
processMessage.type = 'error'
processOutput.isError = true
}
if (processOutput.isReport && !processOutput.isError) {
// open report viewer with report response
let menuParentUuid = routeToDelete.params.menuParentUuid
if (isEmptyValue(menuParentUuid)) {
menuParentUuid = processOutput.menuParentUuid
}
let tableName
if (processOutput.option && !isEmptyValue(processOutput.option)) {
if (processOutput.option === 'drillTable') {
tableName = processOutput.tableName
}
}
router.push({
name: 'Report Viewer',
params: {
processId: processOutput.processId,
instanceUuid: processOutput.instanceUuid,
fileName: isEmptyValue(processOutput.output.fileName) ? processOutput.fileName : processOutput.output.fileName,
menuParentUuid,
tableName
}
})
}
const isSession = !isEmptyValue(getToken())
if (isSession) {
showNotification(processMessage)
}
if (!isEmptyValue(procesingMessage)) {
procesingMessage.close()
}
commit('addStartedProcess', processOutput)
commit('setReportValues', processOutput)
},
changeFormatReport({ commit }, reportFormat) {
if (!isEmptyValue(reportFormat)) {
commit('changeFormatReport', reportFormat)
}
}
},
getters: {
/**
* Running processes that have not received a response from the server
* @param {string} containerUuid
*/
getInExecution: (state) => (containerUuid) => {
return state.inExecution.find(item => item.containerUuid === containerUuid)
},
/**
* Process for send to server, or send without response
*/
getAllInExecution: (state) => {
return state.inExecution
},
/**
* Process send to server, with response from server
*/
getAllFinishProcess: (state) => {
return state.process
},
getNotificationProcess: (state) => {
return state.notificationProcess
},
/**
* Process receibed from server associated whith this session
*/
getAllSessionProcess: (state) => {
return state.sessionProcess
},
/**
* Process request metadata from server filter form uuid process
*/
getInRequestMetadata: (state) => (containerUuid) => {
return state.inRequestMetadata.find(item => item === containerUuid)
},
getProcessResult: (state) => {
return state.reportObject
},
getCachedReport: (state) => (instanceUuid) => {
return state.reportList.find(
item => item.instanceUuid === instanceUuid
)
}
}
}
export default processControl

View File

@ -0,0 +1,112 @@
import { getProcess as getProcessMetadata } from '@/api/ADempiere'
import { showMessage } from '@/utils/ADempiere'
import { generateProcess } from '@/utils/ADempiere/dictionaryUtils'
import language from '@/lang'
import router from '@/router'
const process = {
state: {
process: []
},
mutations: {
addProcess(state, payload) {
state.process.push(payload)
},
dictionaryResetCacheProcess(state) {
state.process = []
}
},
actions: {
/**
* Get Process/Report metadata from server
* @param {string} containerUuid
* @param {number} processId
* @param {object} routeToDelete, route to close in tagView when fail
*/
getProcessFromServer({ commit, dispatch }, {
containerUuid,
processId,
routeToDelete
}) {
return new Promise(resolve => {
getProcessMetadata({
uuid: containerUuid,
id: processId
})
.then(async responseProcess => {
let printFormatsAvailable = []
if (responseProcess.isReport) {
printFormatsAvailable = await dispatch('requestPrintFormats', {
processUuid: containerUuid
})
}
const { processDefinition, actions } = generateProcess({
processToGenerate: {
...responseProcess,
printFormatsAvailable
}
})
dispatch('addPanel', processDefinition)
commit('addProcess', processDefinition)
resolve(processDefinition)
// Add process menu
dispatch('setContextMenu', {
containerUuid,
actions
})
})
.catch(error => {
router.push({
path: '/dashboard'
})
dispatch('tagsView/delView', routeToDelete)
showMessage({
message: language.t('login.unexpectedError'),
type: 'error'
})
console.warn(`Dictionary Process - Error ${error.message}.`)
})
})
},
/**
* Add process associated in window or smart browser
* @param {object} processToGenerate
*/
addProcessAssociated({ commit, dispatch }, {
processToGenerate
}) {
return new Promise(resolve => {
const { processDefinition, actions } = generateProcess({
processToGenerate
})
dispatch('addPanel', processDefinition)
commit('addProcess', processDefinition)
resolve(processDefinition)
// Add process menu
dispatch('setContextMenu', {
containerUuid: processDefinition.uuid,
actions
})
})
}
},
getters: {
getProcess: (state) => (processUuid) => {
return state.process.find(
item => item.uuid === processUuid
)
},
getProcessById: (state) => (processId) => {
return state.process.find(
item => item.id === parseInt(processId)
)
}
}
}
export default process

View File

@ -33,6 +33,13 @@ const reportControl = {
}
},
actions: {
reportActionPerformed({ commit }, {
containerUuid,
field,
value
}) {
},
requestPrintFormats({ commit }, {
processId,
processUuid,
@ -147,7 +154,9 @@ const reportControl = {
if (isEmptyValue(printFormatUuid)) {
printFormatUuid = getters.getDefaultPrintFormat(processUuid).printFormatUuid
}
const parametersList = rootGetters.getParametersToServer({ containerUuid: processUuid })
const parametersList = rootGetters.getParametersToServer({
containerUuid: processUuid
})
getReportOutput({
parametersList,
printFormatUuid,

File diff suppressed because it is too large Load Diff

View File

@ -1,935 +0,0 @@
import { createEntity, updateEntity, deleteEntity, rollbackEntity } from '@/api/ADempiere/persistence'
import { getReferencesList } from '@/api/ADempiere/values'
import { convertObjectToArrayPairs, isEmptyValue } from '@/utils/ADempiere/valueUtils'
import { parseContext } from '@/utils/ADempiere/contextUtils'
import { showMessage } from '@/utils/ADempiere/notification'
import language from '@/lang'
import router from '@/router'
const initStateWindowControl = {
inCreate: [],
references: [],
windowOldRoute: {
path: '',
fullPath: '',
query: {}
},
dataLog: {}, // { containerUuid, recordId, tableName, eventType }
tabSequenceRecord: [],
totalResponse: 0,
totalRequest: 0
}
const windowControl = {
state: initStateWindowControl,
mutations: {
addInCreate(state, payload) {
state.inCreate.push(payload)
},
deleteInCreate(state, payload) {
state.inCreate = state.inCreate.filter(item => item.containerUuid !== payload.containerUuid)
},
addReferencesList(state, payload) {
state.references.push(payload)
},
setDataLog(state, payload) {
state.dataLog = payload
},
setWindowOldRoute(state, payload) {
state.windowOldRoute = payload
},
setTabSequenceRecord(state, payload) {
state.tabSequenceRecord = payload
},
setTotalResponse(state, payload) {
state.totalResponse = payload
},
setTotalRequest(state, payload) {
state.totalRequest = payload
},
resetStateWindowControl(state) {
state = initStateWindowControl
}
},
actions: {
undoPanelToNew({ dispatch, rootGetters }, { containerUuid }) {
const oldAttributes = rootGetters.getColumnNamesAndValues({
containerUuid,
propertyName: 'oldValue',
isObjectReturn: true,
isAddDisplayColumn: true
})
dispatch('notifyPanelChange', {
containerUuid,
newValues: oldAttributes
})
},
createNewEntity({ commit, dispatch, getters, rootGetters }, {
parentUuid,
containerUuid
}) {
return new Promise((resolve, reject) => {
// exists some call to create new record with container uuid
if (getters.getInCreate(containerUuid)) {
return reject({
error: 0,
message: `In this panel (${containerUuid}) is a create new record in progress`
})
}
const { tableName, fieldList } = rootGetters.getPanel(containerUuid)
// delete key from attributes
const attributesList = rootGetters.getColumnNamesAndValues({
containerUuid,
propertyName: 'value',
isEvaluateValues: true,
isAddDisplayColumn: false
})
commit('addInCreate', {
containerUuid,
tableName,
attributesList
})
createEntity({
tableName,
attributesList
})
.then(createEntityResponse => {
const newValues = createEntityResponse.values
attributesList.forEach(element => {
if (element.columnName.includes('DisplayColumn')) {
newValues[element.columnName] = element.value
}
})
showMessage({
message: language.t('data.createRecordSuccessful'),
type: 'success'
})
// update fields with new values
dispatch('notifyPanelChange', {
parentUuid,
containerUuid,
newValues,
isSendToServer: false
})
dispatch('addNewRow', {
parentUuid,
containerUuid,
isPanelValues: true,
isEdit: false
})
// set data log to undo action
const fieldId = fieldList.find(itemField => itemField.isKey)
dispatch('setDataLog', {
containerUuid,
tableName,
recordId: fieldId.value, // TODO: Verify performance with tableName_ID
recordUuid: newValues.UUID,
eventType: 'INSERT'
})
const oldRoute = router.app._route
router.push({
name: oldRoute.name,
params: {
...oldRoute.params
},
query: {
...oldRoute.query,
action: createEntityResponse.uuid
}
})
dispatch('tagsView/delView', oldRoute, true)
resolve({
data: newValues,
recordUuid: createEntityResponse.uuid,
recordId: createEntityResponse.id,
tableName: createEntityResponse.tableName
})
})
.catch(error => {
showMessage({
message: error.message,
type: 'error'
})
console.warn(`Create Entity error: ${error.message}.`)
reject(error)
})
.finally(() => {
commit('deleteInCreate', {
containerUuid,
tableName,
attributesList
})
})
})
},
createEntityFromTable({ commit, dispatch, getters, rootGetters }, {
parentUuid,
containerUuid,
row
}) {
// exists some call to create new record with container uuid
if (getters.getInCreate(containerUuid)) {
return {
error: 0,
message: `In this panel (${containerUuid}) is a create new record in progress.`
}
}
const { tableName, isParentTab } = rootGetters.getPanel(containerUuid)
// TODO: Add support to Binary columns (BinaryData)
const columnsToDontSend = ['BinaryData', 'isEdit', 'isNew', 'isSendServer']
// TODO: Evaluate peformance without filter using delete(prop) before convert object to array
// attributes or fields
const fieldsList = getters.getFieldsListFromPanel(containerUuid)
const attributesList = []
fieldsList.forEach(itemAttribute => {
if (columnsToDontSend.includes(itemAttribute.columnName) || itemAttribute.columnName.includes('DisplayColumn')) {
return false
}
if (isEmptyValue(row[itemAttribute.columnName])) {
return false
}
attributesList.push({
value: row[itemAttribute.columnName],
columnName: itemAttribute.columnName,
valueType: itemAttribute.valueType
})
})
commit('addInCreate', {
containerUuid,
tableName,
attributesList
})
let isError = false
return createEntity({
tableName,
attributesList
})
.then(createEntityResponse => {
showMessage({
message: language.t('data.createRecordSuccessful'),
type: 'success'
})
if (isParentTab) {
// redirect to create new record
const oldRoute = router.app._route
router.push({
name: oldRoute.name,
params: {
...oldRoute.params
},
query: {
...oldRoute.query,
action: createEntityResponse.recordUuid
}
})
}
return {
data: createEntityResponse.values,
...createEntityResponse
}
})
.catch(error => {
showMessage({
message: error.message,
type: 'error'
})
console.warn(`Create Entity Table Error ${error.code}: ${error.message}.`)
isError = true
})
.finally(() => {
if (isError) {
dispatch('addNewRow', {
containerUuid,
row
})
} else {
// refresh record list
dispatch('getDataListTab', {
parentUuid,
containerUuid
})
.catch(error => {
console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`)
})
}
commit('deleteInCreate', {
containerUuid,
tableName,
attributesList
})
})
},
updateCurrentEntity({ dispatch, rootGetters }, {
containerUuid,
recordUuid = null
}) {
const panel = rootGetters.getPanel(containerUuid)
if (!recordUuid) {
recordUuid = rootGetters.getUuid(containerUuid)
}
// TODO: Add support to Binary columns (BinaryData)
const columnsToDontSend = ['Account_Acct']
// attributes or fields
let finalAttributes = rootGetters.getColumnNamesAndValues({
containerUuid: containerUuid,
isEvaluatedChangedValue: true
})
finalAttributes = finalAttributes.filter(itemAttribute => {
if (columnsToDontSend.includes(itemAttribute.columnName) || itemAttribute.columnName.includes('DisplayColumn')) {
return false
}
const field = panel.fieldList.find(itemField => itemField.columnName === itemAttribute.columnName)
if (!field || !field.isUpdateable || !field.isDisplayed) {
return false
}
return true
})
return updateEntity({
tableName: panel.tableName,
recordUuid,
attributesList: finalAttributes
})
.then(updateEntityResponse => {
const newValues = updateEntityResponse.values
// set data log to undo action
// TODO: Verify performance with tableName_ID
let recordId = updateEntityResponse.id
if (isEmptyValue(recordId)) {
recordId = newValues[`${panel.tableName}_ID`]
}
if (isEmptyValue(recordId)) {
const fieldId = panel.fieldList.find(itemField => itemField.isKey)
recordId = fieldId.value
}
if (isEmptyValue(recordUuid)) {
recordUuid = updateEntityResponse.uuid
}
if (isEmptyValue(recordUuid)) {
recordUuid = newValues.UUID
}
dispatch('setDataLog', {
containerUuid,
tableName: panel.tableName,
recordId,
recordUuid,
eventType: 'UPDATE'
})
if (rootGetters.getShowContainerInfo) {
dispatch('listRecordLogs', {
tableName: panel.tableName,
recordId
})
}
return newValues
})
.catch(error => {
showMessage({
message: error.message,
type: 'error'
})
console.warn(`Update Entity Error ${error.code}: ${error.message}`)
})
},
updateCurrentEntityFromTable({ rootGetters }, {
containerUuid,
row
}) {
const { tableName, fieldList } = rootGetters.getPanel(containerUuid)
// TODO: Add support to Binary columns (BinaryData)
const columnsToDontSend = ['BinaryData', 'isEdit', 'isNew', 'isSendServer']
// TODO: Evaluate peformance without filter using delete(prop) before convert object to array
// attributes or fields
let finalAttributes = convertObjectToArrayPairs(row)
finalAttributes = finalAttributes.filter(itemAttribute => {
if (columnsToDontSend.includes(itemAttribute.columnName) || itemAttribute.columnName.includes('DisplayColumn')) {
return false
}
const field = fieldList.find(itemField => itemField.columnName === itemAttribute.columnName)
if (!field || !field.isUpdateable || !field.isDisplayed) {
return false
}
return true
})
return updateEntity({
tableName,
recordUuid: row.UUID,
attributesList: finalAttributes
})
.then(response => {
return response
})
.catch(error => {
showMessage({
message: error.message,
type: 'error'
})
console.warn(`Update Entity Table Error ${error.code}: ${error.message}.`)
})
},
/**
* Update record after run process associated with window
* @param {string} parentUuid
* @param {string} containerUuid
* @param {object} tab
*/
updateRecordAfterRunProcess({ dispatch, rootGetters }, {
parentUuid,
containerUuid,
tab
}) {
const recordUuid = rootGetters.getUuid(containerUuid)
// get new values
dispatch('getEntity', {
parentUuid,
containerUuid,
tableName: tab.tableName,
recordUuid
})
.then(response => {
// update panel
if (tab.isParentTab) {
dispatch('notifyPanelChange', {
parentUuid,
containerUuid,
newValues: response,
isSendCallout: false,
isSendToServer: false
})
}
// update row in table
dispatch('notifyRowTableChange', {
parentUuid,
containerUuid,
row: response,
isEdit: false
})
})
},
deleteEntity({ dispatch, rootGetters }, {
parentUuid,
containerUuid,
recordUuid,
recordId,
row
}) {
return new Promise(resolve => {
const panel = rootGetters.getPanel(containerUuid)
if (!isEmptyValue(row)) {
recordUuid = row.UUID
recordId = row[`${panel.tableName}_ID`]
}
deleteEntity({
tableName: panel.tableName,
recordUuid,
recordId
})
.then(responseDeleteEntity => {
// refresh record list
dispatch('getDataListTab', {
parentUuid,
containerUuid
})
.then(responseDataList => {
if (panel.isParentTab) {
// if response is void, go to new record
if (responseDataList.length <= 0) {
dispatch('resetPanelToNew', {
parentUuid,
containerUuid,
panelType: 'window',
isNewRecord: true
})
} else {
const oldRoute = router.app._route
// else display first record of table in panel
router.push({
name: oldRoute.name,
params: {
...oldRoute.params
},
query: {
...oldRoute.query,
action: responseDataList[0].UUID
}
})
}
}
})
.catch(error => {
console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`)
})
showMessage({
message: language.t('data.deleteRecordSuccessful'),
type: 'success'
})
if (isEmptyValue(recordId)) {
// TODO: Verify performance with tableName_ID
const fieldId = panel.fieldList.find(itemField => itemField.isKey)
recordId = fieldId.value
}
// set data log to undo action
dispatch('setDataLog', {
containerUuid,
tableName: panel.tableName,
recordId,
recordUuid,
eventType: 'DELETE'
})
resolve(responseDeleteEntity)
})
.catch(error => {
showMessage({
message: language.t('data.deleteRecordError'),
type: 'error'
})
console.warn(`Delete Entity - Error ${error.message}, Code: ${error.code}.`)
})
})
},
/**
* Delete selection records in table
* @param {string} parentUuid
* @param {string} containerUuid
* @param {string} tableName
* @param {boolean} isParentTab
*/
deleteSelectionDataList({ dispatch, rootGetters }, {
parentUuid,
containerUuid,
tableName,
isParentTab
}) {
if (isEmptyValue(tableName) || isEmptyValue(isParentTab)) {
const tab = rootGetters.getTab(parentUuid, containerUuid)
tableName = tab.tableName
isParentTab = tab.isParentTab
}
const allData = rootGetters.getDataRecordAndSelection(containerUuid)
let selectionLength = allData.selection.length
allData.selection.forEach((record, index) => {
// validate if the registry row has no uuid before sending to the server
if (isEmptyValue(record.UUID)) {
selectionLength = selectionLength - 1
console.warn(`This row does not contain a record with UUID`, record)
// refresh record list
dispatch('getDataListTab', {
parentUuid,
containerUuid
})
.catch(error => {
console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`)
})
return
}
deleteEntity({
tableName,
recordUuid: record.UUID
})
.then(() => {
if (isParentTab) {
// redirect to create new record
const oldRoute = router.app._route
if (record.UUID === oldRoute.query.action) {
router.push({
name: oldRoute.name,
params: {
...oldRoute.params
},
query: {
...oldRoute.query,
action: 'create-new'
}
})
// clear fields with default values
dispatch('resetPanelToNew', {
parentUuid,
containerUuid
})
// delete view with uuid record delete
dispatch('tagsView/delView', oldRoute, true)
}
}
if ((index + 1) >= selectionLength) {
// refresh record list
dispatch('getDataListTab', {
parentUuid,
containerUuid
})
.catch(error => {
console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`)
})
showMessage({
message: language.t('data.deleteRecordSuccessful'),
type: 'success'
})
}
})
})
},
undoModifyData({ getters }, {
containerUuid,
recordUuid
}) {
return rollbackEntity(getters.getDataLog(containerUuid, recordUuid))
.then(response => {
return response
})
.catch(error => {
showMessage({
message: error.message,
type: 'error'
})
console.warn(`Rollback Entity error: ${error.message}. Code: ${error.code}.`)
})
},
setDataLog({ commit }, {
containerUuid,
tableName,
recordId,
recordUuid,
eventType
}) {
commit('setDataLog', {
containerUuid,
tableName,
recordId,
recordUuid,
eventType
})
},
/**
* Get data to table in tab
* @param {string} parentUuid, window to search record data
* @param {string} containerUuid, tab to search record data
* @param {string} recordUuid, uuid to search
* @param {boolean} isRefreshPanel, if main panel is updated with new response data
* @param {boolean} isLoadAllRecords, if main panel is updated with new response data
*/
getDataListTab({ dispatch, rootGetters }, {
parentUuid,
containerUuid,
recordUuid,
referenceWhereClause = '',
columnName,
value,
criteria,
isAddRecord = false,
isLoadAllRecords = false,
isRefreshPanel = false,
isReference = false,
isShowNotification = true
}) {
const tab = rootGetters.getTab(parentUuid, containerUuid)
let parsedQuery = tab.query
if (!isEmptyValue(parsedQuery) && parsedQuery.includes('@')) {
parsedQuery = parseContext({
parentUuid,
containerUuid,
value: tab.query,
isBooleanToString: true
}).value
}
let parsedWhereClause = tab.whereClause
if (!isEmptyValue(parsedWhereClause) && parsedWhereClause.includes('@')) {
parsedWhereClause = parseContext({
parentUuid,
containerUuid,
value: tab.whereClause,
isBooleanToString: true
}).value
}
if (isReference) {
if (!isEmptyValue(parsedWhereClause)) {
parsedWhereClause += ` AND ${referenceWhereClause}`
} else {
parsedWhereClause += referenceWhereClause
}
}
if (!isEmptyValue(criteria)) {
if (!isEmptyValue(parsedWhereClause)) {
parsedWhereClause += ` AND ${criteria.whereClause}`
} else {
parsedWhereClause += criteria.whereClause
}
}
const conditionsList = []
// TODO: evaluate if overwrite values to conditions
if (!isLoadAllRecords && tab.isParentTab && !isEmptyValue(tab.tableName) && !isEmptyValue(value)) {
conditionsList.push({
columnName,
value
})
}
return dispatch('getObjectListFromCriteria', {
parentUuid,
containerUuid,
tableName: tab.tableName,
query: parsedQuery,
whereClause: parsedWhereClause,
orderByClause: tab.orderByClause,
conditionsList,
isParentTab: tab.isParentTab,
isAddRecord,
isShowNotification
})
.then(response => {
if (isRefreshPanel && !isEmptyValue(recordUuid) && recordUuid !== 'create-new') {
const newValues = response.find(itemData => itemData.UUID === recordUuid)
if (newValues) {
// update fields with values obtained from the server
dispatch('notifyPanelChange', {
parentUuid,
containerUuid,
newValues,
isSendCallout: false,
isSendToServer: false
})
} else {
// this record is missing (Deleted or the query does not include it)
dispatch('resetPanelToNew', {
parentUuid,
containerUuid
})
}
}
return response
})
.catch(error => {
return error
})
.finally(() => {
const currentData = rootGetters.getDataRecordAndSelection(containerUuid)
const { originalNextPageToken, pageNumber, recordCount } = currentData
let nextPage = pageNumber
const isAdd = isAddRecord
if (originalNextPageToken && isAddRecord) {
const pageInToken = originalNextPageToken.substring(originalNextPageToken.length - 2)
if (pageInToken === '-1') {
isAddRecord = false
}
if (pageNumber === 1 && recordCount > 50) {
nextPage = nextPage + 1
isAddRecord = true
}
} else {
isAddRecord = false
}
if (recordCount <= 50) {
isAddRecord = false
}
if (isAddRecord) {
dispatch('setPageNumber', {
parentUuid,
containerUuid,
pageNumber: nextPage,
panelType: 'window',
isAddRecord,
isShowNotification: false
})
}
if (isAdd && isAdd !== isAddRecord) {
if (tab.isSortTab) {
const record = rootGetters.getDataRecordsList(containerUuid)
const recordToTab = record
.map(itemRecord => {
return {
...itemRecord
}
})
.sort((itemA, itemB) => {
return itemA[tab.sortOrderColumnName] - itemB[tab.sortOrderColumnName]
})
dispatch('setTabSequenceRecord', recordToTab)
}
}
})
},
/**
* Get references asociate to record
* @param {string} parentUuid as windowUuid
* @param {string} containerUuid
* @param {string} tableName
* @param {string} recordUuid
*/
getReferencesListFromServer({ commit, rootGetters }, {
parentUuid: windowUuid,
containerUuid,
tableName,
recordUuid
}) {
if (isEmptyValue(tableName)) {
tableName = rootGetters.getTab(windowUuid, containerUuid).tableName
}
return new Promise(resolve => {
getReferencesList({
windowUuid,
tableName,
recordUuid
})
.then(referenceResponse => {
const referencesList = referenceResponse.referencesList.map(item => {
return {
...item,
recordUuid,
type: 'reference'
}
})
const references = {
...referenceResponse,
windowUuid,
recordUuid,
referencesList
}
commit('addReferencesList', references)
resolve(referenceResponse)
})
.catch(error => {
console.warn(`References Load Error ${error.code}: ${error.message}.`)
})
})
},
setWindowOldRoute({ commit }, oldPath = { path: '', fullPath: '', query: {}}) {
commit('setWindowOldRoute', oldPath)
},
setTabSequenceRecord({ commit }, record) {
commit('setTabSequenceRecord', record)
},
/**
* Update records in tab sort
* @param {string} containerUuid
* @param {string} parentUuid
*/
updateSequence({ state, commit, dispatch, getters, rootGetters }, {
parentUuid,
containerUuid
}) {
const { tableName, sortOrderColumnName, sortYesNoColumnName, tabAssociatedUuid } = rootGetters.getTab(parentUuid, containerUuid)
const listSequenceToSet = getters.getTabSequenceRecord
const recordData = rootGetters.getDataRecordsList(containerUuid)
// scrolls through the logs and checks if there is a change to be sent to server
recordData.forEach(itemData => {
const dataSequence = listSequenceToSet.find(item => item.UUID === itemData.UUID)
if (itemData[sortOrderColumnName] === dataSequence[sortOrderColumnName]) {
return
}
const valuesToSend = [{
columnName: sortOrderColumnName,
value: dataSequence[sortOrderColumnName]
}]
if (itemData[sortYesNoColumnName] !== dataSequence[sortYesNoColumnName]) {
valuesToSend.push({
columnName: sortYesNoColumnName,
value: dataSequence[sortYesNoColumnName]
})
}
const countRequest = state.totalRequest + 1
commit('setTotalRequest', countRequest)
updateEntity({
tableName,
recordUuid: itemData.UUID,
attributesList: valuesToSend
})
.catch(error => {
showMessage({
message: error.message,
type: 'error'
})
console.warn(`Update Entity Table Error ${error.code}: ${error.message}`)
})
.finally(() => {
const countResponse = state.totalResponse + 1
commit('setTotalResponse', countResponse)
if (state.totalResponse === state.totalRequest) {
showMessage({
message: language.t('notifications.updateSuccessfully'),
type: 'success'
})
dispatch('setShowDialog', {
type: 'window',
action: undefined
})
commit('setTotalRequest', 0)
commit('setTotalResponse', 0)
dispatch('setRecordSelection', {
parentUuid,
containerUuid,
isLoaded: false
})
dispatch('setTabSequenceRecord', [])
// refresh record list in table source
dispatch('getDataListTab', {
parentUuid,
containerUuid: tabAssociatedUuid
})
.catch(error => {
console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`)
})
}
})
})
}
},
getters: {
getInCreate: (state) => (containerUuid) => {
return state.inCreate.find(item => item.containerUuid === containerUuid)
},
getReferencesList: (state) => (windowUuid, recordUuid) => {
return state.references.find(item => item.windowUuid === windowUuid && item.recordUuid === recordUuid)
},
getReferencesInfo: (state, getters) => ({ windowUuid, recordUuid, referenceUuid }) => {
const references = getters.getReferencesList(windowUuid, recordUuid)
return references.referencesList.find(item => item.uuid === referenceUuid)
},
getTabSequenceRecord: (state) => {
return state.tabSequenceRecord
},
getDataLog: (state) => (containerUuid, recordUuid) => {
const current = state.dataLog
if (current.containerUuid === containerUuid &&
((current.recordUuid === recordUuid) ||
(current.eventType === 'DELETE' && recordUuid === 'create-new'))) {
return current
}
return undefined
}
}
}
export default windowControl

View File

@ -0,0 +1,452 @@
import {
getWindow as getWindowMetadata,
getTab as getTabMetadata
} from '@/api/ADempiere/dictionary'
import { showMessage } from '@/utils/ADempiere/notification'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils'
import language from '@/lang'
import router from '@/router'
import { generateField } from '@/utils/ADempiere/dictionaryUtils'
import { getFieldTemplate } from '@/utils/ADempiere/lookupFactory'
const initStateWindow = {
window: [],
windowIndex: 0
}
const window = {
state: initStateWindow,
mutations: {
addWindow(state, payload) {
state.window.push(payload)
state.windowIndex++
},
dictionaryResetCacheWindow(state) {
state = initStateWindow
},
setCurrentTab(state, payload) {
payload.window.currentTab = payload.tab
payload.window.currentTabUuid = payload.tab.uuid
},
changeWindowAttribute(state, payload) {
let value = payload.attributeValue
if (payload.attributeNameControl) {
value = payload.window[payload.attributeNameControl]
}
payload.window[payload.attributeName] = value
},
changeTabAttribute(state, payload) {
let value = payload.attributeValue
if (payload.attributeNameControl) {
value = payload.tab[payload.attributeNameControl]
}
payload.tab[payload.attributeName] = value
}
},
actions: {
/**
* Get Window metadata from server
* @param {string} windowUuid
* @param {number} windowId
* @param {object} routeToDelete, route to close in tagView when fail
*/
getWindowFromServer({ commit, state, dispatch }, {
windowUuid,
windowId,
routeToDelete
}) {
return getWindowMetadata({
uuid: windowUuid,
id: windowId
})
.then(responseWindow => {
const firstTabTableName = responseWindow.tabsList[0].tableName
const firstTabUuid = responseWindow.tabsList[0].uuid
const tabsListParent = []
const tabsListChildren = []
const tabsSequence = []
// TODO Add source tab on the server for tabs Translation and Sort
const tabs = responseWindow.tabsList.filter(itemTab => {
if (itemTab.isSortTab) {
// TODO: Add convert tab as process function
tabsSequence.push({
uuid: itemTab.uuid,
id: itemTab.id,
parentUuid: windowUuid,
containerUuid: itemTab.uuid,
parentTabUuid: itemTab.parentTabUuid,
panelType: 'window',
type: 'sequence',
isSortTab: itemTab.isSortTab,
name: itemTab.name,
description: itemTab.description,
tableName: itemTab.tableName,
sortOrderColumnName: itemTab.sortOrderColumnName, // order column
sortYesNoColumnName: itemTab.sortYesNoColumnName // included column
})
}
// TODO: Add support to isAdvancedTab, isTranslationTab and isHasTree
return !itemTab.isTranslationTab
}).map((tabItem, index, list) => {
// let tab = tabItem
const tab = {
...tabItem,
containerUuid: tabItem.uuid,
parentUuid: windowUuid,
windowUuid,
tabGroup: tabItem.fieldGroup,
firstTabUuid,
// relations
isParentTab: Boolean(firstTabTableName === tabItem.tableName),
// app properties
isAssociatedTabSequence: false, // show modal with order tab
isShowedRecordNavigation: !(tabItem.isSingleRow),
isLoadFieldsList: false,
index
}
delete tab.processesList
// action is dispatch used in vuex
let actions = []
actions.push({
// action to set default values and enable fields not isUpdateable
name: language.t('window.newRecord'),
processName: language.t('window.newRecord'),
type: 'dataAction',
action: 'setDefaultValues',
uuidParent: windowUuid,
disabled: !tab.isInsertRecord || tab.isReadOnly
}, {
// action to delete record selected
name: language.t('window.deleteRecord'),
processName: language.t('window.deleteRecord'),
type: 'dataAction',
action: 'deleteEntity',
uuidParent: windowUuid,
disabled: tab.isReadOnly
}, {
// action to undo create, update, delete record
name: language.t('data.undo'),
processName: language.t('data.undo'),
type: 'dataAction',
action: 'undoModifyData',
uuidParent: windowUuid,
disabled: false
}, {
name: language.t('data.lockRecord'),
processName: language.t('data.lockRecord'),
type: 'dataAction',
action: 'lockRecord',
disabled: false,
hidden: true,
tableName: '',
recordId: null
}, {
name: language.t('data.unlockRecord'),
processName: language.t('data.unlockRecord'),
type: 'dataAction',
action: 'unlockRecord',
disabled: false,
hidden: true,
tableName: '',
recordId: null
})
if (tab.isSortTab) {
const tabParent = list.find(itemTab => itemTab.tableName === tab.tableName && !itemTab.isSortTab)
if (tabParent) {
tab.tabAssociatedUuid = tabParent.uuid // tab source uuid
tab.tabAssociatedName = tabParent.name // tab source name
}
} else {
// add tabs sequence associated as process in tab source
let orderTabs = tabsSequence.filter(itemTab => itemTab.tableName === tab.tableName)
if (orderTabs.length) {
orderTabs = orderTabs.map(itemTab => {
return {
...itemTab,
// appication attributes
tabAssociatedUuid: tab.uuid, // tab source
tabAssociatedName: tab.name, // tab source
action: 'orderSequence',
panelType: 'window',
type: 'application'
}
})
actions = actions.concat(orderTabs)
tab.isAssociatedTabSequence = true
tab.tabsOrder = orderTabs
}
}
// get processess associated in tab
if (tabItem.processesList && tabItem.processesList.length) {
const processList = tabItem.processesList.map(processItem => {
// TODO: No list of parameters
// add process associated in vuex store
// dispatch('addProcessAssociated', {
// processToGenerate: processItem,
// containerUuidAssociated: tabItem.uuid
// })
return {
id: processItem.id,
uuid: processItem.uuid,
name: processItem.name,
type: 'process',
panelType: 'process',
description: processItem.description,
help: processItem.help,
isReport: processItem.isReport,
isDirectPrint: processItem.isDirectPrint,
containerUuidAssociated: tabItem.uuid,
parentUuidAssociated: windowUuid,
panelTypeAssociated: 'window'
}
})
actions = actions.concat(processList)
}
// Add process menu
dispatch('setContextMenu', {
containerUuid: tab.uuid,
actions
})
if (tab.isParentTab) {
tabsListParent.push(tab)
return tab
}
if (!tab.isSortTab) {
tabsListChildren.push(tab)
}
return tab
})
const newWindow = {
...responseWindow,
tabsList: tabs,
currentTab: tabsListParent[0],
tabsListParent,
tabsListChildren,
// app attributes
currentTabUuid: tabsListParent[0].uuid,
firstTab: tabsListParent[0],
firstTabUuid,
windowIndex: state.windowIndex + 1,
// App properties
isShowedTabsChildren: Boolean(tabsListChildren.length),
isShowedRecordNavigation: undefined,
isShowedAdvancedQuery: false
}
commit('addWindow', newWindow)
return newWindow
})
.catch(error => {
router.push({ path: '/dashboard' })
dispatch('tagsView/delView', routeToDelete)
showMessage({
message: language.t('login.unexpectedError'),
type: 'error'
})
console.warn(`Dictionary Window (State Window) - Error ${error.code}: ${error.message}.`)
})
},
getTabAndFieldFromServer({ dispatch, getters }, {
parentUuid,
containerUuid,
tabId,
panelType = 'window',
panelMetadata,
isAdvancedQuery = false
}) {
return new Promise((resolve, reject) => {
getTabMetadata({
uuid: containerUuid,
id: tabId
})
.then(tabResponse => {
const additionalAttributes = {
parentUuid,
containerUuid,
isShowedFromUser: true,
panelType,
tableName: tabResponse.tableName,
//
isReadOnlyFromForm: false,
isAdvancedQuery,
isEvaluateValueChanges: !isAdvancedQuery
}
let isWithUuidField = false // indicates it contains the uuid field
let fieldLinkColumnName
// Convert and add to app attributes
const fieldsList = tabResponse.fieldsList.map((fieldItem, index) => {
fieldItem = generateField({
fieldToGenerate: fieldItem,
moreAttributes: {
...additionalAttributes,
fieldListIndex: index
}
})
if (!isWithUuidField && fieldItem.columnName === 'UUID') {
isWithUuidField = true
}
if (fieldItem.isParent) {
fieldLinkColumnName = fieldItem.columnName
}
return fieldItem
})
let isTabsChildren = false
if (!isAdvancedQuery) {
const window = getters.getWindow(parentUuid)
isTabsChildren = Boolean(window.tabsListChildren.length)
}
if (!isWithUuidField) {
const fieldUuid = getFieldTemplate({
...additionalAttributes,
isShowedFromUser: false,
name: 'UUID',
columnName: 'UUID',
componentPath: 'FieldText'
})
fieldsList.push(fieldUuid)
}
if (isEmptyValue(panelMetadata)) {
panelMetadata = getters.getTab(parentUuid, containerUuid)
}
// Panel for save on store
const panel = {
...panelMetadata,
isAdvancedQuery,
fieldLinkColumnName,
fieldList: fieldsList,
panelType,
// app attributes
isLoadFieldsList: true,
isShowedTotals: false,
isTabsChildren // to delete records assiciated
}
dispatch('addPanel', panel)
resolve(panel)
dispatch('changeTabAttribute', {
parentUuid,
containerUuid,
tab: panelMetadata,
attributeName: 'isLoadFieldsList',
attributeValue: true
})
})
.catch(error => {
showMessage({
message: language.t('login.unexpectedError'),
type: 'error'
})
console.warn(`Get Dictionary Tab (State Window) - Error ${error.code}: ${error.message}.`, error)
reject(error)
})
})
},
setCurrentTab({ commit, getters }, {
parentUuid,
containerUuid,
window,
tab
}) {
if (isEmptyValue(window)) {
window = getters.getWindow(parentUuid)
}
if (isEmptyValue(tab)) {
tab = window.tabsList.find(itemTab => itemTab.uuid === containerUuid)
}
commit('setCurrentTab', {
window,
tab
})
},
changeWindowAttribute({ commit, getters }, {
parentUuid,
window,
attributeName,
attributeNameControl,
attributeValue
}) {
if (isEmptyValue(window)) {
window = getters.getWindow(parentUuid)
}
commit('changeWindowAttribute', {
parentUuid,
window,
attributeName,
attributeNameControl,
attributeValue
})
},
changeTabAttribute({ commit, getters }, {
parentUuid,
containerUuid,
tab,
attributeName,
attributeNameControl,
attributeValue
}) {
if (isEmptyValue(tab)) {
tab = getters.getTab(parentUuid, containerUuid)
}
commit('changeTabAttribute', {
tab,
attributeName,
attributeValue,
attributeNameControl
})
}
},
getters: {
getWindow: (state) => (windowUuid) => {
return state.window.find(
item => item.uuid === windowUuid
)
},
getIsShowedRecordNavigation: (state, getters) => (windowUuid) => {
const window = getters.getWindow(windowUuid)
if (window) {
return window.isShowedRecordNavigation
}
return window
},
getTab: (state, getters) => (windowUuid, tabUuid) => {
const window = getters.getWindow(windowUuid)
if (window) {
return window.tabsList.find(tabItem => {
return tabItem.uuid === tabUuid
})
}
return window
},
getCurrentTab: (state, getters) => (windowUuid) => {
const window = getters.getWindow(windowUuid)
if (window) {
return window.tabsList.find(tabItem => {
return tabItem.uuid === window.currentTabUuid
})
}
return {
isInsertRecord: false
}
},
getTableNameFromTab: (state, getters) => (windowUuid, tabUuid) => {
return getters.getTab(windowUuid, tabUuid).tableName
}
}
}
export default window

View File

@ -157,7 +157,9 @@ const actions = {
// TODO: return #Date as long data type Date (5)
responseGetInfo.defaultContextMap.set('#Date', new Date())
// set multiple context
dispatch('setMultipleContextMap', responseGetInfo.defaultContextMap, {
dispatch('setMultiplePreference', {
values: responseGetInfo.defaultContextMap
}, {
root: true
})
@ -295,7 +297,7 @@ const actions = {
console.warn(`Error ${error.code} getting Organizations list: ${error.message}.`)
})
},
changeOrganization({ commit, dispatch }, {
changeOrganization({ dispatch }, {
organizationUuid
}) {
setCurrentOrganization(organizationUuid)

View File

@ -1,4 +1,5 @@
import { isEmptyValue } from '@/utils/ADempiere/valueUtils'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js'
import { convertBooleanToString } from '@/utils/ADempiere/valueFormat.js'
import evaluator from '@/utils/ADempiere/evaluator'
import store from '@/store'
@ -10,13 +11,89 @@ export const getContext = ({
containerUuid,
columnName
}) => {
return store.getters.getContext({
parentUuid,
containerUuid,
columnName
})
let value
const isPreferenceValue = columnName.startsWith('$') || columnName.startsWith('#')
if (isPreferenceValue || columnName.startsWith(`P|${parentUuid}`) || columnName.startsWith(`P|${columnName}`)) {
value = store.getters.getPreference({
parentUuid,
containerUuid,
columnName
})
}
if (!isPreferenceValue && isEmptyValue(value)) {
value = store.getters.getValueOfContainer({
parentUuid,
containerUuid,
columnName
})
}
return value
}
/**
* Get Preference.
* <pre>
* 0) Current Setting
* 1) Window Preference
* 2) Global Preference
* 3) Login settings
* 4) Accounting settings
* </pre>
* @param {string} parentUuid UUID Window
* @param {string} containerUuid UUID Tab, Process, SmartBrowser, Report and Form
* @param {string} columnName (context) Entity to search
* @return preference value
*/
export function getPreference({
parentUuid,
containerUuid,
columnName
}) {
let value
if (isEmptyValue(columnName)) {
console.warn('Require Context ColumnName')
return value
}
// USER PREFERENCES
// View Preferences
if (parentUuid) {
value = getContext({
parentUuid: 'P' + parentUuid,
containerUuid,
columnName
})
if (!isEmptyValue(value)) {
return value
}
}
// Global Preferences
value = getContext({
columnName: 'P|' + columnName
})
if (!isEmptyValue(value)) {
return value
}
// SYSTEM PREFERENCES
// Login setting
// get # globals context only window
value = getContext({
columnName: '#' + columnName
})
if (!isEmptyValue(value)) {
return value
}
// Accounting setting
value = getContext({
columnName: '$' + columnName
})
return value
} // getPreference
/**
* Extracts the associated fields from the logics or default values
* @param {string} displayLogic
@ -50,6 +127,12 @@ export function getParentFields({
return parentFields
}
export const specialColumns = [
'C_AcctSchema_ID',
'C_Currency_ID',
'C_Convertion_Type_ID'
]
/**
* Parse Context String
* @param {string} value: (REQUIRED) String to parsing
@ -71,17 +154,22 @@ export function parseContext({
}) {
let isError = false
const errorsList = []
value = String(value)
if (isEmptyValue(value)) {
value = undefined
if (specialColumns.includes(columnName)) {
value = contextInfo = getContext({
columnName: '$' + columnName
})
}
return {
value: undefined,
value,
isError: true,
errorsList: []
errorsList
}
}
if (value.includes('@SQL=')) {
value = value.replace('@SQL=', '')
}
value = String(value).replace('@SQL=')
// const instances = value.length - value.replace('@', '').length
// if ((instances > 0) && (instances % 2) !== 0) { // could be an email address
// return value
@ -92,12 +180,6 @@ export function parseContext({
let outString = ''
let firstIndexTag = inString.indexOf('@')
const convertBooleanToString = (booleanValue) => {
if (booleanValue) {
return 'Y'
}
return 'N'
}
while (firstIndexTag !== -1) {
outString = outString + inString.substring(0, firstIndexTag) // up to @
@ -122,23 +204,32 @@ export function parseContext({
containerUuid,
columnName
}) // get context
if (isEmptyValue(contextInfo)) {
// get global context
if (token.startsWith('#') || token.startsWith('$')) {
contextInfo = getContext({
columnName
})
} else {
// get accounting context
if (specialColumns.includes(columnName)) {
contextInfo = getContext({
columnName: '$' + columnName
})
}
}
}
// menu attribute isEmptyValue isSOTrx
if (!isEmptyValue(isSOTrxMenu) && token === 'IsSOTrx' && isEmptyValue(contextInfo)) {
contextInfo = isSOTrxMenu
}
if ((isBooleanToString || isSQL) && typeof contextInfo === 'boolean') {
contextInfo = convertBooleanToString(contextInfo)
}
if (isEmptyValue(contextInfo) &&
(token.startsWith('#') || token.startsWith('$'))) {
contextInfo = getContext({
columnName
}) // get global context
}
// menu attribute isEmptyValue isSOTrx
if (!isEmptyValue(isSOTrxMenu) && token === 'IsSOTrx' && isEmptyValue(contextInfo)) {
contextInfo = isSOTrxMenu
if (isBooleanToString || isSQL) {
contextInfo = convertBooleanToString(contextInfo)
}
}
if (contextInfo === undefined || contextInfo.length === 0) {
// console.info(`No Context for: ${token}`)
isError = true
@ -153,7 +244,8 @@ export function parseContext({
inString = inString.substring(secondIndexTag + 1, inString.length) // from second @
firstIndexTag = inString.indexOf('@')
}
} // end while loop
if (!['object', 'boolean'].includes(typeof contextInfo)) {
outString = outString + inString // add the rest of the string
}
@ -173,67 +265,3 @@ export function parseContext({
value: outString
}
} // parseContext
/**
* Get Preference.
* <pre>
* 0) Current Setting
* 1) Window Preference
* 2) Global Preference
* 3) Login settings
* 4) Accounting settings
* </pre>
* @param {string} parentUuid UUID Window
* @param {string} containerUuid UUID Tab, Process, SmartBrowser, Report and Form
* @param {string} columnName (context) Entity to search
* @return preference value
*/
export function getPreference({
parentUuid,
containerUuid,
columnName
}) {
let retValue
if (isEmptyValue(columnName)) {
console.warn('Require Context ColumnName')
return retValue
}
// USER PREFERENCES
// View Preferences
if (parentUuid && containerUuid) {
retValue = getContext({
parentUuid: 'P' + parentUuid,
containerUuid,
columnName: columnName
})
if (!isEmptyValue(retValue)) {
return retValue
}
}
// Global Preferences
retValue = getContext({
columnName: 'P|' + columnName
})
if (!isEmptyValue(retValue)) {
return retValue
}
// SYSTEM PREFERENCES
// Login setting
// get # globals context only window
retValue = getContext({
columnName: '#' + columnName
})
if (!isEmptyValue(retValue)) {
return retValue
}
// Accounting setting
retValue = getContext({
columnName: '$' + columnName
})
return retValue
} // getPreference

View File

@ -63,7 +63,7 @@ export function generateField({
...moreAttributes,
columnName: fieldToGenerate.columnName,
value: parsedDefaultValue,
isSOTrxMenu: isSOTrxMenu
isSOTrxMenu
}).value
}
@ -88,7 +88,8 @@ export function generateField({
}
parsedDefaultValue = parsedValueComponent({
fieldType: componentReference.componentPath,
componentPath: componentReference.componentPath,
columnName: fieldToGenerate.columnName,
value: parsedDefaultValue,
displayType: fieldToGenerate.displayType,
isMandatory: fieldToGenerate.isMandatory,
@ -132,7 +133,8 @@ export function generateField({
}
parsedDefaultValueTo = parsedValueComponent({
fieldType: componentReference.componentPath,
componentPath: componentReference.componentPath,
columnName: fieldToGenerate.columnName,
value: parsedDefaultValueTo,
displayType: fieldToGenerate.displayType,
isMandatory: fieldToGenerate.isMandatory,
@ -170,12 +172,15 @@ export function generateField({
const field = {
...fieldToGenerate,
...moreAttributes,
columnNameTo: undefined,
elementNameTo: undefined,
isSOTrxMenu,
// displayed attributes
componentPath: componentReference.componentPath,
isSupported: componentReference.isSupported,
size: componentReference.size || DEFAULT_SIZE,
displayColumn: undefined, // link to value from selects and table
displayColumnName: `DisplayColumn_${fieldToGenerate.columnName}`, // key to display column
// value attributes
value: String(parsedDefaultValue).trim() === '' ? undefined : parsedDefaultValue,
oldValue: parsedDefaultValue,
@ -211,9 +216,12 @@ export function generateField({
// Overwrite some values
if (field.isRange) {
field.operator = 'GREATER_EQUAL'
field.columnNameTo = `${field.columnName}_To`
field.elementNameTo = `${field.elementNameTo}_To`
if (typeRange) {
field.uuid = `${field.uuid}_To`
field.columnName = `${field.columnName}_To`
field.columnName = field.columnNameTo
field.elementName = field.elementNameTo
field.name = `${field.name} To`
field.value = parsedDefaultValueTo
field.defaultValue = field.defaultValueTo
@ -491,24 +499,32 @@ export function sortFields({
/**
* Determinate if field is displayed
* @param {boolean} field.isActive
* @param {boolean} field.isDisplayed
* @param {boolean} field.isDisplayedFromLogic
* @param {boolean} field.isQueryCriteria
* @param {string} field.panelType
* @param {boolean} isActive
* @param {boolean} isDisplayed
* @param {boolean} isDisplayedFromLogic
* @param {boolean} isQueryCriteria
* @param {string} panelType
* @returns {boolean}
*/
export function fieldIsDisplayed(field) {
// if is Advanced Query
if (field.panelType === 'table') {
return field.isDisplayed && field.isDisplayedFromLogic
export function fieldIsDisplayed({
panelType,
isActive,
isDisplayed,
isDisplayedFromLogic,
isQueryCriteria
}) {
// Verify if field is active
if (!isActive) {
return false
}
const isBrowserDisplayed = field.isQueryCriteria // browser query criteria
const isWindowDisplayed = field.isDisplayed && field.isDisplayedFromLogic // window, process and report, browser result
const isDisplayedView = (field.panelType === 'browser' && isBrowserDisplayed) || (field.panelType !== 'browser' && isWindowDisplayed)
// Verify for displayed and is active
return field.isActive && isDisplayedView
// browser query criteria
if (panelType === 'browser') {
return isQueryCriteria
}
// window, table (advanced query), process and report, browser (table) result
return isDisplayed && isDisplayedFromLogic
}
// Convert action to action name for route

View File

@ -1,3 +1,6 @@
import { convertStringToBoolean } from '@/utils/ADempiere/valueFormat.js'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js'
// This class is used for evaluate a conditional
// format := {expression} [{logic} {expression}]<br>
// expression := @{context}@{operand}{value} or @{context}@{operand}{value}<br>
@ -27,7 +30,7 @@ class evaluator {
defaultReturned = false
}) {
// empty logic
if (logic === undefined || logic === null || logic.trim() === '') {
if (isEmptyValue(logic)) {
return defaultReturned
}
const st = logic.trim().replace('\n', '')
@ -96,7 +99,7 @@ class evaluator {
logic
}) {
// not context info, not logic
if (logic === undefined || logic === null || logic.trim() === '') {
if (isEmptyValue(logic)) {
return defaultReturned
}
@ -140,14 +143,14 @@ class evaluator {
columnName: first
})
// in context exists this column name
if (value === null || value === undefined) {
// console.info(`.The column ${first} not exists in context.`)
if (isEmptyValue(value)) {
// console.info(`.The column ${first} not exists in context.`)
return defaultReturned
}
firstEval = value // replace with it's value
}
if (firstEval === null || firstEval === undefined) {
if (isEmptyValue(firstEval)) {
return defaultReturned
}
if (typeof firstEval === 'string') {
@ -193,16 +196,6 @@ class evaluator {
* @return {boolean}
*/
static evaluateLogicTuple(value1, operand, value2) {
const convertStringToBoolean = (valueToParsed) => {
const valueString = String(valueToParsed).trim()
if (valueString === 'Y') {
return true
} else if (valueString === 'N') {
return false
}
return valueToParsed
}
// Convert value 1 string value to boolean value
value1 = convertStringToBoolean(value1)
@ -250,7 +243,7 @@ class evaluator {
*/
static parseDepends(parseString) {
const listFields = []
if (parseString === null || parseString === undefined) {
if (isEmptyValue(parseString)) {
// return array empty
return listFields
}

View File

@ -285,6 +285,7 @@ export function getFieldTemplate(overwriteDefinition) {
isKey: false,
isSelectionColumn: false,
isUpdateable: true,
//
formatPattern: undefined,
VFormat: undefined,
value: undefined,
@ -293,6 +294,7 @@ export function getFieldTemplate(overwriteDefinition) {
parsedDefaultValue: undefined,
defaultValueTo: undefined,
parsedDefaultValueTo: undefined,
valueType: componentReference.valueType, // value type to convert with gGRPC
valueMin: undefined,
valueMax: undefined,
//

View File

@ -1,10 +1,90 @@
// A util class for handle format for time, date and others values to beused to display information
// Note that this file use moment library for a easy conversion
import moment from 'moment'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js'
import store from '@/store'
import { DATE, DATE_PLUS_TIME, TIME } from '@/utils/ADempiere/references'
export const convertStringToBoolean = (valueToParsed) => {
const valueString = String(valueToParsed).trim()
if (valueString === 'N' || valueString === 'false') {
return false
}
return Boolean(valueToParsed)
}
export const convertBooleanToString = (booleanValue) => {
if (booleanValue || booleanValue === 'true') {
return 'Y'
}
return 'N'
}
/**
* Convert a object to array pairs
* @param {object} object, object to convert
* @param {string} nameKey, name from key in pairs
* @param {string} nameValue, name from value in pairs
* @returns {array} [ { nameKey: key, nameValue: value } ]
*/
export function convertObjectToKeyValue({
object,
keyName = 'columnName',
valueName = 'value'
}) {
return Object.keys(object).map(key => {
const returnPairs = {}
returnPairs[keyName] = key
returnPairs[valueName] = object[key]
return returnPairs
})
}
/**
* Convert array pairs of object to literal object { key: value }
* @param {array} array, Array to convert
* @param {string} nameKey, name from key in pairs
* @param {string} nameValue, name from value in pairs
* @returns {object} { key: value, key2: value2 }
*/
export function convertArrayKeyValueObject({
array,
keyName = 'columnName',
valueName = 'value'
}) {
const result = {}
array.forEach(element => {
result[element[keyName]] = element[valueName]
})
return result
}
/**
* Convert map of pairs to literal object
* @param {object} object
* @returns {map}
*/
export function convertObjectToHasMap({ object }) {
return new Map(
Object.entries(object)
)
}
/**
* Convert map of pairs to literal object
* @param {map} hasMapToConvert
* @returns {object} { key: value, key2: value2 }
*/
export function convertHasMapToObject({ map }) {
return Object.fromEntries(map)
// const result = {}
// map.forEach((value, key) => {
// result[key] = value
// })
// return result
}
// This function just convert all java date format to moment format.
// For know about java format pattern see: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
// Also you can read moment docus: https://momentjs.com/docs/

View File

@ -1,4 +1,5 @@
import { TABLE, TABLE_DIRECT } from '@/utils/ADempiere/references'
import { convertStringToBoolean, convertBooleanToString } from '@/utils/ADempiere/valueFormat.js'
import { TABLE, TABLE_DIRECT } from '@/utils/ADempiere/references.js'
/**
* Checks if value is empty. Deep-checks arrays and objects
@ -87,49 +88,6 @@ export function clientDateTime(date = null, type = '') {
return currentDateTime.date + ' ' + currentDateTime.time
}
/**
* Convert a object to array pairs
* @param {object} objectToConvert, object to convert
* @param {string} nameKey, name from key in pairs
* @param {string} nameValue, name from value in pairs
* @returns {array} [ { nameKey: key, nameValue: value } ]
*/
export function convertObjectToArrayPairs(objectToConvert, nameKey = 'columnName', nameValue = 'value') {
return Object.keys(objectToConvert).map(key => {
const returnPairs = {}
returnPairs[nameKey] = key
returnPairs[nameValue] = objectToConvert[key]
return returnPairs
})
}
/**
* Convert array pairs of object to simple object { key:value }
* @param {array} arrayToConvert, object to convert
* @param {string} nameKey, name from key in pairs
* @param {string} nameValue, name from value in pairs
*/
export function convertArrayPairsToObject({
arrayToConvert,
nameKey = 'columnName',
nameValue = 'value'
}) {
const result = {}
arrayToConvert.forEach(element => {
result[element[nameKey]] = element[nameValue]
})
return result
}
export function convertHasMapToObject(hasMapToConvert) {
const result = {}
hasMapToConvert.forEach((value, key) => {
result[key] = value
})
return result
}
export function convertFieldListToShareLink(fieldList) {
var attributesListLink = ''
fieldList.map(fieldItem => {
@ -230,28 +188,33 @@ export const recursiveTreeSearch = ({
/**
* Parsed value to component type
* @param {mixed} value, value to parsed
* @param {string} fieldType, or componentPath
* @param {string} componentPath
* @param {number} displayType, reference in ADempiere
* @param {boolean} isMandatory, field is mandatory
* @param {boolean} isIdentifier, field is ID
*/
export function parsedValueComponent({
fieldType,
componentPath,
value,
columnName,
displayType,
isMandatory = false,
isIdentifier = false
}) {
const isEmpty = isEmptyValue(value)
if (isEmpty && !isMandatory) {
if (fieldType === 'FieldYesNo') {
if (componentPath === 'FieldYesNo') {
if (columnName === 'IsActive') {
return true
}
// Processing, Processed, and any other columnName, return false by default
return Boolean(value)
}
return undefined
}
var returnValue
switch (fieldType) {
switch (componentPath) {
// data type Number
case 'FieldNumber':
if (isEmpty) {
@ -272,12 +235,10 @@ export function parsedValueComponent({
// data type Boolean
case 'FieldYesNo':
if (value === 'false' || value === 'N') {
value = false
} else if (typeof value === 'object' && Object.prototype.hasOwnProperty.call(value, 'query')) {
if (typeof value === 'object' && Object.prototype.hasOwnProperty.call(value, 'query')) {
returnValue = value
}
returnValue = Boolean(value)
returnValue = convertStringToBoolean(value)
break
// data type String
@ -312,7 +273,7 @@ export function parsedValueComponent({
value = undefined
}
if (typeof value === 'boolean') {
value = value ? 'Y' : 'N'
value = convertBooleanToString(value)
}
// Table (18) or Table Direct (19)
if (displayType === TABLE_DIRECT.id || (displayType === TABLE.id && isIdentifier)) {

View File

@ -117,8 +117,11 @@ export default {
isLoadedRecords() {
return this.$store.getters.getDataRecordAndSelection(this.browserUuid).isLoaded
},
getContainerIsReadyForSubmit() {
return !this.$store.getters.isNotReadyForSubmit(this.browserUuid) && !this.browserMetadata.awaitForValuesToQuery
isReadyToSearch() {
if (this.browserMetadata.awaitForValuesToQuery) {
return false
}
return !this.$store.getters.isNotReadyForSubmit(this.browserUuid)
},
isMobile() {
return this.$store.state.app.device === 'mobile'
@ -136,19 +139,15 @@ export default {
return 'content-help'
},
isShowedCriteria() {
if (this.getterBrowser) {
return this.getterBrowser.isShowedCriteria
if (this.browserMetadata) {
return this.browserMetadata.isShowedCriteria
}
return false
}
},
watch: {
isShowedCriteria(value) {
const activeSearch = []
if (value) {
activeSearch.push('opened-criteria')
}
this.activeSearch = activeSearch
this.handleCollapse(value)
}
},
created() {
@ -166,6 +165,18 @@ export default {
attributeValue: showCriteria
})
},
/**
* Manage open or closed component collapse of criteria
*/
handleCollapse(isShowedCriteria) {
// by default criteria if closed
const activeSearch = []
if (isShowedCriteria) {
// open criteria
activeSearch.push('opened-criteria')
}
this.activeSearch = activeSearch
},
getBrowser() {
const browser = this.getterBrowser
if (browser) {
@ -181,6 +192,7 @@ export default {
})
.then(browserResponse => {
this.browserMetadata = browserResponse
this.handleCollapse(browserResponse.isShowedCriteria)
this.defaultSearch()
})
.finally(() => {
@ -188,24 +200,23 @@ export default {
})
},
defaultSearch() {
// open or closed show criteria
this.activeSearch = []
if (this.browserMetadata.isShowedCriteria) {
this.activeSearch = ['opened-criteria']
}
if (!this.isLoadedRecords) {
if (this.getContainerIsReadyForSubmit) {
if (this.isLoadedRecords) {
// not research
return
} else {
if (this.isReadyToSearch) {
// first search by default
this.$store.dispatch('getBrowserSearch', {
containerUuid: this.browserUuid
})
return
}
} else {
this.$store.dispatch('setRecordSelection', {
containerUuid: this.browserUuid,
panelType: this.panelType
})
}
// set default values into data
this.$store.dispatch('setRecordSelection', {
containerUuid: this.browserUuid,
panelType: this.panelType
})
}
}
}