Skip to content

Commit

Permalink
Refactor of the filter-panel (#165)
Browse files Browse the repository at this point in the history
Tons of features:
- new look
- new API
- better control of single filter cards
- reactive counts
- more open for new features
  • Loading branch information
gogonzo committed Jul 14, 2023
1 parent 95eae92 commit 56f30ba
Show file tree
Hide file tree
Showing 155 changed files with 14,415 additions and 14,095 deletions.
1 change: 1 addition & 0 deletions .github/workflows/check.yaml
Expand Up @@ -36,6 +36,7 @@ jobs:
with:
additional-env-vars: |
_R_CHECK_CRAN_INCOMING_REMOTE_=false
_R_CHECK_EXAMPLE_TIMING_THRESHOLD_=10
additional-r-cmd-check-params: --as-cran
enforce-note-blocklist: true
note-blocklist: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
@@ -1,4 +1,5 @@
*.Rcheck
.Rprofile
*.html
*.rprof
*.sas.txt
Expand Down
1 change: 0 additions & 1 deletion .pre-commit-config.yaml
Expand Up @@ -26,7 +26,6 @@ repos:
- methods
- bioc::MultiAssayExperiment
- R6
- rlang
- rtables
- shinyjs
- shinyWidgets
Expand Down
31 changes: 19 additions & 12 deletions DESCRIPTION
Expand Up @@ -2,15 +2,20 @@ Type: Package
Package: teal.slice
Title: Filter Module for `teal` Applications
Version: 0.3.0.9005
Date: 2023-06-29
Date: 2023-07-14
Authors@R: c(
person("Dawid", "Kaledkowski", , "dawid.kaledkowski@roche.com", role = c("aut", "cre")),
person("Pawel", "Rucki", , "pawel.rucki@roche.com", role = "aut"),
person("Nikolas", "Burkoff", , "nikolas.burkoff@roche.com", role = "aut"),
person("Mahmoud", "Hallal", , "mahmoud.hallal@roche.com", role = "aut"),
person("Maciej", "Nasinski", , "maciej.nasinski@contractors.roche.com", role = "aut"),
person("Konrad", "Pagacz", , "konrad.pagacz@contractors.roche.com", role = "aut"),
person("Junlue", "Zhao", , "zhaoj88@gene.com", role = "aut"),
person("Dawid", "Kaledkowski", email = "dawid.kaledkowski@roche.com", role = c("aut", "cre")),
person("Pawel", "Rucki", email = "pawel.rucki@roche.com", role = "aut"),
person("Aleksander", "Chlebowski", email = "aleksander.chlebowski@contractors.roche.com", role = "aut"),
person("Kartikeya", "Kirar", email = "kartikeya.kirar@businesspartner.roche.com", role = "aut"),
person("Marcin", "Kosinski", email = "marcin.kosinski.mk1@roche.com", role = "aut"),
person("Chendi", "Liao", email = "chendi.liao@roche.com", role = "rev"),
person("Dony", "Unardi", email = "unardid@gene.com", role = "rev"),
person("Mahmoud", "Hallal", role = "aut"),
person("Nikolas", "Burkoff", role = "aut"),
person("Maciej", "Nasinski", role = "aut"),
person("Konrad", "Pagacz", role = "aut"),
person("Junlue", "Zhao", role = "aut"),
person("F. Hoffmann-La Roche AG", role = c("cph", "fnd"))
)
Description: Filter module for teal applications.
Expand All @@ -19,22 +24,24 @@ Depends:
R (>= 4.0),
shiny
Imports:
bslib (>= 0.4.0),
checkmate,
dplyr,
ggplot2,
grDevices,
jsonlite,
htmltools,
lifecycle,
logger (>= 0.2.0),
methods,
plotly,
R6,
shinycssloaders,
shinyjs,
shinyWidgets (>= 0.5.0),
stats,
shinyWidgets (>= 0.6.2),
teal.data (>= 0.1.2.9011),
teal.logger (>= 0.1.1),
teal.widgets (>= 0.2.0)
Suggests:
bslib,
formatters (>= 0.3.1),
knitr,
MultiAssayExperiment,
Expand Down
31 changes: 16 additions & 15 deletions NAMESPACE
@@ -1,7 +1,11 @@
# Generated by roxygen2: do not edit by hand

S3method(get_supported_filter_varnames,FilteredDataset)
S3method(get_supported_filter_varnames,MAEFilteredDataset)
S3method("[",teal_slices)
S3method(as.list,teal_slice)
S3method(c,teal_slices)
S3method(format,teal_slice)
S3method(format,teal_slices)
S3method(get_supported_filter_varnames,MultiAssayExperiment)
S3method(get_supported_filter_varnames,default)
S3method(get_supported_filter_varnames,matrix)
S3method(init_filter_state,Date)
Expand All @@ -20,33 +24,30 @@ S3method(init_filtered_data,TealData)
S3method(init_filtered_data,default)
S3method(init_filtered_dataset,MultiAssayExperiment)
S3method(init_filtered_dataset,data.frame)
S3method(resolve_state,default)
S3method(resolve_state,default_filter)
S3method(resolve_state,list)
S3method(print,teal_slice)
S3method(print,teal_slices)
S3method(variable_types,DFrame)
S3method(variable_types,DataTable)
S3method(variable_types,data.frame)
S3method(variable_types,default)
S3method(variable_types,matrix)
export(FilterPanelAPI)
export(as.teal_slice)
export(as.teal_slices)
export(clear_filter_states)
export(get_filter_expr)
export(get_filter_state)
export(init_filter_states)
export(init_filtered_data)
export(init_filtered_dataset)
export(is.teal_slice)
export(is.teal_slices)
export(remove_filter_state)
export(set_filter_state)
export(slices_restore)
export(slices_store)
export(teal_slice)
export(teal_slices)
import(R6)
import(shiny)
importFrom(dplyr,filter)
importFrom(ggplot2,ggplot)
importFrom(grDevices,rgb)
importFrom(lifecycle,badge)
importFrom(logger,log_trace)
importFrom(methods,is)
importFrom(shinyWidgets,pickerOptions)
importFrom(shinyjs,hide)
importFrom(stats,setNames)
importFrom(teal.data,dataset)
importFrom(teal.widgets,optionalSelectInput)
28 changes: 24 additions & 4 deletions NEWS.md
@@ -1,6 +1,23 @@
# teal.slice 0.3.0.9005

* Remove `scda` from dependencies.
### New features

* API is based now on `teal_slices` and `teal_slice` objects.
* Implemented reactive counts of single filter card to compare filtered and unfiltered variable distributions. See `count_type` in `teal_slices`.
* Possible now to specify filter based on arbitrary logical expression. See `expr` argument in `teal_slice`.
* Possible now to limit choices in single filter card. See `choices` argument in `teal_slice`.
* Possible now to initialize filter panel without "Add filter variables" panel through `module_add` in `teal_slices`.
* Possible now to set filter which can't be removed by app user. See `anchored` argument in `teal_slice`.
* Possible now to set filter which selection remains the same. See `fixed` argument in `teal_slice`.
* Possible now to limit variable by single level only. See `multuple` argument in `teal_slice`
* Changed appearance of filter cards to collapsible accordion.
* Replaced `sliderInput` with interactive `plotly` to be able to zoom variable distribution.

### Breaking changes

* Setting filters using a list is now deprecated. Use `teal_slices` and `teal_slice` instead.
* Removed `CDISCFilteredData` and `CDISCFilteredDataset` and implementing `JoinKeys` handling in their parent classes (`FilteredData` and `DefaultFilteredDataset`).
* Specifying set of filterable columns is done through `include_varnames` and `exclude_varnames`. Specifying `attr(, "filterable")` is hard deprecated.

# teal.slice 0.3.0

Expand All @@ -13,6 +30,7 @@
* Added a global turn on/off button for the Filter Panel.
* Added ability to collapse Active Filter Display panel.
* Added ability to collapse all filters of an individual dataset.
* Added fixed filter states.

### Enhancements

Expand All @@ -22,12 +40,14 @@

* Fixed an error where the `RangeFilterState` produced an error when using `bootstrap 4`.
* Fixed a bug that caused the range slider to omit values selected programmatically through the filter API.
* Fixed a bug where setting incorrect values for Date and Date time ranges caused the app to crash.

### Miscellaneous

* Calculation of step in slider for `RangeFilterState` now uses `checkmate::test_integerish` instead of `is.integer`.
* Updated `init_filtered_data` to take into account the removal of `CDISCTealData` from `teal.data` package.
* Added examples apps for `ChoicesFilterState` and `DFFilterStates`.
* Added `shinyvalidate` validation for Date and Date time ranges.
* Added examples apps for `FilterState` child classes and `DFFilterStates`.

# teal.slice 0.2.0

Expand All @@ -47,10 +67,10 @@
### Enhancements

* Redesigned the count bars for filter panel check box inputs.
* Redesigned the filter panel input for dates to use CSS flexbox.
* Redesigned the filter panel input for dates to use `CSS flexbox`.
* Update icons to be compatible with Font Awesome 6.
* Updates the `FilteredData` method `get_formatted_filter_state` so it no longer appends empty filters.
* Added clearer installation instructions to README.
* Added clearer installation instructions to `README`.

### Breaking changes

Expand Down
73 changes: 24 additions & 49 deletions R/FilterPanelAPI.R
Expand Up @@ -21,18 +21,18 @@
#' isolate(fpa$get_filter_state())
#'
#' # set a filter state
#' isolate(
#' set_filter_state(
#' fpa,
#' list(iris = list(Species = list(selected = "setosa", keep_na = TRUE)))
#' set_filter_state(
#' fpa,
#' teal_slices(
#' teal_slice(dataname = "iris", varname = "Species", selected = "setosa", keep_na = TRUE)
#' )
#' )
#'
#' # get the actual filter state --> named list with filters
#' isolate(fpa$get_filter_state())
#'
#' # remove all_filter_states
#' fpa$remove_all_filter_states()
#' fpa$clear_filter_states()
#'
#' # get the actual filter state --> empty named list
#' isolate(fpa$get_filter_state())
Expand All @@ -44,6 +44,7 @@ FilterPanelAPI <- R6::R6Class( # nolint
#' @description
#' Initialize a `FilterPanelAPI` object
#' @param datasets (`FilteredData`) object.
#'
initialize = function(datasets) {
checkmate::assert_class(datasets, "FilteredData")
private$filtered_data <- datasets
Expand All @@ -56,78 +57,52 @@ FilterPanelAPI <- R6::R6Class( # nolint
#' The output list is a compatible input to `set_filter_state`.
#'
#' @return `list` with named elements corresponding to `FilteredDataset` objects with active filters.
#'
get_filter_state = function() {
private$filtered_data$get_filter_state()
},

#' @description
#' Sets active filter states.
#' @param filter (`named list`)\cr
#' nested list of filter selections applied to datasets.
#' @param filter (`teal_slices`)
#'
#' @return `NULL` invisibly
#'
#' @return `NULL`
set_filter_state = function(filter) {
if (private$filtered_data$get_filter_panel_active()) {
private$filtered_data$set_filter_state(filter)
} else {
warning(private$deactivated_msg)
}
private$filtered_data$set_filter_state(filter)
invisible(NULL)
},

#' @description
#' Remove one or more `FilterState` of a `FilteredDataset` in the `FilteredData` object.
#' @param filter (`named list`)\cr
#' nested list of filter selections applied to datasets.
#'
#' @return `NULL`
#' @param filter (`teal_slices`)\cr
#' specifying `FilterState` objects to remove;
#' `teal_slice`s may contain only `dataname` and `varname`, other elements are ignored
#'
#' @return `NULL` invisibly
#'
remove_filter_state = function(filter) {
if (private$filtered_data$get_filter_panel_active()) {
private$filtered_data$remove_filter_state(filter)
} else {
warning(private$deactivated_msg)
}
private$filtered_data$remove_filter_state(filter)
invisible(NULL)
},

#' @description Remove all `FilterStates` of the `FilteredData` object.
#'
#' @param datanames (`character`)\cr
#' datanames to remove their `FilterStates`;
#' `datanames` to remove their `FilterStates`;
#' omit to remove all `FilterStates` in the `FilteredData` object
#'
#' @return `NULL`
#'
remove_all_filter_states = function(datanames) {
if (private$filtered_data$get_filter_panel_active()) {
datanames_to_remove <- if (missing(datanames)) private$filtered_data$datanames() else datanames
private$filtered_data$remove_all_filter_states(datanames = datanames_to_remove)
} else {
warning(private$deactivated_msg)
}
invisible(NULL)
},
#' @description
#' Toggle the state of the global Filter Panel button by running `javascript` code
#' to click the toggle button with the `filter_panel_active` id suffix.
#' The button id is prefixed with the Filter Panel shiny namespace.
#' This button is observed in `srv_filter_panel` method that executes
#' `filter_panel_enable()` or `filter_panel_disable()` method depending on the toggle state.
#' @return `NULL` invisibly
#'
#' @return `NULL`
filter_panel_toggle = function() {
shinyjs::runjs(
sprintf(
'$("#%s-filter_turn_onoff").click();',
private$filtered_data$get_filter_panel_ui_id()
)
)
clear_filter_states = function(datanames) {
datanames_to_remove <- if (missing(datanames)) private$filtered_data$datanames() else datanames
private$filtered_data$clear_filter_states(datanames = datanames_to_remove)
invisible(NULL)
}
),
## __Private Methods ====
private = list(
filtered_data = NULL,
deactivated_msg = "Filter Panel is deactivated so the action can not be applied with api."
filtered_data = NULL
)
)

0 comments on commit 56f30ba

Please sign in to comment.