Skip to content

Commit

Permalink
fix: metadata drag fill (#6914)
Browse files Browse the repository at this point in the history
* fix: metadata drag fill

* feat: optimize code

* feat: optimize code

---------

Co-authored-by: 杨国璇 <[email protected]>
  • Loading branch information
YangGuoXuan-0503 and 杨国璇 authored Oct 17, 2024
1 parent b9ec368 commit db75243
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 24 deletions.
15 changes: 10 additions & 5 deletions frontend/src/metadata/store/server-operator.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getColumnByKey } from '../utils/column';
import { getRowById } from '../utils/table';
import { checkIsDir } from '../utils/row';
import { getFileNameFromRecord } from '../utils/cell';
import ObjectUtils from '../utils/object-utils';

const MAX_LOAD_RECORDS = 100;

Expand Down Expand Up @@ -35,12 +36,16 @@ class ServerOperator {
}
const recordsData = row_ids.map(rowId => {
return { record_id: rowId, record: id_row_updates[rowId], obj_id: id_obj_id[rowId] };
});
window.sfMetadataContext.modifyRecords(repo_id, recordsData, is_copy_paste).then(res => {
}).filter(recordData => recordData.record && !ObjectUtils.isEmpty(recordData.record));
if (recordsData.length === 0) {
callback({ operation });
}).catch(error => {
callback({ error: gettext('Failed to modify records') });
});
} else {
window.sfMetadataContext.modifyRecords(repo_id, recordsData, is_copy_paste).then(res => {
callback({ operation });
}).catch(error => {
callback({ error: gettext('Failed to modify records') });
});
}
break;
}
case OPERATION_TYPE.DELETE_RECORDS: {
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/metadata/utils/object-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class ObjectUtils {
if (!source || !comparison) return false;
return !this.isObjectChanged(source, comparison);
}

static isEmpty = (target) => {
return target && target.constructor === Object && Object.keys(target).length === 0;
};
}

export const hasOwnProperty = (obj, propertyKey) => {
Expand Down
171 changes: 152 additions & 19 deletions frontend/src/metadata/views/table/utils/grid-utils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import dayjs from 'dayjs';
import { getCellValueByColumn, getFileNameFromRecord } from '../../../utils/cell';
import { getCellValueByColumn, getFileNameFromRecord, isCellValueChanged } from '../../../utils/cell';
import { getColumnByIndex, getColumnOriginName } from '../../../utils/column';
import { CellType, NOT_SUPPORT_DRAG_COPY_COLUMN_TYPES, PRIVATE_COLUMN_KEY, TRANSFER_TYPES } from '../../../constants';
import { CellType, NOT_SUPPORT_DRAG_COPY_COLUMN_TYPES, PRIVATE_COLUMN_KEY, TRANSFER_TYPES,
REG_NUMBER_DIGIT, REG_STRING_NUMBER_PARTS, COLUMN_RATE_MAX_NUMBER,
} from '../../../constants';
import { getGroupRecordByIndex } from './group-metrics';
import { convertCellValue } from './convert-utils';
import { Utils } from '../../../../utils/utils';
Expand Down Expand Up @@ -209,14 +211,15 @@ class GridUtils {
const value = draggedRangeMatrix[j - startColumnIdx][idx];
const rule = rules[cellKey];
const fillingValue = rule({ n: fillingIndex - 1, value });

updatedOriginalRows[dragRowId] = Object.assign({}, updatedOriginalRows[dragRowId], { [columnName]: fillingValue });
oldOriginalRows[dragRowId] = Object.assign({}, oldOriginalRows[dragRowId], { [columnName]: dragRow[columnName] });
const update = updatedOriginalRows[dragRowId];
const oldUpdate = oldOriginalRows[dragRowId];

updatedRows[dragRowId] = Object.assign({}, updatedRows[dragRowId], update);
oldRows[dragRowId] = Object.assign({}, oldRows[dragRowId], oldUpdate);
if (isCellValueChanged(fillingValue, dragRow[columnName], type)) {
updatedOriginalRows[dragRowId] = Object.assign({}, updatedOriginalRows[dragRowId], { [columnName]: fillingValue });
oldOriginalRows[dragRowId] = Object.assign({}, oldOriginalRows[dragRowId], { [columnName]: dragRow[columnName] });
const update = updatedOriginalRows[dragRowId];
const oldUpdate = oldOriginalRows[dragRowId];

updatedRows[dragRowId] = Object.assign({}, updatedRows[dragRowId], update);
oldRows[dragRowId] = Object.assign({}, oldRows[dragRowId], oldUpdate);
}
}
}
currentGroupRowIndex++;
Expand Down Expand Up @@ -260,21 +263,21 @@ class GridUtils {
case CellType.DATE: {
let format = data && data.format && data.format.indexOf('HH:mm') > -1 ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD';
let value0 = valueList[0];
let yearTolerance = this.getYearTolerance(valueList);
let yearTolerance = this._getYearTolerance(valueList);
if (yearTolerance) {
ruleMatrixItem = ({ n }) => {
return dayjs(value0).add(n * yearTolerance, 'years').format(format);
};
break;
}
let monthTolerance = this.getMonthTolerance(valueList);
let monthTolerance = this._getMonthTolerance(valueList);
if (monthTolerance) {
ruleMatrixItem = ({ n }) => {
return dayjs(value0).add(n * monthTolerance, 'months').format(format);
};
break;
}
let dayTolerance = this.getDayTolerance(valueList);
let dayTolerance = this._getDayTolerance(valueList);
if (dayTolerance) {
ruleMatrixItem = ({ n }) => {
let time = n * dayTolerance + this.getDateStringValue(value0);
Expand All @@ -285,15 +288,15 @@ class GridUtils {
break;
}
case CellType.NUMBER: {
ruleMatrixItem = this.getLeastSquares(valueList);
ruleMatrixItem = this._getLeastSquares(valueList);
break;
}
case CellType.TEXT: {
ruleMatrixItem = this._getTextRule(valueList);
break;
}
case CellType.RATE: {
ruleMatrixItem = this.getRatingLeastSquares(valueList, data);
ruleMatrixItem = this._getRatingLeastSquares(valueList, data);
break;
}
default: {
Expand All @@ -312,7 +315,7 @@ class GridUtils {
return dateObject.isValid() ? dateObject.valueOf() : 0;
}

getYearTolerance(dateList) {
_getYearTolerance(dateList) {
let date0 = dayjs(dateList[0]);
let date1 = dayjs(dateList[1]);
if (!date0.isValid() || !date1.isValid()) {
Expand All @@ -334,7 +337,7 @@ class GridUtils {
return isYearArithmeticSequence ? tolerance : 0;
}

getMonthTolerance(dateList) {
_getMonthTolerance(dateList) {
let date0 = dayjs(dateList[0]);
let date1 = dayjs(dateList[1]);
if (!date0.isValid() || !date1.isValid()) {
Expand All @@ -355,7 +358,7 @@ class GridUtils {
return isMonthArithmeticSequence ? tolerance : 0;
}

getDayTolerance(dateList) {
_getDayTolerance(dateList) {
let date0 = this.getDateStringValue(dateList[0]);
let tolerance = this.getDateStringValue(dateList[1]) - date0;
let isDayArithmeticSequence = dateList.every((date, i) => {
Expand All @@ -367,7 +370,7 @@ class GridUtils {
return isDayArithmeticSequence ? tolerance : 0;
}

getLeastSquares(numberList) {
_getLeastSquares(numberList) {
let slope;
let intercept;
let xAverage;
Expand Down Expand Up @@ -405,6 +408,136 @@ class GridUtils {
};
}

_isArithmeticSequence(numberList) {
let number0 = numberList[0];
let tolerance = numberList[1] - number0;
let func = (v, n) => {
return v === n * (tolerance) + number0;
};
return numberList.every(func);
}

_getTextItemStructureInfo(textItem) {
let validTextItem = textItem || '';
let lastNumberPosition = -1;
let lastNumber = validTextItem;
let valueList = validTextItem.match(REG_STRING_NUMBER_PARTS) || [];
for (let i = valueList.length - 1; i > -1; i--) {
let valueItem = valueList[i];
if (REG_NUMBER_DIGIT.test(valueItem)) {
lastNumberPosition = i;
lastNumber = valueItem;
break;
}
}
if (lastNumberPosition !== -1) {
valueList[lastNumberPosition] = '-|*|-sf-metadata-|*|-';
}

return { lastNumberPosition, lastNumber, structure: valueList.join('') };
}

_getTextFillNumberRule(valueList, lastNumber, lastNumberPosition, fillFunc) {
let isStartWith0 = lastNumber.startsWith('0');
return ({ n }) => {
let fillValue = fillFunc ? fillFunc({ lastNumber, n }) : '';
if (isStartWith0 && fillValue.length < lastNumber.length) {
fillValue = '0'.repeat(lastNumber.length - fillValue.length) + fillValue;
}
valueList[lastNumberPosition] = fillValue;
return valueList.join('');
};
}

_getTextRule(textList) {
let isAllNotIncludeNumber = textList.every(item => !REG_NUMBER_DIGIT.test(item || ''));
if (isAllNotIncludeNumber) {
return NORMAL_RULE;
}
if (textList.length === 1) {
let valueList = textList[0].match(REG_STRING_NUMBER_PARTS);
let { lastNumberPosition, lastNumber } = this._getTextItemStructureInfo(textList[0]);
return this._getTextFillNumberRule(valueList, lastNumber, lastNumberPosition, ({ lastNumber, n }) => {
let lastNumberValue = parseInt(lastNumber, 10);
return (lastNumberValue + n) + '';
});
}
// isStructureConsistent: the last number part is not equal, other is equal
let structureList = textList.map((text) => this._getTextItemStructureInfo(text));
let firstStructure = structureList[0];
let isStructureConsistent = structureList.every(structure => structure['lastNumberPosition'] === firstStructure['lastNumberPosition'] && structure['structure'] === firstStructure['structure']);
if (isStructureConsistent) {
let numberList = structureList.map(structure => parseInt(structure.lastNumber, 10));
if (this._isArithmeticSequence(numberList)) {
let valueList = textList[0].match(REG_STRING_NUMBER_PARTS);
let secondStructure = structureList[1];
let secondStructureLastNumberValue = parseInt(secondStructure['lastNumber'], 10);
return this._getTextFillNumberRule(valueList, firstStructure['lastNumber'], firstStructure['lastNumberPosition'], ({ lastNumber, n }) => {
let lastNumberValue = parseInt(lastNumber, 10);
return (n * (secondStructureLastNumberValue - lastNumberValue) + lastNumberValue) + '';
});
}
return NORMAL_RULE;
}
return ({ value, n }) => {
if (REG_NUMBER_DIGIT.test(value || '')) {
let valueList = value.match(REG_STRING_NUMBER_PARTS);
let { lastNumberPosition, lastNumber } = this._getTextItemStructureInfo(value);
let isStartWith0 = lastNumber.startsWith('0');
let lastNumberValue = parseInt(lastNumber, 10);
let fillValue = (lastNumberValue + Math.floor(n / textList.length)) + '';
if (isStartWith0 && fillValue.length < lastNumber.length) {
fillValue = '0'.repeat(lastNumber.length - fillValue.length) + fillValue;
}
valueList[lastNumberPosition] = fillValue;
return valueList.join('');
}
return value;
};
}

_getRatingLeastSquares(numberList, data) {
const { rate_max_number = COLUMN_RATE_MAX_NUMBER[4].name } = data || {};
let slope;
let intercept;
let xAverage;
let yAverage;
let xSum = 0;
let ySum = 0;
let xSquareSum = 0;
let xySum = 0;
let validCellsLen = 0;
let emptyCellPositions = [];
numberList.forEach((v, i) => {
if (v !== undefined && v !== null && v !== '') {
validCellsLen++;
xSum += i;
ySum += v;
xySum += (v * i);
xSquareSum += Math.pow(i, 2);
} else {
emptyCellPositions.push(i);
}
});
if (validCellsLen < 2) {
return NORMAL_RULE;
}
xAverage = xSum / validCellsLen;
yAverage = ySum / validCellsLen;
slope = (xySum - validCellsLen * xAverage * yAverage) / (xSquareSum - validCellsLen * Math.pow(xAverage, 2));
intercept = yAverage - slope * xAverage;
return ({ n }) => {
if (emptyCellPositions.length && emptyCellPositions.includes(n % numberList.length)) {
return '';
}
let y = n * slope + intercept;
const value = Number(parseFloat(y).toFixed(0));
if (value > rate_max_number) return rate_max_number;
if (value < 0) return 0;
return value;
};
}

}

export default GridUtils;

0 comments on commit db75243

Please sign in to comment.