Skip to content

Commit

Permalink
Removed reset of field settings on schema change
Browse files Browse the repository at this point in the history
Because column aggregation settings on list fields were stored based on column order, thing could break if a list field changed. That is why we had the workaround to reset field settings on every schema change.

Now column aggregation is connected to column ID (instead of order). This means that schema changes at most cause invalid aggregation settings to not be used, instead of causing issues in list presentation.

Because of this change, we can now keep field settings alive even with schema changes.
  • Loading branch information
r3-gabriel committed Oct 18, 2023
1 parent d1a7188 commit a698c2d
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 98 deletions.
44 changes: 21 additions & 23 deletions www/comps/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,14 +385,14 @@ let MyList = {
<th v-for="(b,i) in columnBatches">
<my-list-column-batch
@close="columnBatchIndexOption = -1"
@del-aggregator="setAggregators(i,null)"
@del-aggregator="setAggregators"
@del-order="setOrder(b,null)"
@set-aggregator="setAggregators(i,$event)"
@set-aggregator="setAggregators"
@set-filters="filtersColumn = $event;reloadInside('filtersColumn')"
@set-order="setOrder(b,$event)"
@toggle="clickColumn(i)"
:aggregator="columnBatchIndexMapAggr[i]"
:columnBatch="b"
:columnIdMapAggr="columnIdMapAggr"
:columns="columns"
:columnSortPos="getColumnBatchSortPos(b)"
:filters="filters"
Expand Down Expand Up @@ -509,7 +509,7 @@ let MyList = {
<!-- result aggregations -->
<my-list-aggregate ref="aggregations"
:columnBatches="columnBatches"
:columnBatchIndexMapAggr="columnBatchIndexMapAggr"
:columnIdMapAggr="columnIdMapAggr"
:columns="columns"
:filters="filtersCombined"
:leaveOneEmpty="hasBulkActions"
Expand Down Expand Up @@ -710,15 +710,15 @@ let MyList = {
cardsOrderByColumnIndex:-1,

// list data
columnBatchIndexMapAggr:{}, // map of aggregators, key: column batch index
count:0, // total result set count
limit:0, // current result limit
offset:0, // current result offset
orders:[], // column orderings, copied on mount, changable by user
rows:[], // current result set
filtersColumn:[], // current user column filters
filtersQuick:'', // current user quick text filter
filtersUser:[], // current user filters
columnIdMapAggr:{}, // aggregators by column ID
count:0, // total result set count
limit:0, // current result limit
offset:0, // current result offset
orders:[], // column orderings, copied on mount, changable by user
rows:[], // current result set
filtersColumn:[], // current user column filters
filtersQuick:'', // current user quick text filter
filtersUser:[], // current user filters

// list constants
refTabindex:'input_row_', // prefix for vue references to tabindex elements
Expand Down Expand Up @@ -1007,10 +1007,10 @@ let MyList = {
}

// load cached list options
this.filtersColumn = this.fieldOptionGet(this.fieldId,'filtersColumn',[]);
this.filtersQuick = this.fieldOptionGet(this.fieldId,'filtersQuick','');
this.filtersUser = this.fieldOptionGet(this.fieldId,'filtersUser',[]);
this.columnBatchIndexMapAggr = this.fieldOptionGet(this.fieldId,'columnBatchIndexMapAggr',{});
this.filtersColumn = this.fieldOptionGet(this.fieldId,'filtersColumn',[]);
this.filtersQuick = this.fieldOptionGet(this.fieldId,'filtersQuick','');
this.filtersUser = this.fieldOptionGet(this.fieldId,'filtersUser',[]);
this.columnIdMapAggr = this.fieldOptionGet(this.fieldId,'columnIdMapAggr',{});
},
beforeUnmount() {
this.setAutoRenewTimer(true);
Expand Down Expand Up @@ -1246,13 +1246,11 @@ let MyList = {
}
}
},
setAggregators(columnBatchIndex,aggregator) {
if(aggregator !== null)
this.columnBatchIndexMapAggr[columnBatchIndex] = aggregator;
else
delete(this.columnBatchIndexMapAggr[columnBatchIndex]);
setAggregators(columnId,aggregator) {
if(aggregator !== null) this.columnIdMapAggr[columnId] = aggregator;
else delete(this.columnIdMapAggr[columnId]);

this.fieldOptionSet(this.fieldId,'columnBatchIndexMapAggr',this.columnBatchIndexMapAggr);
this.fieldOptionSet(this.fieldId,'columnIdMapAggr',this.columnIdMapAggr);
this.$refs.aggregations.get();
},
setAutoRenewTimer(justClear) {
Expand Down
101 changes: 52 additions & 49 deletions www/comps/listAggregate.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,37 @@ let MyListAggregate = {
template:`<tr class="aggregation" v-if="anyValues">
<td v-if="leaveOneEmpty"></td>
<td v-for="(b,i) in columnBatches">
{{ typeof columnBatchIndexMapValue[i] !== 'undefined' ? columnBatchIndexMapValue[i] : '' }}
{{ valuesByColumnBatch[i] !== null ? valuesByColumnBatch[i] : '' }}
</td>
</tr>`,
props:{
columnBatches: { type:Array, required:true }, // list column batches
columnBatchIndexMapAggr:{ type:Object, required:true }, // list aggregators
columns: { type:Array, required:true }, // list columns
filters: { type:Array, required:true }, // list filters
leaveOneEmpty: { type:Boolean, required:true },
joins: { type:Array, required:true }, // list joins
relationId: { type:String, required:true } // list base relation
columnBatches: { type:Array, required:true }, // list column batches
columnIdMapAggr:{ type:Object, required:true }, // map of aggregators by column ID
columns: { type:Array, required:true }, // list columns
filters: { type:Array, required:true }, // list filters
leaveOneEmpty: { type:Boolean, required:true },
joins: { type:Array, required:true }, // list joins
relationId: { type:String, required:true } // list base relation
},
data() {
return {
columnBatchIndexMapValue:{}
valuesByColumnBatch:[]
};
},
computed:{
anyValues: (s) => Object.keys(s.columnBatchIndexMapValue).length !== 0,
// map aggregator column ID to corresponding column batch index
columnIdMapColumnBatchIndex:(s) => {
let out = {};
for(let i = 0, j = s.columnBatches.length; i < j; i++) {
const c = s.getFirstColumnUsableAsAggregator(s.columnBatches[i],s.columns);

if(c !== null)
out[c.id] = i;
}
return out;
},

anyValues: (s) => s.valuesByColumnBatch.length !== 0,
dateFormat:(s) => s.$store.getters.settings.dateFormat,

// stores
Expand All @@ -44,22 +56,19 @@ let MyListAggregate = {

// calls
get() {
this.columnBatchIndexMapValue = {};
this.valuesByColumnBatch = [];

let columns = [];
for(let i = 0, j = this.columnBatches.length; i < j; i++) {
if(typeof this.columnBatchIndexMapAggr[i] === 'undefined')
continue;

let b = this.columnBatches[i];
let c = JSON.parse(JSON.stringify(
this.getFirstColumnUsableAsAggregator(b,this.columns)
));

if(c === null)
continue;

c.aggregator = this.columnBatchIndexMapAggr[i];
columns.push(c);
for(let columnId in this.columnIdMapAggr) {
for(let column of this.columns) {
if(column.id !== columnId)
continue;

const c = JSON.parse(JSON.stringify(column));
c.aggregator = this.columnIdMapAggr[columnId];
columns.push(c);
break;
}
}

if(columns.length === 0)
Expand All @@ -72,36 +81,30 @@ let MyListAggregate = {
filters:this.filters
},false).then(
res => {
let values = [];
for(let r of res.payload.rows) {
for(let v of r.values) {
values.push(v);
}
if(res.payload.rows.length !== 1 || res.payload.rows[0].values.length !== columns.length)
return;

const row = res.payload.rows[0];

for(let b of this.columnBatches) {
this.valuesByColumnBatch.push(null);
}

// set aggregated values
let valueIndex = -1;
for(let i = 0, j = this.columnBatches.length; i < j; i++) {

if(typeof this.columnBatchIndexMapAggr[i] === 'undefined')
continue;

valueIndex++;
let a = this.columnBatchIndexMapAggr[i];
let v = values[valueIndex];
for(let i = 0, j = columns.length; i < j; i++) {
const c = columns[i];
let v = row.values[i];

// count aggregations can be taken directly
if(a === 'count') {
this.columnBatchIndexMapValue[i] = v;
continue;
if(c.aggregator !== 'count') {
switch(this.attributeIdMap[c.attributeId].contentUse) {
case 'date': v = this.getUnixFormat(v,this.dateFormat); break;
case 'datetime': v = this.getUnixFormat(v,this.dateFormat + ' H:i'); break;
case 'time': v = this.getUtcTimeStringFromUnix(v); break;
}
}

switch(this.attributeIdMap[columns[valueIndex].attributeId].contentUse) {
case 'date': v = this.getUnixFormat(v,this.dateFormat); break;
case 'datetime': v = this.getUnixFormat(v,this.dateFormat + ' H:i'); break;
case 'time': v = this.getUtcTimeStringFromUnix(v); break;
}
this.columnBatchIndexMapValue[i] = v;
const bi = this.columnIdMapColumnBatchIndex[c.id];
this.valuesByColumnBatch[bi] = v;
}
},
this.$root.genericError
Expand Down
47 changes: 27 additions & 20 deletions www/comps/listColumnBatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,14 @@ let MyListColumnBatch = {
</div>
<!-- aggregation -->
<div class="columnOptionItem" v-if="canAggregate">
<div class="columnOptionItem" v-if="aggrColumn !== null">
<my-button image="sum.png"
@trigger="aggregatorProcessed = ''"
:active="aggregatorProcessed !== ''"
@trigger="aggregatorInput = ''"
:active="aggregatorInput !== ''"
:captionTitle="capApp.button.aggregatorsHint"
:naked="true"
/>
<select v-model="aggregatorProcessed">
<select v-model="aggregatorInput">
<option value="">-</option>
<option value="avg">{{ capGen.option.aggAvg }}</option>
<option value="count">{{ capGen.option.aggCount }}</option>
Expand Down Expand Up @@ -140,18 +140,18 @@ let MyListColumnBatch = {
</div>
</div>`,
props:{
aggregator: { required:true },
columnBatch: { type:Object, required:true }, // column batch to show options for
columns: { type:Array, required:true }, // list columns
columnSortPos:{ type:Number, required:true }, // list sort for this column (number indicates sort position)
filters: { type:Array, required:true }, // list filters (predefined)
filtersColumn:{ type:Array, required:true }, // list filters from users column selection
lastInRow: { type:Boolean, required:true },
joins: { type:Array, required:true }, // list joins
orders: { type:Array, required:true }, // list orders
relationId: { type:String, required:true }, // list query base relation ID
rowCount: { type:Number, required:true }, // list total row count
show: { type:Boolean, required:true }
columnBatch: { type:Object, required:true }, // column batch to show options for
columnIdMapAggr:{ type:Object, required:true },
columns: { type:Array, required:true }, // list columns
columnSortPos: { type:Number, required:true }, // list sort for this column (number indicates sort position)
filters: { type:Array, required:true }, // list filters (predefined)
filtersColumn: { type:Array, required:true }, // list filters from users column selection
lastInRow: { type:Boolean, required:true },
joins: { type:Array, required:true }, // list joins
orders: { type:Array, required:true }, // list orders
relationId: { type:String, required:true }, // list query base relation ID
rowCount: { type:Number, required:true }, // list total row count
show: { type:Boolean, required:true }
},
emits:[
'close','del-aggregator','del-order','set-aggregator',
Expand All @@ -176,9 +176,16 @@ let MyListColumnBatch = {
}
},
computed:{
aggregatorProcessed:{
get() { return typeof this.aggregator !== 'undefined' ? this.aggregator : ''; },
set(v) { this.$emit(v === '' ? 'del-aggregator' : 'set-aggregator', v); }
aggregatorInput:{
get() {
return this.aggrColumn !== null &&
typeof this.columnIdMapAggr[this.aggrColumn.id] !== 'undefined'
? this.columnIdMapAggr[this.aggrColumn.id] : '';
},
set(v) {
if(v === '') this.$emit('del-aggregator',this.aggrColumn.id,null);
else this.$emit('set-aggregator',this.aggrColumn.id,v);
}
},

// returns column of the column batch that is used for filtering (null if none is available)
Expand Down Expand Up @@ -215,7 +222,7 @@ let MyListColumnBatch = {
},

// simple
canAggregate: (s) => s.getFirstColumnUsableAsAggregator(s.columnBatch,s.columns) !== null,
aggrColumn: (s) => s.getFirstColumnUsableAsAggregator(s.columnBatch,s.columns),
canOpen: (s) => s.rowCount > 1 || s.isFiltered,
showFilterAny: (s) => s.showFilterItems || s.showFilterText,
showFilterItems:(s) => s.values.length != 0,
Expand Down
7 changes: 1 addition & 6 deletions www/stores/storeLocal.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,6 @@ const MyStoreLocal = {
set('tokenKeep',payload);
},
schemaTimestamp(state,payload) {
// if schema timestamp changed from last known one, reset dependent data
if(state.schemaTimestamp !== payload) {
state.fieldIdMapOption = {};
set('fieldIdMapOption',{});
}
state.schemaTimestamp = payload;
set('schemaTimestamp',payload);
}
Expand Down Expand Up @@ -150,7 +145,7 @@ let init = function() {
if(typeof value !== 'undefined' && value !== null)
MyStoreLocal.state[k] = JSON.parse(value);
}
} ()
}();

let set = function(name,value) {
if(typeof value !== 'undefined')
Expand Down

0 comments on commit a698c2d

Please sign in to comment.