Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ cran_examples_sanitizer.R
^check/
^twbparser.Rcheck$
^\.Rd2pdf20656$
^\.git$
^\.claude$
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: twbparser
Title: Parse 'Tableau' Workbooks into Functional Data
Version: 0.3.1
Version: 0.4.0
Authors@R:
person("George", "Arthur", , "prigasgenthian48@gmail.com", role = c("aut", "cre"),
comment = c(ORCID = "0000-0002-1975-1459"))
Expand Down Expand Up @@ -46,4 +46,4 @@ Encoding: UTF-8
Language: en-US
LazyData: false
Roxygen: list(markdown = TRUE, r6 = FALSE)
RoxygenNote: 7.3.2
RoxygenNote: 7.3.3
10 changes: 10 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,21 @@ export(tbs_publish_info)
export(twb_charts)
export(twb_colors)
export(twb_custom_sql)
export(twb_dashboard_actions)
export(twb_dashboard_filters)
export(twb_dashboard_layout)
export(twb_dashboard_sheets)
export(twb_dashboard_summary)
export(twb_dashboards)
export(twb_initial_sql)
export(twb_page_composition)
export(twb_pages)
export(twb_pages_summary)
export(twb_published_refs)
export(twb_sheet_axes)
export(twb_sheet_filters)
export(twb_sheet_shelves)
export(twb_sheet_sorts)
export(twbx_extract_files)
export(twbx_list)
export(validate_relationships)
Expand Down Expand Up @@ -63,6 +70,7 @@ importFrom(igraph,graph_from_data_frame)
importFrom(igraph,layout_with_fr)
importFrom(igraph,make_empty_graph)
importFrom(purrr,map)
importFrom(purrr,map_chr)
importFrom(purrr,map_dfr)
importFrom(rlang,.data)
importFrom(stringr,str_detect)
Expand All @@ -82,7 +90,9 @@ importFrom(withr,with_seed)
importFrom(xml2,read_xml)
importFrom(xml2,xml_attr)
importFrom(xml2,xml_attrs)
importFrom(xml2,xml_children)
importFrom(xml2,xml_find_all)
importFrom(xml2,xml_find_first)
importFrom(xml2,xml_name)
importFrom(xml2,xml_parent)
importFrom(xml2,xml_text)
52 changes: 52 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,55 @@
# twbparser 0.4.0

## New features

### Per-worksheet intelligence

* `twb_sheet_shelves()` — extract every field placed on rows, cols, or an
encoding shelf (color, size, label, detail, tooltip) for one or all worksheets.
* `twb_sheet_filters()` — extract worksheet-level filters including categorical
member lists, range min/max, and include/exclude mode.
* `twb_sheet_axes()` — extract per-axis configuration: reversed, include-zero,
and scale type (linear, log, …).
* `twb_sheet_sorts()` — extract sort directives with sort direction and method
(field aggregate, alphabetic, manual, data-source order).
* All four are exposed on `TwbParser` as `get_sheet_shelves()`,
`get_sheet_filters()`, `get_sheet_axes()`, `get_sheet_sorts()` and as
no-parens active bindings (`parser$sheet_shelves`, etc.).

### Per-dashboard intelligence

* `twb_dashboard_sheets()` — list every worksheet placed on a dashboard with
zone id and pixel position (x, y, w, h).
* `twb_dashboard_layout()` — full zone tree including parent zone id, component
type (worksheet / filter / container / …), layout type (tiled / floating),
and pixel bounds.
* `twb_dashboard_actions()` — extract filter and URL actions with source and
target sheets, run-on trigger type, and URL value.
* All three are exposed on `TwbParser` as `get_dashboard_sheets()`,
`get_dashboard_layout()`, `get_dashboard_actions()` and as active bindings.

## Bug fixes

* `plot_relationship_graph()`: fixed edge direction — the `from` vertex was
incorrectly built from `right_field` instead of `left_field`.
* `plot_source_join_graph()`: fixed reference to non-existent columns
`left_source` / `right_source`; replaced with `left_table` / `right_table`.
* `infer_implicit_relationships()`: added deduplication before the field-name
self-join to prevent Cartesian explosion when many tables share a field name;
added `relationship = "many-to-many"` to suppress the dplyr 1.1+ warning.
* Fixed `integer_` typo in `insights.R` that caused errors when parsing
dashboard zone dimensions.

## Internal

* Canonical `.twb_clean_table()` and `.twb_clean_field()` helpers added to
`utils.R`, replacing four independent copies scattered across `fields.R`,
`calculated_fields.R`, `relationships.R`, `joins.R`, and `dependency_graph.R`.
* `.twb_clean_field()` now correctly strips Tableau column-instance prefixes
(`none:Category:nk` → `Category`) and returns unnamed vectors.

---

# twbparser 0.3.1

* Remove use of `unlockBinding()` in internal TwbParser active-binding helpers.
Expand Down
9 changes: 9 additions & 0 deletions R/active-bindings.R
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ twb_install_active_properties <- function(x, cache = TRUE) {
rebind("twbx_extracts_tbl", wrap_cache("twbx_extracts_tbl", function() x$get_twbx_extracts()))
rebind("twbx_images_tbl", wrap_cache("twbx_images_tbl", function() x$get_twbx_images()))

## Phase 2/3: sheet & dashboard intelligence
rebind("sheet_shelves", wrap_cache("sheet_shelves", function() x$get_sheet_shelves()))
rebind("sheet_filters", wrap_cache("sheet_filters", function() x$get_sheet_filters()))
rebind("sheet_axes", wrap_cache("sheet_axes", function() x$get_sheet_axes()))
rebind("sheet_sorts", wrap_cache("sheet_sorts", function() x$get_sheet_sorts()))
rebind("dashboard_sheets", wrap_cache("dashboard_sheets", function() x$get_dashboard_sheets()))
rebind("dashboard_layout", wrap_cache("dashboard_layout", function() x$get_dashboard_layout()))
rebind("dashboard_actions", wrap_cache("dashboard_actions", function() x$get_dashboard_actions()))

## Validation snapshot (read-only)
rebind(
"validation",
Expand Down
18 changes: 3 additions & 15 deletions R/calculated_fields.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,6 @@
ifelse(is.na(x), NA_character_, gsub("\\[|\\]", "", x))
}

#' @keywords internal
.clean_table <- function(x) {
if (is.null(x) || is.na(x)) {
return(NA_character_)
}
x <- gsub("^\\[.*?\\]\\.", "", x) # drop [Extract]. / [Connection].
x <- gsub("\\[|\\]", "", x) # strip [ ]
x <- sub("_[0-9A-Fa-f]{32}$", "", x) # drop 32-hex suffix
x <- trimws(x)
if (!nzchar(x)) NA_character_ else x
}

#' Extract calculated fields from a TWB
#'
#' Finds columns that contain \code{<calculation>}nodes and returns metadata and
Expand Down Expand Up @@ -103,7 +91,7 @@ extract_calculated_fields <- function(xml_doc, include_parameters = FALSE) {
calc_class = calc_class,
is_table_calc = is_tbl,
table = raw_tbl,
table_clean = .clean_table(raw_tbl)
table_clean = .twb_clean_table(raw_tbl)
)
})
}) |>
Expand Down Expand Up @@ -181,7 +169,7 @@ extract_parameters <- function(xml_doc) {
current_value = cur_val,
is_parameter = TRUE,
table = raw_tbl,
table_clean = .clean_table(raw_tbl)
table_clean = .twb_clean_table(raw_tbl)
)
})
}) |>
Expand Down Expand Up @@ -251,7 +239,7 @@ extract_raw_fields <- function(xml_doc) {
is_hidden = attr_safe_get(a, "hidden", "false") %in% c("true", "1"),
is_parameter = FALSE,
table = raw_tbl,
table_clean = .clean_table(raw_tbl)
table_clean = .twb_clean_table(raw_tbl)
)
})
}) |>
Expand Down
Loading
Loading