Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] handling of threaded comments #674

Merged
merged 11 commits into from
Jul 16, 2023
1 change: 1 addition & 0 deletions .lintr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ linters: linters_with_defaults(
exclusions: list(
# otherwise they will throw locally
"vignettes/conditional-formatting.R",
"vignettes/openxlsx2.R",
"vignettes/openxlsx2_basic_manual.R",
"vignettes/openxlsx2_charts_manual.R",
"vignettes/openxlsx2_formulas_manual.R",
Expand Down
3 changes: 3 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,12 @@ export(wb_add_named_region)
export(wb_add_named_style)
export(wb_add_numfmt)
export(wb_add_page_break)
export(wb_add_person)
export(wb_add_pivot_table)
export(wb_add_plot)
export(wb_add_sparklines)
export(wb_add_style)
export(wb_add_thread)
export(wb_add_worksheet)
export(wb_clean_sheet)
export(wb_clone_sheet_style)
Expand All @@ -84,6 +86,7 @@ export(wb_get_cell_style)
export(wb_get_creators)
export(wb_get_named_regions)
export(wb_get_order)
export(wb_get_person)
export(wb_get_selected)
export(wb_get_sheet_name)
export(wb_get_sheet_names)
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
* `wb_dims(1:5, letters)`
* `wb_dims(1:5, 1:26)`
* `wb_dims(matrix(1, 5, 26))` with an added row for column names
* Handling of thread comments is not possible via `wb_add_thread()`. This includes options to reply and resolve comments.

## Refactoring

Expand Down
55 changes: 51 additions & 4 deletions R/class-comment.R
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,10 @@ wbComment <- R6::R6Class(
#' @name create_comment
#' @title Create, write and remove comments
#' @description The comment functions (create, write and remove) allow the
#' modification of comments. In newer Excels they are called notes, while they
#' are called comments in openxml. Modification of what Excel now calls comment
#' (openxml calls them threadedComments) is not yet possible
#' modification of comments. In newer spreadsheet software they are called
#' notes, while they are called comments in openxml. Modification of what
#' newer spreadsheet software now calls comment is possible via
#' [wb_add_thread()].
#' @param text Comment text. Character vector.
#' @param author Author of comment. Character vector of length 1
#' @param style A Style object or list of style objects the same length as comment vector.
Expand Down Expand Up @@ -179,7 +180,6 @@ create_comment <- function(text,
#' @param comment A Comment object. See [create_comment()].
#' @param dims worksheet cell "A1"
#' @rdname comment
#' @keywords internal
#' @export
write_comment <- function(
wb,
Expand Down Expand Up @@ -388,3 +388,50 @@ remove_comment <- function(
wb_comment <- function(text = character(), author = character(), style = character()) {
wbComment$new(text = text, author = author, style = style)
}

as_fmt_txt <- function(x) {
vapply(x, function(y) {
ifelse(is_xml(y), si_to_txt(xml_node_create("si", xml_children = y)), y)
},
NA_character_
)
}

wb_get_comment <- function(wb, sheet = current_sheet(), dims = "A1") {
sheet_id <- wb$validate_sheet(sheet)
cmts <- list()
if (length(wb$comments) >= sheet_id) {
cmts <- as.data.frame(do.call("rbind", wb$comments[[sheet_id]]))
if (!is.null(dims)) cmts <- cmts[cmts$ref == dims, ]
# print(cmts)
cmts <- cmts[c("ref", "author", "comment")]
if (nrow(cmts)) {
cmts$comment <- as_fmt_txt(cmts$comment)
cmts$sheet_id <- sheet_id
}
}
cmts
}

wb_get_thread <- function(wb, sheet = current_sheet(), dims = "A1") {

sheet <- wb$validate_sheet(sheet)

tc <- cbind(
rbindlist(xml_attr(wb$threadComments[[sheet]], "threadedComment")),
text = xml_value(wb$threadComments[[sheet]], "threadedComment", "text")
)

if (!is.null(dims)) {
tc <- tc[tc$ref == dims, ]
}

persons <- wb$get_person()

tc <- merge(tc, persons, by.x = "personId", by.y = "id",
all.x = TRUE, all.y = FALSE)

tc$dT <- as.POSIXct(tc$dT, format = "%Y-%m-%dT%H:%M:%SZ")

tc[c("dT", "ref", "displayName", "text", "done")]
}
83 changes: 83 additions & 0 deletions R/class-workbook-wrappers.R
Original file line number Diff line number Diff line change
Expand Up @@ -2863,6 +2863,7 @@ wb_add_dxfs_style <- function(
#' @param ... additional arguments
#' @returns The `wbWorkbook` object
#' @rdname comment
#' @seealso [wb_add_thread()]
#' @export
wb_add_comment <- function(
wb,
Expand Down Expand Up @@ -2907,6 +2908,88 @@ wb_remove_comment <- function(
)
}

#' @rdname wb_add_thread
#' @details
#' If a threaded comment is added, it needs a person attached with it. The default is to create a person with provider id `"None"`. Other providers are possible with specific values for `id` and `user_id`. If you require the following, create a workbook via spreadsheet software load it and get the values with [wb_get_person()]
#' @param wb a workbook
#' @param name the name to display
#' @param id (optional) the display id
#' @param user_id (optional) the user id
#' @param provider_id (optional) the provider id
#' @keywords comments
#' @export
wb_add_person <- function(
wb,
name = NULL,
id = NULL,
user_id = NULL,
provider_id = "None"
) {
assert_workbook(wb)
wb$clone()$add_person(
name = name,
id = id,
user_id = user_id,
provider_id = provider_id
)
}

#' @rdname wb_add_thread
#' @export
wb_get_person <- function(wb, name = NULL) {
assert_workbook(wb)
wb$get_person(name)
}

#' add threaded comment to worksheet
#'
#' These functions allow adding thread comments to spreadsheets. This is not yet supported by all spreadsheet software.
#' @param wb a workbook
#' @param sheet a worksheet
#' @param dims a cell
#' @param comment the comment to add
#' @param person_id the person Id this should be added for
#' @param reply logical if the comment is a reply
#' @param resolve logical if the comment should be maked as resolved
#' @seealso [wb_add_comment()]
#' @name wb_add_thread
#' @examples
#' wb <- wb_workbook()$add_worksheet()$
#' add_person(name = "openxlsx2")
#'
#' pid <- wb$get_person(name = "openxlsx")$id
#'
#' # write a comment to a thread, reply to one and solve some
#' wb <- wb %>%
#' wb_add_thread(dims = "A1", comment = "wow it works!", person_id = pid) %>%
#' wb_add_thread(dims = "A2", comment = "indeed", person_id = pid, resolve = TRUE) %>%
#' wb_add_thread(dims = "A1", comment = "so cool", person_id = pid, reply = TRUE)
#' @export
wb_add_thread <- function(
wb,
sheet = current_sheet(),
dims = "A1",
comment = NULL,
person_id,
reply = FALSE,
resolve = FALSE
) {

if (missing(person_id)) {
person_id <- substitute()
}

assert_workbook(wb)
wb$clone()$add_thread(
sheet = sheet,
dims = dims,
comment = comment,
person_id = person_id,
reply = reply,
resolve = resolve
)
}

#' Add form control Checkbox, Radiobuttons or Dropmenu
#' @param wb A workbook object
#' @param sheet A worksheet of the workbook
Expand Down
Loading