1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-12 21:30:39 +00:00
Files
seahub/frontend/src/metadata/metadata-view/_basic/utils/group/group-row.js
2024-08-16 20:30:55 +08:00

305 lines
10 KiB
JavaScript

import { DateUtils } from '../date';
import {
sortDate,
sortText,
sortNumber,
sortCheckbox,
sortCollaborator,
sortSingleSelect,
sortMultipleSelect,
} from '../sort/sort-column';
import { MAX_GROUP_LEVEL } from '../../constants/group';
import {
CellType,
DATE_COLUMN_OPTIONS,
MULTIPLE_CELL_VALUE_COLUMN_TYPE_MAP,
SINGLE_CELL_VALUE_COLUMN_TYPE_MAP,
} from '../../constants/column';
import {
SORT_COLUMN_OPTIONS,
SORT_TYPE,
TEXT_SORTER_COLUMN_TYPES,
NUMBER_SORTER_COLUMN_TYPES,
} from '../../constants/sort';
import { deleteInvalidGroupby } from './core';
import { getGeolocationByGranularity, getCollaboratorsNames, getCellValueByColumn, isValidCellValue } from '../cell';
const _getFormattedCellValue = (cellValue, groupby) => {
const { column, count_type: countType } = groupby;
const { type: columnType } = column;
switch (columnType) {
case CellType.TEXT:
case CellType.LAST_MODIFIER:
case CellType.CREATOR: {
return cellValue || null;
}
case CellType.DATE:
case CellType.CTIME:
case CellType.MTIME: {
return DateUtils.getDateByGranularity(cellValue, countType) || null;
}
case CellType.NUMBER: {
return (cellValue || cellValue === 0) ? cellValue : null;
}
case CellType.CHECKBOX: {
return !!cellValue;
}
case CellType.SINGLE_SELECT: {
return cellValue || null;
}
case CellType.MULTIPLE_SELECT: {
return Array.isArray(cellValue) ? cellValue : [];
}
case CellType.COLLABORATOR: {
return Array.isArray(cellValue) ? cellValue : [];
}
case CellType.GEOLOCATION: {
return getGeolocationByGranularity(cellValue, countType);
}
default: {
return null;
}
}
};
const _getStrCellValue = (cellValue, columnType) => {
let sCellValue = null;
if (SINGLE_CELL_VALUE_COLUMN_TYPE_MAP[columnType]) {
sCellValue = typeof cellValue === 'string' ? cellValue : String(cellValue);
} else if (MULTIPLE_CELL_VALUE_COLUMN_TYPE_MAP[columnType]) {
sCellValue = [...cellValue].sort().toString();
}
return sCellValue;
};
const _findGroupIndexWithMultipleGroupbys = (sCellValue, cellValue2GroupIndexMap, groupsLength) => {
const target = cellValue2GroupIndexMap[sCellValue];
if (target && target.index > -1) {
return target.index;
}
// eslint-disable-next-line
cellValue2GroupIndexMap[sCellValue] = {};
// eslint-disable-next-line
cellValue2GroupIndexMap[sCellValue].subgroups = {};
// eslint-disable-next-line
cellValue2GroupIndexMap[sCellValue].index = groupsLength;
return -1;
};
const _findGroupIndex = (sCellValue, cellValue2GroupIndexMap, groupsLength) => {
const index = cellValue2GroupIndexMap[sCellValue];
if (index > -1) {
return index;
}
// eslint-disable-next-line
cellValue2GroupIndexMap[sCellValue] = groupsLength;
return -1;
};
const getSortedGroups = (groups, groupbys, level, collaborators = []) => {
const sortFlag = 0;
const { column, sort_type } = groupbys[level];
const { type: columnType, data: columnData } = column;
const normalizedSortType = sort_type || SORT_TYPE.UP;
let option_id_index_map = {};
if (columnType === CellType.SINGLE_SELECT || columnType === CellType.MULTIPLE_SELECT) {
const { options } = columnData || {};
if (Array.isArray(options)) {
options.forEach((option, index) => {
option_id_index_map[option.id] = index;
});
}
}
groups.sort((currGroupRow, nextGroupRow) => {
let { cell_value: currCellVal } = currGroupRow;
let { cell_value: nextCellVal } = nextGroupRow;
if (SORT_COLUMN_OPTIONS.includes(columnType)) {
let sortResult;
if (TEXT_SORTER_COLUMN_TYPES.includes(columnType)) {
sortResult = sortText(currCellVal, nextCellVal, normalizedSortType);
} else if (DATE_COLUMN_OPTIONS.includes(columnType)) {
sortResult = sortDate(currCellVal, nextCellVal, normalizedSortType);
} else if (NUMBER_SORTER_COLUMN_TYPES.includes(columnType)) {
sortResult = sortNumber(currCellVal, nextCellVal, normalizedSortType);
} else if (columnType === CellType.CHECKBOX) {
sortResult = sortCheckbox(currCellVal, nextCellVal, normalizedSortType);
} else if (columnType === CellType.COLLABORATOR) {
let currCollaborators = currCellVal;
let nextCollaborators = nextCellVal;
if (collaborators) {
currCollaborators = getCollaboratorsNames(currCollaborators, collaborators);
nextCollaborators = getCollaboratorsNames(nextCollaborators, collaborators);
}
sortResult = sortCollaborator(currCollaborators, nextCollaborators, normalizedSortType);
} else if (columnType === CellType.SINGLE_SELECT) {
sortResult = sortSingleSelect(currCellVal, nextCellVal, { sort_type: normalizedSortType, option_id_index_map });
} else if (columnType === CellType.MULTIPLE_SELECT) {
sortResult = sortMultipleSelect(currCellVal, nextCellVal, { sort_type: normalizedSortType, option_id_index_map });
}
return sortFlag || sortResult;
}
const isValidCurrCellVal = isValidCellValue(currCellVal);
const isValidNextCellVal = isValidCellValue(nextCellVal);
if (!isValidCurrCellVal && !isValidNextCellVal) return 0;
if (!isValidCurrCellVal) return 1;
if (!isValidNextCellVal) return -1;
return 0;
});
// for nested group.
const isNestedGroup = Array.isArray(groups[0].subgroups) && groups[0].subgroups.length > 0;
if (isNestedGroup) {
const nextLevel = level + 1;
// eslint-disable-next-line
groups = groups.map((group) => {
const sortedSubgroups = getSortedGroups(group.subgroups, groupbys, nextLevel, collaborators);
return {
...group,
subgroups: sortedSubgroups,
};
});
}
return groups;
};
const groupRowsWithMultipleGroupbys = (groupbys, rows, collaborators) => {
const validGroupbys = groupbys.length > MAX_GROUP_LEVEL
? groupbys.slice(0, MAX_GROUP_LEVEL)
: [...groupbys];
let groups = [];
let cellValue2GroupIndexMap = {};
rows.forEach((row) => {
const rowId = row._id;
let updatedGroup;
let updateCellValue2GroupIndexMap;
for (let level = 0; level < validGroupbys.length; level++) {
const currentGroupby = validGroupbys[level];
const { column, column_key } = currentGroupby;
const { type: columnType } = column;
const cellValue = getCellValueByColumn(row, column);
const formattedValue = _getFormattedCellValue(cellValue, currentGroupby);
const sCellValue = _getStrCellValue(formattedValue, columnType);
const group = {
cell_value: formattedValue,
original_cell_value: cellValue,
row_ids: null,
column_key,
subgroups: [],
summaries: {},
};
if (level === 0) {
let groupedRowIndex = _findGroupIndexWithMultipleGroupbys(sCellValue, cellValue2GroupIndexMap, groups.length);
updateCellValue2GroupIndexMap = cellValue2GroupIndexMap[sCellValue].subgroups;
if (groupedRowIndex < 0) {
groups.push(group);
updatedGroup = groups[groups.length - 1];
} else {
updatedGroup = groups[groupedRowIndex];
}
} else {
let groupedRowIndex = _findGroupIndexWithMultipleGroupbys(sCellValue, updateCellValue2GroupIndexMap, updatedGroup.subgroups.length);
updateCellValue2GroupIndexMap = updateCellValue2GroupIndexMap[sCellValue].subgroups;
if (groupedRowIndex < 0) {
updatedGroup.subgroups.push(group);
updatedGroup = updatedGroup.subgroups[updatedGroup.subgroups.length - 1];
} else {
updatedGroup = updatedGroup.subgroups[groupedRowIndex];
}
// update row_ids in the deepest group.
if (level === validGroupbys.length - 1) {
if (!updatedGroup.row_ids) {
updatedGroup.row_ids = [rowId];
} else {
updatedGroup.row_ids.push(rowId);
}
}
}
}
});
groups = getSortedGroups(groups, validGroupbys, 0, collaborators);
return groups;
};
/**
* Group table rows
* @param {array} groupbys e.g. [{ column_key, count_type, column, ... }, ...]
* @param {array} rows e.g. [{ _id, ... }, ...]
* @param {array} collaborators e.g. [ collaborator, ... ]
* @returns groups: [{
* cell_value, original_cell_value, column_key,
row_ids, subgroups, summaries, ...}, ...], array
*/
const groupTableRows = (groupbys, rows, collaborators = []) => {
if (groupbys.length === 0) {
return [];
}
if (groupbys.length > 1) {
return groupRowsWithMultipleGroupbys(groupbys, rows, collaborators);
}
const groupby = groupbys[0];
const { column_key, column } = groupby;
const { type: columnType } = column;
let groups = [];
let cellValue2GroupIndexMap = {};
rows.forEach((r) => {
const cellValue = getCellValueByColumn(r, column);
const formattedValue = _getFormattedCellValue(cellValue, groupby);
const cellValueStr = _getStrCellValue(formattedValue, columnType);
let groupedRowIndex = _findGroupIndex(cellValueStr, cellValue2GroupIndexMap, groups.length);
if (groupedRowIndex > -1) {
groups[groupedRowIndex].row_ids.push(r._id);
} else {
groups.push({
cell_value: formattedValue,
original_cell_value: cellValue,
column_key,
row_ids: [r._id],
subgroups: null,
summaries: {},
});
}
});
// sort groups
groups = getSortedGroups(groups, groupbys, 0, collaborators);
return groups;
};
/**
* Group view rows
* @param {array} groupbys e.g. [{ column_key, count_type, column, ... }, ...]
* @param {object} table e.g. { id_row_map, ... }
* @param {array} rowsIds e.g. [ row._id, ...]
* @param {array} value e.g. { collaborators }
* @returns groups: [{
* cell_value, original_cell_value, column_key,
row_ids, subgroups, summaries, ...}, ...], array
*/
const getGroupRows = (table, rows, groupbys, { collaborators }) => {
if (rows.length === 0) return [];
if (groupbys.length === 0) return rows;
let validGroupbys = [];
try {
validGroupbys = deleteInvalidGroupby(groupbys, table.columns);
} catch (err) {
validGroupbys = [];
}
return groupTableRows(validGroupbys, rows, collaborators);
};
export {
groupTableRows,
getGroupRows,
};