From 1b584f46d3906533c7ba0a90b7cc048d94a5ebe5 Mon Sep 17 00:00:00 2001 From: patrick blume Date: Tue, 29 Oct 2024 10:01:39 +0100 Subject: [PATCH 1/6] Minor fixes Adapt column size when adding template, deleting building block Adapt conversion possibilities of building blocks --- src/Client/OfficeInterop/OfficeInterop.fs | 255 +++++++++++++----- .../BuildingBlock/CellConvertComponent.fs | 26 +- 2 files changed, 203 insertions(+), 78 deletions(-) diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index da047248..7bbdc514 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -117,6 +117,18 @@ module OfficeInteropExtensions = name = name ) + /// + /// Delete an existing column at the given index + /// + /// + /// + /// + /// + /// + static member deleteColumn (index: float) (excelTable: Table) = + let col = excelTable.columns.getItemAt index + col.delete() + /// /// Add only the row values of the column you are adding /// @@ -225,7 +237,6 @@ module OfficeInteropExtensions = member this.ToExcelValues() = let table = this - // Cancel if there are no columns if table.Columns.Length = 0 then ResizeArray() @@ -558,7 +569,7 @@ let tryGetActiveAnnotationTable (context: RequestContext) = let _ = context.workbook.load(propertyNames=U2.Case2 (ResizeArray[|"tables"|])) let activeWorksheet = context.workbook.worksheets.getActiveWorksheet().load(U2.Case1 "position") let tables = context.workbook.tables - let _ = tables.load(propertyNames=U2.Case2 (ResizeArray[|"items"; "worksheet"; "name"; "position"; "values"|])) + let _ = tables.load(propertyNames=U2.Case2 (ResizeArray[|"items"; "worksheet"; "name"; "position"; "style"; "values"|])) let! table = context.sync().``then``(fun _ -> let activeWorksheetPosition = activeWorksheet.position @@ -1448,7 +1459,7 @@ let joinTable (tableToAdd: ArcTable, options: TableJoinOptions option) = arcTable.Value.Join(tableToAdd, ?index=index, ?joinOptions=options, forceReplace=true) let tableValues = arcTable.Value.ToExcelValues() |> Array.ofSeq - let (headers, body) = Array.ofSeq(tableValues.[0]), tableValues.[1..] + let (headers, _) = Array.ofSeq(tableValues.[0]), tableValues.[1..] let newTableRange = excelTable.getRange() @@ -1494,18 +1505,9 @@ let joinTable (tableToAdd: ArcTable, options: TableJoinOptions option) = newTable.columns.load(propertyNames = U2.Case2 (ResizeArray["name"; "items"])) |> ignore newBodyRange.load(propertyNames = U2.Case2 (ResizeArray["name"; "columnCount"; "values"])) - do! context.sync().``then``(fun _ -> + do! context.sync().``then``(fun _ -> ()) - newBodyRange.values <- ResizeArray body - newBodyRange.format.autofitColumns() - newBodyRange.format.autofitRows() - - newTable.columns.items - |> Array.ofSeq - |> Array.iter (fun column -> - if ARCtrl.Spreadsheet.ArcTable.helperColumnStrings |> List.exists (fun cName -> column.name.StartsWith cName) then - column.getRange().columnHidden <- true) - ) + do! ExcelHelper.adoptTableFormats(newTable, context, true) return [InteropLogging.Msg.create InteropLogging.Warning $"Joined template {tableToAdd.Name} to table {excelTable.name}!"] else @@ -1604,6 +1606,33 @@ let getSelectedBuildingBlock (table: Table) (context: RequestContext) = ) } +/// +/// Returns a ResizeArray of indices and header names for the selected building block +/// The indices are rebased to the excel annotation table. +/// +/// +/// +let getSelectedBuildingBlockCell (table: Table) (context: RequestContext) = + promise { + + let selectedRange = context.workbook.getSelectedRange().load(U2.Case2 (ResizeArray[|"columnIndex"; "rowIndex";|])) + + let headerRange = table.getHeaderRowRange() + let _ = headerRange.load(U2.Case2 (ResizeArray [|"columnCount"; "columnIndex"; "rowIndex"; "values";|])) |> ignore + + return! context.sync().``then``(fun _ -> + let rebasedIndex = selectedRange.columnIndex - headerRange.columnIndex |> int + if rebasedIndex < 0 || rebasedIndex >= (int headerRange.columnCount) then + failwith "Cannot select building block outside of annotation table!" + let headers: string [] = [|for v in headerRange.values.[0] do v.Value :?> string|] + let selectedHeader = rebasedIndex, headers.[rebasedIndex] + let buildingBlockGroups = groupToBuildingBlocks headers + let selectedBuildingBlock = + buildingBlockGroups.Find(fun bb -> bb.Contains selectedHeader) + selectedBuildingBlock, selectedRange.rowIndex + ) + } + /// /// Select a building block, shifted by adaptedIndex from the selected building block /// @@ -1650,6 +1679,10 @@ let removeSelectedAnnotationBlock () = log $"delete column {i}" column.delete() + do! context.sync().``then``(fun _ -> ()) + + do! ExcelHelper.adoptTableFormats(excelTable, context, true) + return [InteropLogging.Msg.create InteropLogging.Info $"The building block associated with column {snd (selectedBuildingBlock.Item 0)} has been deleted"] | Result.Error msgs -> return msgs } @@ -1658,12 +1691,10 @@ let removeSelectedAnnotationBlock () = /// /// Get the main column of the arc table of the selected building block of the active annotation table /// -let getArcMainColumn (excelTable:Table) (context: RequestContext)= +let getArcMainColumn (excelTable: Table) (arcTable: ArcTable) (context: RequestContext)= promise { let! selectedBlock = getSelectedBuildingBlock excelTable context - let! arcTable = ArcTable.tryGetFromExcelTable(excelTable, context) - let protoHeaders = excelTable.getHeaderRowRange() let _ = protoHeaders.load(U2.Case2 (ResizeArray(["values"]))) @@ -1684,11 +1715,11 @@ let getArcMainColumn (excelTable:Table) (context: RequestContext)= else failwith "Could not find a fitting arc table index" let targetColumn = - let potColumn = arcTable.Value.GetColumn arcTableIndex + let potColumn = arcTable.GetColumn arcTableIndex if columnName.Contains(potColumn.Header.ToString()) then potColumn else failwith "Could not find a fitting arc table index with matchin name" - return targetColumn + return (targetColumn, arcTableIndex) } /// @@ -1701,59 +1732,70 @@ let tryGetArcMainColumnFromFrontEnd () = match result with | Result.Ok table -> - let! column = getArcMainColumn table context + let! arcTable = ArcTable.tryGetFromExcelTable(table, context) + let! column = getArcMainColumn table arcTable.Value context return Some column | Result.Error _ -> return None } ) +/// +/// Delete columns of at the given indices of the table +/// +/// +/// +let deleteSelectedExcelColumns (selectedColumns: seq) (excelTable: Table) = + // iterate DESCENDING to avoid index shift + for i in Seq.sortByDescending (fun x -> x) selectedColumns do + let column = excelTable.columns.getItemAt(i) + log $"delete column {i}" + column.delete() + /// /// Convert the body of the given column into free text /// /// -let convertToFreeTextColumn (column: CompositeColumn) = - let freeTextCells = column.Cells |> Array.map (fun c -> c.ToFreeTextCell()) - freeTextCells - |> Array.iteri (fun i _ -> column.Cells.[i] <- freeTextCells.[i]) - +let convertToFreeTextCell (arcTable: ArcTable) (columnIndex: int) (column: CompositeColumn) rowIndex = + let header = column.Header + let freeTextCell = column.Cells.[rowIndex].ToFreeTextCell() + let newHeader = + match header with + | header when header.isOutput -> CompositeHeader.Output (IOType.FreeText (header.ToString())) + | header when header.isInput -> CompositeHeader.Input (IOType.FreeText (header.ToString())) + | _ -> CompositeHeader.FreeText (header.ToString()) + arcTable.UpdateCellAt(columnIndex, rowIndex, freeTextCell, true) + arcTable.UpdateHeader(columnIndex, newHeader, false) + /// /// Convert the body of the given column into data /// /// -let convertToDataColumn (column: CompositeColumn) = - let dataCells = column.Cells |> Array.map (fun c -> c.ToDataCell()) - dataCells - |> Array.iteri (fun i _ -> column.Cells.[i] <- dataCells.[i]) +let convertToDataCell (arcTable: ArcTable) (columnIndex: int) (column: CompositeColumn) rowIndex = + let header = column.Header + let dataCell = column.Cells.[rowIndex].ToDataCell() + let newHeader = + match header with + | header when header.isOutput -> CompositeHeader.Output IOType.Data + | header when header.isInput -> CompositeHeader.Input IOType.Data + | _ -> CompositeHeader.FreeText (header.ToString()) + arcTable.UpdateHeader(columnIndex, newHeader, false) + arcTable.UpdateCellAt(columnIndex, rowIndex, dataCell, true) /// /// Convert the body of the given column into unit /// /// -let convertToUnitColumn (column: CompositeColumn) = - let unitCells = column.Cells |> Array.map (fun c -> c.ToUnitizedCell()) - unitCells - |> Array.iteri (fun i _ -> column.Cells.[i] <- unitCells.[i]) +let convertToUnitCell (column: CompositeColumn) rowIndex = + let unitCell = column.Cells.[rowIndex].ToUnitizedCell() + column.Cells.[rowIndex] <- unitCell /// /// Convert the body of the given column into term /// /// -let convertToTermColumn (column: CompositeColumn) = - let termCells = column.Cells |> Array.map (fun c -> c.ToTermCell()) - termCells - |> Array.iteri (fun i _ -> column.Cells.[i] <- termCells.[i]) - -/// -/// Delete columns of at the given indices of the table -/// -/// -/// -let deleteSelectedExcelColumns (selectedColumns: seq) (excelTable: Table) = - // iterate DESCENDING to avoid index shift - for i in Seq.sortByDescending (fun x -> x) selectedColumns do - let column = excelTable.columns.getItemAt(i) - log $"delete column {i}" - column.delete() +let convertToTermCell (column: CompositeColumn) rowIndex = + let termCell = column.Cells.[rowIndex].ToTermCell() + column.Cells.[rowIndex] <- termCell /// /// Add a building block at a specified position to the given table @@ -1762,7 +1804,7 @@ let deleteSelectedExcelColumns (selectedColumns: seq) (excelTable: Table) = /// /// /// -let addBuildingBlockAt (excelIndex: int) (newBB: CompositeColumn) (table: Table) (context: RequestContext)= +let addBuildingBlockCellAt (excelIndex: int) (newBB: CompositeColumn) (table: Table) (context: RequestContext) = promise { let headers = table.getHeaderRowRange() let _ = headers.load(U2.Case2 (ResizeArray [|"values"|])) @@ -1791,6 +1833,43 @@ let addBuildingBlockAt (excelIndex: int) (newBB: CompositeColumn) (table: Table) |> List.iteri (fun ci header -> ExcelHelper.addColumnAndRows (float (excelIndex + ci)) table header bodyValues.[ci] |> ignore) } +type BodyCellType = +| Term +| Unitized +| Text +| Data + +let getSelectedCellType () = + Excel.run(fun context -> + promise { + let! result = tryGetActiveAnnotationTable context + + match result with + | Result.Ok excelTable -> + let! _, rowIndex = getSelectedBuildingBlockCell excelTable context + let! arcTable = ArcTable.tryGetFromExcelTable(excelTable, context) + let! (arcMainColumn, _) = getArcMainColumn excelTable arcTable.Value context + + if (arcMainColumn.Validate false) && rowIndex > 0 then + + let result = + match arcMainColumn with + | amc when amc.Header.ToString() = "Output [Sample Name]" -> None + | amc when amc.Header.ToString() = "Input [Source Name]" -> None + | amc when amc.Cells.[(int rowIndex) - 1].isUnitized -> Some BodyCellType.Unitized + | amc when amc.Cells.[(int rowIndex) - 1].isTerm -> Some BodyCellType.Term + | amc when amc.Cells.[(int rowIndex) - 1].isData -> Some BodyCellType.Data + | amc when amc.Header.isInput && amc.Cells.[(int rowIndex) - 1].isFreeText -> Some BodyCellType.Text + | amc when amc.Header.isOutput && amc.Cells.[(int rowIndex) - 1].isFreeText -> Some BodyCellType.Text + | _ -> None + + return result + else return None + + | Result.Error _ -> return None + } + ) + /// /// This function is used to convert building blocks that can be converted. Data building blocks can be converted into free text, free text into data, /// terms into units and units into terms @@ -1802,28 +1881,78 @@ let convertBuildingBlock () = match result with | Result.Ok excelTable -> - let! selectedBuildingBlock = getSelectedBuildingBlock excelTable context - let excelMainColumnIndex = fst selectedBuildingBlock.[0] - let! arcMainColumn = getArcMainColumn excelTable context + let! selectedBuildingBlock, rowIndex = getSelectedBuildingBlockCell excelTable context + let! arcTable = ArcTable.tryGetFromExcelTable(excelTable, context) + + let! (arcMainColumn, arcIndex) = getArcMainColumn excelTable arcTable.Value context let msgText = - match arcMainColumn with - | amc when amc.Header.isInput -> $"Input column {snd selectedBuildingBlock.[0]} cannot be converted" - | amc when amc.Header.isOutput -> $"Output column {snd selectedBuildingBlock.[0]} cannot be converted" - | _ -> "" + if rowIndex = 0 then "Headers cannot be converted" + else "" match arcMainColumn with - | amc when amc.Cells.[0].isUnitized -> convertToTermColumn amc - | amc when amc.Cells.[0].isTerm -> convertToUnitColumn amc - | amc when amc.Cells.[0].isData -> convertToDataColumn amc - | amc when amc.Cells.[0].isFreeText -> convertToFreeTextColumn amc + | amc when amc.Cells.[(int rowIndex) - 1].isUnitized -> + convertToTermCell amc ((int rowIndex) - 1) + arcTable.Value.UpdateColumn(arcIndex, arcMainColumn.Header, arcMainColumn.Cells) + | amc when amc.Cells.[(int rowIndex) - 1].isTerm -> + convertToUnitCell amc ((int rowIndex) - 1) + arcTable.Value.UpdateColumn(arcIndex, arcMainColumn.Header, arcMainColumn.Cells) + | amc when amc.Cells.[(int rowIndex) - 1].isData -> convertToFreeTextCell arcTable.Value arcIndex amc ((int rowIndex) - 1) + | amc when amc.Cells.[(int rowIndex) - 1].isFreeText -> convertToDataCell arcTable.Value arcIndex amc ((int rowIndex) - 1) | _ -> () - deleteSelectedExcelColumns (selectedBuildingBlock |> Seq.map (fun (i, _) -> i)) excelTable + let name = excelTable.name + let style = excelTable.style + + let newTableRange = excelTable.getRange() + + let newExcelTableValues = arcTable.Value.ToExcelValues() + let _ = newTableRange.load(propertyNames = U2.Case2 (ResizeArray["values"; "columnCount"; "rowCount"])) + + do! context.sync().``then``(fun _ -> + let difference = (newExcelTableValues.Item 0).Count - (int newTableRange.columnCount) + + match difference with + | diff when diff > 0 -> + for i = 0 to diff - 1 do + ExcelHelper.addColumn (newTableRange.columnCount + (float i)) excelTable (i.ToString()) (int newTableRange.rowCount) "" |> ignore + | diff when diff < 0 -> + for i = 0 downto diff + 1 do + ExcelHelper.deleteColumn 0 excelTable + | _ -> () + ) + + let newTableRange = excelTable.getRange() + let _ = newTableRange.load(propertyNames = U2.Case2 (ResizeArray["values"; "columnCount"])) + + let test = + newExcelTableValues + |> Array.ofSeq + |> Array.map (fun item -> + item + |> Array.ofSeq + |> Array.map(fun itemi -> + itemi.Value.ToString() + ) + ) + + do! context.sync().``then``(fun _ -> + excelTable.delete() + newTableRange.values <- newExcelTableValues + ) + + let _ = newTableRange.load(propertyNames = U2.Case2 (ResizeArray["values"; "worksheet"])) do! context.sync().``then``(fun _ -> ()) - do! addBuildingBlockAt excelMainColumnIndex arcMainColumn excelTable context + let activeSheet = newTableRange.worksheet + let _ = activeSheet.load(U2.Case2 (ResizeArray[|"tables"|])) + + do! context.sync().``then``(fun _ -> + let newTable = activeSheet.tables.add(U2.Case1 newTableRange, true) + newTable.name <- name + newTable.style <- style + ) do! ExcelHelper.adoptTableFormats(excelTable, context, true) diff --git a/src/Client/Pages/BuildingBlock/CellConvertComponent.fs b/src/Client/Pages/BuildingBlock/CellConvertComponent.fs index 03a9c6bf..5056b2b9 100644 --- a/src/Client/Pages/BuildingBlock/CellConvertComponent.fs +++ b/src/Client/Pages/BuildingBlock/CellConvertComponent.fs @@ -9,30 +9,26 @@ module private CellConvertComponentHelpers = let getSelectedCellType (setState: Model.BuildingBlock.BodyCellType option -> unit) = promise { - //Write function to access current header state of excel - - let! mainColumn = tryGetArcMainColumnFromFrontEnd () + //Write function to access current state of selected excel cell excel + let! cellType = getSelectedCellType () let result = - match mainColumn with - | Some column when column.Header.isInput -> None - | Some column when column.Header.isOutput -> None - | Some column when column.Cells.[0].isUnitized -> Model.BuildingBlock.BodyCellType.Unitized |> Some - | Some column when column.Cells.[0].isTerm -> Model.BuildingBlock.BodyCellType.Term |> Some - | Some column when column.Cells.[0].isFreeText -> Model.BuildingBlock.BodyCellType.Text |> Some - | Some column when column.Cells.[0].isData -> Model.BuildingBlock.BodyCellType.Data |> Some + match cellType with + | Some BodyCellType.Unitized -> Some Model.BuildingBlock.BodyCellType.Unitized + | Some BodyCellType.Term -> Some Model.BuildingBlock.BodyCellType.Term + | Some BodyCellType.Text -> Some Model.BuildingBlock.BodyCellType.Text + | Some BodyCellType.Data -> Some Model.BuildingBlock.BodyCellType.Data | _ -> None - setState result } let getTargetConversionType (cellType: Model.BuildingBlock.BodyCellType option) = if cellType.IsSome then match cellType.Value with - | Model.BuildingBlock.BodyCellType.Unitized -> Model.BuildingBlock.BodyCellType.Term |> Some - | Model.BuildingBlock.BodyCellType.Term -> Model.BuildingBlock.BodyCellType.Unitized |> Some - | Model.BuildingBlock.BodyCellType.Text -> Model.BuildingBlock.BodyCellType.Data |> Some - | Model.BuildingBlock.BodyCellType.Data -> Model.BuildingBlock.BodyCellType.Text |> Some + | Model.BuildingBlock.BodyCellType.Unitized -> Some Model.BuildingBlock.BodyCellType.Term + | Model.BuildingBlock.BodyCellType.Term -> Some Model.BuildingBlock.BodyCellType.Unitized + | Model.BuildingBlock.BodyCellType.Text -> Some Model.BuildingBlock.BodyCellType.Data + | Model.BuildingBlock.BodyCellType.Data -> Some Model.BuildingBlock.BodyCellType.Text else None type CellConvertComponent = From 005c76c7034bc6fb99c823a21407a02e4b4726bc Mon Sep 17 00:00:00 2001 From: patrick blume Date: Tue, 29 Oct 2024 10:02:17 +0100 Subject: [PATCH 2/6] Nope --- src/Client/OfficeInterop/OfficeInterop.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index 7bbdc514..3a6ed82b 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -1828,7 +1828,7 @@ let addBuildingBlockCellAt (excelIndex: int) (newBB: CompositeColumn) (table: Ta bc |> Array.ofSeq |> Array.map (fun br -> [|U3.Case2 br|] :> IList>)) - + "" headers |> List.iteri (fun ci header -> ExcelHelper.addColumnAndRows (float (excelIndex + ci)) table header bodyValues.[ci] |> ignore) } From ba1e9640c5924edc4fb2300949afd7eedd5dc84e Mon Sep 17 00:00:00 2001 From: patrick blume Date: Tue, 29 Oct 2024 10:02:48 +0100 Subject: [PATCH 3/6] fix --- src/Client/OfficeInterop/OfficeInterop.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index 3a6ed82b..7bbdc514 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -1828,7 +1828,7 @@ let addBuildingBlockCellAt (excelIndex: int) (newBB: CompositeColumn) (table: Ta bc |> Array.ofSeq |> Array.map (fun br -> [|U3.Case2 br|] :> IList>)) - "" + headers |> List.iteri (fun ci header -> ExcelHelper.addColumnAndRows (float (excelIndex + ci)) table header bodyValues.[ci] |> ignore) } From 5514be086c62b508f512bf202816a6c760d59f6b Mon Sep 17 00:00:00 2001 From: patrick blume Date: Tue, 29 Oct 2024 11:39:33 +0100 Subject: [PATCH 4/6] Apply review changes --- src/Client/OfficeInterop/OfficeInterop.fs | 48 +++++-------------- .../BuildingBlock/CellConvertComponent.fs | 18 ++----- 2 files changed, 18 insertions(+), 48 deletions(-) diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index 7bbdc514..49207ef6 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -1756,16 +1756,9 @@ let deleteSelectedExcelColumns (selectedColumns: seq) (excelTable: Table) = /// /// let convertToFreeTextCell (arcTable: ArcTable) (columnIndex: int) (column: CompositeColumn) rowIndex = - let header = column.Header let freeTextCell = column.Cells.[rowIndex].ToFreeTextCell() - let newHeader = - match header with - | header when header.isOutput -> CompositeHeader.Output (IOType.FreeText (header.ToString())) - | header when header.isInput -> CompositeHeader.Input (IOType.FreeText (header.ToString())) - | _ -> CompositeHeader.FreeText (header.ToString()) arcTable.UpdateCellAt(columnIndex, rowIndex, freeTextCell, true) - arcTable.UpdateHeader(columnIndex, newHeader, false) - + /// /// Convert the body of the given column into data /// @@ -1804,7 +1797,7 @@ let convertToTermCell (column: CompositeColumn) rowIndex = /// /// /// -let addBuildingBlockCellAt (excelIndex: int) (newBB: CompositeColumn) (table: Table) (context: RequestContext) = +let addBuildingBlockAt (excelIndex: int) (newBB: CompositeColumn) (table: Table) (context: RequestContext) = promise { let headers = table.getHeaderRowRange() let _ = headers.load(U2.Case2 (ResizeArray [|"values"|])) @@ -1833,12 +1826,6 @@ let addBuildingBlockCellAt (excelIndex: int) (newBB: CompositeColumn) (table: Ta |> List.iteri (fun ci header -> ExcelHelper.addColumnAndRows (float (excelIndex + ci)) table header bodyValues.[ci] |> ignore) } -type BodyCellType = -| Term -| Unitized -| Text -| Data - let getSelectedCellType () = Excel.run(fun context -> promise { @@ -1850,17 +1837,15 @@ let getSelectedCellType () = let! arcTable = ArcTable.tryGetFromExcelTable(excelTable, context) let! (arcMainColumn, _) = getArcMainColumn excelTable arcTable.Value context - if (arcMainColumn.Validate false) && rowIndex > 0 then + if rowIndex > 0 then let result = match arcMainColumn with - | amc when amc.Header.ToString() = "Output [Sample Name]" -> None - | amc when amc.Header.ToString() = "Input [Source Name]" -> None - | amc when amc.Cells.[(int rowIndex) - 1].isUnitized -> Some BodyCellType.Unitized - | amc when amc.Cells.[(int rowIndex) - 1].isTerm -> Some BodyCellType.Term - | amc when amc.Cells.[(int rowIndex) - 1].isData -> Some BodyCellType.Data - | amc when amc.Header.isInput && amc.Cells.[(int rowIndex) - 1].isFreeText -> Some BodyCellType.Text - | amc when amc.Header.isOutput && amc.Cells.[(int rowIndex) - 1].isFreeText -> Some BodyCellType.Text + | amc when amc.Cells.[(int rowIndex) - 1].isUnitized -> Some CompositeCellDiscriminate.Unitized + | amc when amc.Cells.[(int rowIndex) - 1].isTerm -> Some CompositeCellDiscriminate.Term + | amc when amc.Cells.[(int rowIndex) - 1].isData -> Some CompositeCellDiscriminate.Data + | amc when amc.Header.isInput && amc.Header.IsDataColumn && amc.Cells.[(int rowIndex) - 1].isFreeText -> Some CompositeCellDiscriminate.Text + | amc when amc.Header.isOutput && amc.Header.IsDataColumn && amc.Cells.[(int rowIndex) - 1].isFreeText -> Some CompositeCellDiscriminate.Text | _ -> None return result @@ -1925,17 +1910,6 @@ let convertBuildingBlock () = let newTableRange = excelTable.getRange() let _ = newTableRange.load(propertyNames = U2.Case2 (ResizeArray["values"; "columnCount"])) - let test = - newExcelTableValues - |> Array.ofSeq - |> Array.map (fun item -> - item - |> Array.ofSeq - |> Array.map(fun itemi -> - itemi.Value.ToString() - ) - ) - do! context.sync().``then``(fun _ -> excelTable.delete() newTableRange.values <- newExcelTableValues @@ -1954,7 +1928,11 @@ let convertBuildingBlock () = newTable.style <- style ) - do! ExcelHelper.adoptTableFormats(excelTable, context, true) + let! newTable = tryGetActiveAnnotationTable context + + match newTable with + | Result.Ok table -> do! ExcelHelper.adoptTableFormats(table, context, true) + | _ -> () let msg = if String.IsNullOrEmpty(msgText) then $"Converted building block of {snd selectedBuildingBlock.[0]} to unit" diff --git a/src/Client/Pages/BuildingBlock/CellConvertComponent.fs b/src/Client/Pages/BuildingBlock/CellConvertComponent.fs index 912c1687..7b0015a9 100644 --- a/src/Client/Pages/BuildingBlock/CellConvertComponent.fs +++ b/src/Client/Pages/BuildingBlock/CellConvertComponent.fs @@ -5,7 +5,6 @@ open Feliz.Bulma open OfficeInterop.Core open Shared -open ARCtrl.Helper module private CellConvertComponentHelpers = @@ -14,23 +13,16 @@ module private CellConvertComponentHelpers = //Write function to access current state of selected excel cell excel let! cellType = getSelectedCellType () - let result = - match cellType with - | Some BodyCellType.Unitized -> Some Model.BuildingBlock.BodyCellType.Unitized - | Some BodyCellType.Term -> Some Model.BuildingBlock.BodyCellType.Term - | Some BodyCellType.Text -> Some Model.BuildingBlock.BodyCellType.Text - | Some BodyCellType.Data -> Some Model.BuildingBlock.BodyCellType.Data - | _ -> None - setState result + setState cellType } let getTargetConversionType (cellType: CompositeCellDiscriminate option) = if cellType.IsSome then match cellType.Value with - | Model.BuildingBlock.BodyCellType.Unitized -> Some Model.BuildingBlock.BodyCellType.Term - | Model.BuildingBlock.BodyCellType.Term -> Some Model.BuildingBlock.BodyCellType.Unitized - | Model.BuildingBlock.BodyCellType.Text -> Some Model.BuildingBlock.BodyCellType.Data - | Model.BuildingBlock.BodyCellType.Data -> Some Model.BuildingBlock.BodyCellType.Text + | CompositeCellDiscriminate.Unitized -> Some CompositeCellDiscriminate.Term + | CompositeCellDiscriminate.Term -> Some CompositeCellDiscriminate.Unitized + | CompositeCellDiscriminate.Text -> Some CompositeCellDiscriminate.Data + | CompositeCellDiscriminate.Data -> Some CompositeCellDiscriminate.Text else None type CellConvertComponent = From 84eb39c4ae8e198649e87ca1519a90c8201f97ae Mon Sep 17 00:00:00 2001 From: patrick blume Date: Tue, 29 Oct 2024 16:07:20 +0100 Subject: [PATCH 5/6] Implement review changes --- src/Client/OfficeInterop/OfficeInterop.fs | 109 +++++++++++------- .../BuildingBlock/CellConvertComponent.fs | 55 +++++---- 2 files changed, 98 insertions(+), 66 deletions(-) diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index 49207ef6..a613f5d5 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -1587,9 +1587,7 @@ let addAnnotationBlockHandler (newBB: CompositeColumn) = /// let getSelectedBuildingBlock (table: Table) (context: RequestContext) = promise { - let selectedRange = context.workbook.getSelectedRange().load(U2.Case2 (ResizeArray[|"columnIndex"|])) - let headerRange = table.getHeaderRowRange() let _ = headerRange.load(U2.Case2 (ResizeArray [|"columnIndex"; "values"; "columnCount"|])) |> ignore @@ -1633,6 +1631,68 @@ let getSelectedBuildingBlockCell (table: Table) (context: RequestContext) = ) } +/// +/// Get the main column of the arc table of the selected building block of the active annotation table +/// +let getArcMainColumn (excelTable: Table) (arcTable: ArcTable) (context: RequestContext) = + promise { + let! selectedBlock = getSelectedBuildingBlock excelTable context + + let protoHeaders = excelTable.getHeaderRowRange() + let _ = protoHeaders.load(U2.Case2 (ResizeArray(["values"]))) + + do! context.sync().``then``(fun _ -> ()) + + let headers = protoHeaders.values.Item 0 |> Array.ofSeq |> Array.map (fun c -> c.ToString()) + + let arcTableIndices = (groupToBuildingBlocks headers) |> Array.ofSeq |> Array.map (fun i -> i |> Array.ofSeq) + + let arcTableIndex = + let potResult = arcTableIndices |> Array.mapi (fun i c -> i, c |> Array.tryFind (fun (_, s) -> s = snd selectedBlock.[0])) + let result = potResult |> Array.filter (fun (_, c) -> c.IsSome) |> Array.map (fun (i, c) -> i, c.Value) + Array.tryHead result + + let arcTableIndex, columnName = + if arcTableIndex.IsSome then + fst arcTableIndex.Value, snd (snd arcTableIndex.Value) + else failwith "Could not find a fitting arc table index" + + let targetColumn = + let potColumn = arcTable.GetColumn arcTableIndex + if columnName.Contains(potColumn.Header.ToString()) then potColumn + else failwith "Could not find a fitting arc table index with matchin name" + + return (targetColumn, arcTableIndex) + } + +/// +/// Get the valid cell type for the conversion based on input cell type +/// +/// +let getValidConversionCellType (cellType: CompositeCellDiscriminate option) = + Excel.run(fun context -> + promise { + let! result = tryGetActiveAnnotationTable context + match result with + | Result.Ok excelTable -> + let! arcTable = ArcTable.tryGetFromExcelTable(excelTable, context) + let! (arcMainColumn, _) = getArcMainColumn excelTable arcTable.Value context + + return + match cellType with + | Some CompositeCellDiscriminate.Unitized -> Some CompositeCellDiscriminate.Term + | Some CompositeCellDiscriminate.Term -> Some CompositeCellDiscriminate.Unitized + | Some CompositeCellDiscriminate.Data -> Some CompositeCellDiscriminate.Text + | Some CompositeCellDiscriminate.Text -> + if (arcMainColumn.Header.isInput || arcMainColumn.Header.isOutput) && arcMainColumn.Header.IsDataColumn then + Some CompositeCellDiscriminate.Data + else None + | _ -> None + + | Result.Error _ -> return None + } + ) + /// /// Select a building block, shifted by adaptedIndex from the selected building block /// @@ -1688,40 +1748,6 @@ let removeSelectedAnnotationBlock () = } ) -/// -/// Get the main column of the arc table of the selected building block of the active annotation table -/// -let getArcMainColumn (excelTable: Table) (arcTable: ArcTable) (context: RequestContext)= - promise { - let! selectedBlock = getSelectedBuildingBlock excelTable context - - let protoHeaders = excelTable.getHeaderRowRange() - let _ = protoHeaders.load(U2.Case2 (ResizeArray(["values"]))) - - do! context.sync().``then``(fun _ -> ()) - - let headers = protoHeaders.values.Item 0 |> Array.ofSeq |> Array.map (fun c -> c.ToString()) - - let arcTableIndices = (groupToBuildingBlocks headers) |> Array.ofSeq |> Array.map (fun i -> i |> Array.ofSeq) - - let arcTableIndex = - let potResult = arcTableIndices |> Array.mapi (fun i c -> i, c |> Array.tryFind (fun (_, s) -> s = snd selectedBlock.[0])) - let result = potResult |> Array.filter (fun (_, c) -> c.IsSome) |> Array.map (fun (i, c) -> i, c.Value) - Array.tryHead result - - let arcTableIndex, columnName = - if arcTableIndex.IsSome then - fst arcTableIndex.Value, snd (snd arcTableIndex.Value) - else failwith "Could not find a fitting arc table index" - - let targetColumn = - let potColumn = arcTable.GetColumn arcTableIndex - if columnName.Contains(potColumn.Header.ToString()) then potColumn - else failwith "Could not find a fitting arc table index with matchin name" - - return (targetColumn, arcTableIndex) - } - /// /// Get the main column of the arc table of the selected building block of the active annotation table /// @@ -1826,6 +1852,9 @@ let addBuildingBlockAt (excelIndex: int) (newBB: CompositeColumn) (table: Table) |> List.iteri (fun ci header -> ExcelHelper.addColumnAndRows (float (excelIndex + ci)) table header bodyValues.[ci] |> ignore) } +/// +/// Get the cell type of the selected cell +/// let getSelectedCellType () = Excel.run(fun context -> promise { @@ -1838,17 +1867,13 @@ let getSelectedCellType () = let! (arcMainColumn, _) = getArcMainColumn excelTable arcTable.Value context if rowIndex > 0 then - - let result = + return match arcMainColumn with | amc when amc.Cells.[(int rowIndex) - 1].isUnitized -> Some CompositeCellDiscriminate.Unitized | amc when amc.Cells.[(int rowIndex) - 1].isTerm -> Some CompositeCellDiscriminate.Term | amc when amc.Cells.[(int rowIndex) - 1].isData -> Some CompositeCellDiscriminate.Data - | amc when amc.Header.isInput && amc.Header.IsDataColumn && amc.Cells.[(int rowIndex) - 1].isFreeText -> Some CompositeCellDiscriminate.Text - | amc when amc.Header.isOutput && amc.Header.IsDataColumn && amc.Cells.[(int rowIndex) - 1].isFreeText -> Some CompositeCellDiscriminate.Text + | amc when amc.Cells.[(int rowIndex) - 1].isFreeText -> Some CompositeCellDiscriminate.Text | _ -> None - - return result else return None | Result.Error _ -> return None diff --git a/src/Client/Pages/BuildingBlock/CellConvertComponent.fs b/src/Client/Pages/BuildingBlock/CellConvertComponent.fs index 7b0015a9..95183b1c 100644 --- a/src/Client/Pages/BuildingBlock/CellConvertComponent.fs +++ b/src/Client/Pages/BuildingBlock/CellConvertComponent.fs @@ -6,34 +6,42 @@ open Feliz.Bulma open OfficeInterop.Core open Shared +type CellDiscriminateState = { + SelectedCellState: CompositeCellDiscriminate option + TargetCellState: CompositeCellDiscriminate option + } with + static member init = { + SelectedCellState = None + TargetCellState = None + } + module private CellConvertComponentHelpers = - let getSelectedCellType (setState: CompositeCellDiscriminate option -> unit) = + let setCellTypes (state: CellDiscriminateState) (setState: CellDiscriminateState -> unit) = promise { //Write function to access current state of selected excel cell excel - let! cellType = getSelectedCellType () + let! selectedCellType = getSelectedCellType () - setState cellType - } + if selectedCellType.IsSome then + let! targetCellType = getValidConversionCellType (selectedCellType) - let getTargetConversionType (cellType: CompositeCellDiscriminate option) = - if cellType.IsSome then - match cellType.Value with - | CompositeCellDiscriminate.Unitized -> Some CompositeCellDiscriminate.Term - | CompositeCellDiscriminate.Term -> Some CompositeCellDiscriminate.Unitized - | CompositeCellDiscriminate.Text -> Some CompositeCellDiscriminate.Data - | CompositeCellDiscriminate.Data -> Some CompositeCellDiscriminate.Text - else None + setState { + state with + SelectedCellState = selectedCellType + TargetCellState = targetCellType + } + } type CellConvertComponent = [] static member Main () = - let (state: CompositeCellDiscriminate option), setState = React.useState(None) - + //let (state: CompositeCellDiscriminate option), setState = React.useState(None) + //let (targetState: CompositeCellDiscriminate option), setTargetState = React.useState(None) + let (cellDiscriminateState, setCellDiscriminateState) = React.useState(CellDiscriminateState.init) React.useEffectOnce(fun () -> - CellConvertComponentHelpers.getSelectedCellType setState + CellConvertComponentHelpers.setCellTypes cellDiscriminateState setCellDiscriminateState |> Promise.start ) @@ -43,27 +51,26 @@ type CellConvertComponent = Bulma.button.button [ Bulma.color.isSuccess prop.text "Refresh" - prop.onClick (fun _ -> CellConvertComponentHelpers.getSelectedCellType setState |> Promise.start) + prop.onClick (fun _ -> + CellConvertComponentHelpers.setCellTypes cellDiscriminateState setCellDiscriminateState |> Promise.start + ) ] - Html.div (string state) + Html.div (string cellDiscriminateState.SelectedCellState) ] Bulma.buttons [ Bulma.button.button [ - if state.IsSome then + if cellDiscriminateState.TargetCellState.IsSome then Bulma.color.isSuccess prop.disabled false - prop.text $"Convert {state.Value} to" - - - + prop.text $"Convert {cellDiscriminateState.SelectedCellState.Value} to" else Bulma.color.isDanger prop.disabled true prop.text $"Unconvertible" prop.onClick (fun _ -> - CellConvertComponentHelpers.getSelectedCellType setState |> ignore + CellConvertComponentHelpers.setCellTypes cellDiscriminateState setCellDiscriminateState |> Promise.start convertBuildingBlock () |> Promise.start) ] - Html.div (string (CellConvertComponentHelpers.getTargetConversionType state)) + Html.div (string cellDiscriminateState.TargetCellState) ] ] From a56edceb6852b35184feb699b4c8ccf862f6b2b3 Mon Sep 17 00:00:00 2001 From: patrick blume Date: Tue, 29 Oct 2024 20:49:54 +0100 Subject: [PATCH 6/6] Apply review changes --- src/Client/OfficeInterop/OfficeInterop.fs | 86 ++++++++++--------- .../BuildingBlock/CellConvertComponent.fs | 15 ++-- 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index a613f5d5..65a1b397 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -1666,33 +1666,65 @@ let getArcMainColumn (excelTable: Table) (arcTable: ArcTable) (context: RequestC } /// -/// Get the valid cell type for the conversion based on input cell type +/// Get the cell type of the selected cell /// -/// -let getValidConversionCellType (cellType: CompositeCellDiscriminate option) = +let getSelectedCellType () = Excel.run(fun context -> promise { let! result = tryGetActiveAnnotationTable context + match result with | Result.Ok excelTable -> + let! _, rowIndex = getSelectedBuildingBlockCell excelTable context let! arcTable = ArcTable.tryGetFromExcelTable(excelTable, context) let! (arcMainColumn, _) = getArcMainColumn excelTable arcTable.Value context - return - match cellType with - | Some CompositeCellDiscriminate.Unitized -> Some CompositeCellDiscriminate.Term - | Some CompositeCellDiscriminate.Term -> Some CompositeCellDiscriminate.Unitized - | Some CompositeCellDiscriminate.Data -> Some CompositeCellDiscriminate.Text - | Some CompositeCellDiscriminate.Text -> - if (arcMainColumn.Header.isInput || arcMainColumn.Header.isOutput) && arcMainColumn.Header.IsDataColumn then - Some CompositeCellDiscriminate.Data - else None - | _ -> None + if rowIndex > 0 then + return + match arcMainColumn with + | amc when amc.Cells.[(int rowIndex) - 1].isUnitized -> Some CompositeCellDiscriminate.Unitized + | amc when amc.Cells.[(int rowIndex) - 1].isTerm -> Some CompositeCellDiscriminate.Term + | amc when amc.Cells.[(int rowIndex) - 1].isData -> Some CompositeCellDiscriminate.Data + | amc when amc.Cells.[(int rowIndex) - 1].isFreeText -> Some CompositeCellDiscriminate.Text + | _ -> None + else return None | Result.Error _ -> return None } ) +/// +/// Get the valid cell type for the conversion based on input cell type +/// +/// +let getValidConversionCellTypes () = + Excel.run(fun context -> + promise { + let! result = tryGetActiveAnnotationTable context + + match result with + | Result.Ok excelTable -> + let! _, rowIndex = getSelectedBuildingBlockCell excelTable context + let! arcTable = ArcTable.tryGetFromExcelTable(excelTable, context) + let! (arcMainColumn, _) = getArcMainColumn excelTable arcTable.Value context + + if rowIndex > 0 then + return + match arcMainColumn with + | amc when amc.Cells.[(int rowIndex) - 1].isUnitized -> (Some CompositeCellDiscriminate.Unitized, Some CompositeCellDiscriminate.Term) + | amc when amc.Cells.[(int rowIndex) - 1].isTerm -> (Some CompositeCellDiscriminate.Term, Some CompositeCellDiscriminate.Unitized) + | amc when amc.Cells.[(int rowIndex) - 1].isData -> (Some CompositeCellDiscriminate.Data, Some CompositeCellDiscriminate.Text) + | amc when amc.Cells.[(int rowIndex) - 1].isFreeText -> + if (arcMainColumn.Header.isInput || arcMainColumn.Header.isOutput) && arcMainColumn.Header.IsDataColumn then + (Some CompositeCellDiscriminate.Text, Some CompositeCellDiscriminate.Data) + else + (Some CompositeCellDiscriminate.Data, None) + | _ -> (None, None) + else return (None, None) + | Result.Error _ -> return (None, None) + } + ) + /// /// Select a building block, shifted by adaptedIndex from the selected building block /// @@ -1852,34 +1884,6 @@ let addBuildingBlockAt (excelIndex: int) (newBB: CompositeColumn) (table: Table) |> List.iteri (fun ci header -> ExcelHelper.addColumnAndRows (float (excelIndex + ci)) table header bodyValues.[ci] |> ignore) } -/// -/// Get the cell type of the selected cell -/// -let getSelectedCellType () = - Excel.run(fun context -> - promise { - let! result = tryGetActiveAnnotationTable context - - match result with - | Result.Ok excelTable -> - let! _, rowIndex = getSelectedBuildingBlockCell excelTable context - let! arcTable = ArcTable.tryGetFromExcelTable(excelTable, context) - let! (arcMainColumn, _) = getArcMainColumn excelTable arcTable.Value context - - if rowIndex > 0 then - return - match arcMainColumn with - | amc when amc.Cells.[(int rowIndex) - 1].isUnitized -> Some CompositeCellDiscriminate.Unitized - | amc when amc.Cells.[(int rowIndex) - 1].isTerm -> Some CompositeCellDiscriminate.Term - | amc when amc.Cells.[(int rowIndex) - 1].isData -> Some CompositeCellDiscriminate.Data - | amc when amc.Cells.[(int rowIndex) - 1].isFreeText -> Some CompositeCellDiscriminate.Text - | _ -> None - else return None - - | Result.Error _ -> return None - } - ) - /// /// This function is used to convert building blocks that can be converted. Data building blocks can be converted into free text, free text into data, /// terms into units and units into terms diff --git a/src/Client/Pages/BuildingBlock/CellConvertComponent.fs b/src/Client/Pages/BuildingBlock/CellConvertComponent.fs index 95183b1c..680e03db 100644 --- a/src/Client/Pages/BuildingBlock/CellConvertComponent.fs +++ b/src/Client/Pages/BuildingBlock/CellConvertComponent.fs @@ -20,16 +20,13 @@ module private CellConvertComponentHelpers = let setCellTypes (state: CellDiscriminateState) (setState: CellDiscriminateState -> unit) = promise { //Write function to access current state of selected excel cell excel - let! selectedCellType = getSelectedCellType () + let! (selectedCellType, targetCellType) = getValidConversionCellTypes () - if selectedCellType.IsSome then - let! targetCellType = getValidConversionCellType (selectedCellType) - - setState { - state with - SelectedCellState = selectedCellType - TargetCellState = targetCellType - } + setState { + state with + SelectedCellState = selectedCellType + TargetCellState = targetCellType + } } type CellConvertComponent =