2022-04-01 20:14:41 +00:00
|
|
|
/**
|
|
|
|
* This file contains logic moved from BaseView.js and ported to TS.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import {GristDoc} from 'app/client/components/GristDoc';
|
|
|
|
import {getDocIdHash, RichPasteObject} from 'app/client/lib/tableUtil';
|
|
|
|
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
|
|
|
import {UserAction} from 'app/common/DocActions';
|
|
|
|
import {isFullReferencingType} from 'app/common/gristTypes';
|
|
|
|
import {SchemaTypes} from 'app/common/schema';
|
|
|
|
import {BulkColValues} from 'app/plugin/GristData';
|
2023-12-18 17:50:57 +00:00
|
|
|
import {ViewSectionRec} from "app/client/models/entities/ViewSectionRec";
|
2022-04-01 20:14:41 +00:00
|
|
|
import omit = require('lodash/omit');
|
2023-12-18 17:50:57 +00:00
|
|
|
import pick = require('lodash/pick');
|
2022-04-01 20:14:41 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Given a 2-d paste column-oriented paste data and target cols, transform the data to omit
|
|
|
|
* fields that shouldn't be pasted over and extract rich paste data if available.
|
|
|
|
* When pasting into empty columns, also update them with options from the source column.
|
|
|
|
* `data` is a column-oriented 2-d array of either
|
|
|
|
* plain strings or rich paste data returned by `tableUtil.parsePasteHtml`.
|
|
|
|
* `fields` are the target fields being pasted into.
|
|
|
|
*/
|
|
|
|
export async function parsePasteForView(
|
|
|
|
data: Array<string | RichPasteObject>[], fields: ViewFieldRec[], gristDoc: GristDoc
|
|
|
|
): Promise<BulkColValues> {
|
|
|
|
const result: BulkColValues = {};
|
|
|
|
const actions: UserAction[] = [];
|
|
|
|
const thisDocIdHash = getDocIdHash();
|
|
|
|
|
|
|
|
data.forEach((col, idx) => {
|
|
|
|
const field = fields[idx];
|
|
|
|
const colRec = field?.column();
|
|
|
|
if (!colRec || colRec.isRealFormula() || colRec.disableEditData()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const parser = field.createValueParser() || (x => x);
|
|
|
|
let typeMatches = false;
|
|
|
|
if (col[0] && typeof col[0] === "object") {
|
|
|
|
const {colType, docIdHash, colRef} = col[0];
|
|
|
|
const targetType = colRec.type();
|
|
|
|
const docIdMatches = docIdHash === thisDocIdHash;
|
|
|
|
typeMatches = docIdMatches || !isFullReferencingType(colType || "");
|
|
|
|
|
|
|
|
if (targetType !== "Any") {
|
|
|
|
typeMatches = typeMatches && colType === targetType;
|
|
|
|
} else if (docIdMatches && colRef) {
|
|
|
|
// Try copying source column type and options into empty columns
|
|
|
|
const sourceColRec = gristDoc.docModel.columns.getRowModel(colRef);
|
|
|
|
const sourceType = sourceColRec.type();
|
|
|
|
// Check that the source column still exists, has a type other than Text, and the type hasn't changed.
|
|
|
|
// For Text columns, we don't copy over column info so that type guessing can still happen.
|
|
|
|
if (sourceColRec.getRowId() && sourceType !== "Text" && sourceType === colType) {
|
|
|
|
const colInfo: Partial<SchemaTypes["_grist_Tables_column"]> = {
|
|
|
|
type: sourceType,
|
|
|
|
visibleCol: sourceColRec.visibleCol(),
|
|
|
|
// Conditional formatting rules are not copied right now, that's a bit more complicated
|
|
|
|
// and copying the formula may or may not be desirable.
|
|
|
|
widgetOptions: JSON.stringify(omit(sourceColRec.widgetOptionsJson(), "rulesOptions")),
|
|
|
|
};
|
|
|
|
actions.push(
|
|
|
|
["UpdateRecord", "_grist_Tables_column", colRec.getRowId(), colInfo],
|
|
|
|
["MaybeCopyDisplayFormula", colRef, colRec.getRowId()],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result[colRec.colId()] = col.map(v => {
|
|
|
|
if (v) {
|
|
|
|
if (typeof v === "string") {
|
|
|
|
return parser(v);
|
|
|
|
}
|
|
|
|
if (typeMatches && v.hasOwnProperty('rawValue')) {
|
|
|
|
return v.rawValue;
|
|
|
|
}
|
|
|
|
if (v.hasOwnProperty('displayValue')) {
|
|
|
|
return parser(v.displayValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
if (actions.length) {
|
|
|
|
await gristDoc.docData.sendActions(actions);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2023-12-18 17:50:57 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get default values for a new record so that it continues to satisfy the current linking filters.
|
|
|
|
* Exclude formula columns since we can't set their values.
|
|
|
|
*/
|
|
|
|
export function getDefaultColValues(viewSection: ViewSectionRec): Record<string, any> {
|
|
|
|
const linkingState = viewSection.linkingState.peek();
|
|
|
|
if (!linkingState) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
const dataColIds = viewSection.columns.peek()
|
|
|
|
.filter(col => !col.isRealFormula.peek())
|
|
|
|
.map(col => col.colId.peek());
|
|
|
|
return pick(linkingState.getDefaultColValues(), dataColIds);
|
|
|
|
}
|