@@ -1034,4 +1034,139 @@ describe('OpenAPI SelectionController (e2e)', () => {
10341034 undefined ,
10351035 ] ) ;
10361036 } ) ;
1037+
1038+ describe ( 'paste with projection' , ( ) => {
1039+ let projectionTable : ITableFullVo ;
1040+
1041+ beforeEach ( async ( ) => {
1042+ // Create a table with 4 fields: A, B, C, D
1043+ projectionTable = await createTable ( baseId , {
1044+ name : 'projection-table' ,
1045+ fields : [
1046+ { name : 'Field A' , type : FieldType . SingleLineText } ,
1047+ { name : 'Field B' , type : FieldType . SingleLineText } ,
1048+ { name : 'Field C' , type : FieldType . SingleLineText } ,
1049+ { name : 'Field D' , type : FieldType . SingleLineText } ,
1050+ ] ,
1051+ records : [
1052+ { fields : { 'Field A' : 'A1' , 'Field B' : 'B1' , 'Field C' : 'C1' , 'Field D' : 'D1' } } ,
1053+ { fields : { 'Field A' : 'A2' , 'Field B' : 'B2' , 'Field C' : 'C2' , 'Field D' : 'D2' } } ,
1054+ ] ,
1055+ } ) ;
1056+ } ) ;
1057+
1058+ afterEach ( async ( ) => {
1059+ await permanentDeleteTable ( baseId , projectionTable . id ) ;
1060+ } ) ;
1061+
1062+ it ( 'should paste correctly when projection order is shuffled' , async ( ) => {
1063+ const fieldA = projectionTable . fields . find ( ( f ) => f . name === 'Field A' ) ! ;
1064+ const fieldB = projectionTable . fields . find ( ( f ) => f . name === 'Field B' ) ! ;
1065+ const fieldC = projectionTable . fields . find ( ( f ) => f . name === 'Field C' ) ! ;
1066+ const fieldD = projectionTable . fields . find ( ( f ) => f . name === 'Field D' ) ! ;
1067+
1068+ // Projection order is shuffled: D, B, A (skip C)
1069+ // Original order in table: A, B, C, D
1070+ const projection = [ fieldD . id , fieldB . id , fieldA . id ] ;
1071+
1072+ // Paste 3 columns of data: should map to D, B, A respectively
1073+ await apiPaste ( projectionTable . id , {
1074+ viewId : projectionTable . views [ 0 ] . id ,
1075+ content : 'NewD1\tNewB1\tNewA1' ,
1076+ ranges : [
1077+ [ 0 , 0 ] ,
1078+ [ 0 , 0 ] ,
1079+ ] ,
1080+ projection,
1081+ } ) ;
1082+
1083+ const recordsData = await getRecords ( projectionTable . id , {
1084+ viewId : projectionTable . views [ 0 ] . id ,
1085+ fieldKeyType : FieldKeyType . Id ,
1086+ } ) ;
1087+
1088+ const firstRecord = recordsData . data . records [ 0 ] ;
1089+
1090+ // Verify: should update according to projection order
1091+ expect ( firstRecord . fields [ fieldA . id ] ) . toBe ( 'NewA1' ) ; // projection column 3
1092+ expect ( firstRecord . fields [ fieldB . id ] ) . toBe ( 'NewB1' ) ; // projection column 2
1093+ expect ( firstRecord . fields [ fieldC . id ] ) . toBe ( 'C1' ) ; // not in projection, should remain unchanged
1094+ expect ( firstRecord . fields [ fieldD . id ] ) . toBe ( 'NewD1' ) ; // projection column 1
1095+ } ) ;
1096+
1097+ it ( 'should paste correctly when projection order is reversed' , async ( ) => {
1098+ const fieldA = projectionTable . fields . find ( ( f ) => f . name === 'Field A' ) ! ;
1099+ const fieldB = projectionTable . fields . find ( ( f ) => f . name === 'Field B' ) ! ;
1100+ const fieldC = projectionTable . fields . find ( ( f ) => f . name === 'Field C' ) ! ;
1101+ const fieldD = projectionTable . fields . find ( ( f ) => f . name === 'Field D' ) ! ;
1102+
1103+ // Projection completely reversed: D, C, B, A
1104+ const projection = [ fieldD . id , fieldC . id , fieldB . id , fieldA . id ] ;
1105+
1106+ // Paste 2x2 data
1107+ await apiPaste ( projectionTable . id , {
1108+ viewId : projectionTable . views [ 0 ] . id ,
1109+ content : 'NewD1\tNewC1\nNewD2\tNewC2' ,
1110+ ranges : [
1111+ [ 0 , 0 ] ,
1112+ [ 1 , 1 ] ,
1113+ ] ,
1114+ projection,
1115+ } ) ;
1116+
1117+ const recordsData = await getRecords ( projectionTable . id , {
1118+ viewId : projectionTable . views [ 0 ] . id ,
1119+ fieldKeyType : FieldKeyType . Id ,
1120+ } ) ;
1121+
1122+ // Verify first row: column 0 (index 0) maps to D, column 1 (index 1) maps to C
1123+ const firstRecord = recordsData . data . records [ 0 ] ;
1124+ expect ( firstRecord . fields [ fieldA . id ] ) . toBe ( 'A1' ) ; // not in paste range, should remain unchanged
1125+ expect ( firstRecord . fields [ fieldB . id ] ) . toBe ( 'B1' ) ; // not in paste range, should remain unchanged
1126+ expect ( firstRecord . fields [ fieldC . id ] ) . toBe ( 'NewC1' ) ;
1127+ expect ( firstRecord . fields [ fieldD . id ] ) . toBe ( 'NewD1' ) ;
1128+
1129+ // Verify second row
1130+ const secondRecord = recordsData . data . records [ 1 ] ;
1131+ expect ( secondRecord . fields [ fieldA . id ] ) . toBe ( 'A2' ) ;
1132+ expect ( secondRecord . fields [ fieldB . id ] ) . toBe ( 'B2' ) ;
1133+ expect ( secondRecord . fields [ fieldC . id ] ) . toBe ( 'NewC2' ) ;
1134+ expect ( secondRecord . fields [ fieldD . id ] ) . toBe ( 'NewD2' ) ;
1135+ } ) ;
1136+
1137+ it ( 'should paste to correct field when using shuffled projection with column offset' , async ( ) => {
1138+ const fieldA = projectionTable . fields . find ( ( f ) => f . name === 'Field A' ) ! ;
1139+ const fieldB = projectionTable . fields . find ( ( f ) => f . name === 'Field B' ) ! ;
1140+ const fieldC = projectionTable . fields . find ( ( f ) => f . name === 'Field C' ) ! ;
1141+ const fieldD = projectionTable . fields . find ( ( f ) => f . name === 'Field D' ) ! ;
1142+
1143+ // Projection shuffled order: C, A, D
1144+ const projection = [ fieldC . id , fieldA . id , fieldD . id ] ;
1145+
1146+ // Paste to column index 1 (maps to Field A in projection)
1147+ await apiPaste ( projectionTable . id , {
1148+ viewId : projectionTable . views [ 0 ] . id ,
1149+ content : 'UpdatedA1' ,
1150+ ranges : [
1151+ [ 1 , 0 ] ,
1152+ [ 1 , 0 ] ,
1153+ ] ,
1154+ projection,
1155+ } ) ;
1156+
1157+ const recordsData = await getRecords ( projectionTable . id , {
1158+ viewId : projectionTable . views [ 0 ] . id ,
1159+ fieldKeyType : FieldKeyType . Id ,
1160+ } ) ;
1161+
1162+ const firstRecord = recordsData . data . records [ 0 ] ;
1163+
1164+ // Field A should be updated (projection index 1)
1165+ expect ( firstRecord . fields [ fieldA . id ] ) . toBe ( 'UpdatedA1' ) ;
1166+ // Other fields should remain unchanged
1167+ expect ( firstRecord . fields [ fieldB . id ] ) . toBe ( 'B1' ) ;
1168+ expect ( firstRecord . fields [ fieldC . id ] ) . toBe ( 'C1' ) ;
1169+ expect ( firstRecord . fields [ fieldD . id ] ) . toBe ( 'D1' ) ;
1170+ } ) ;
1171+ } ) ;
10371172} ) ;
0 commit comments