https://github.com/DivadNojnarg/shiny-edit-data
Edit data app POC
https://github.com/DivadNojnarg/shiny-edit-data
Last synced: 4 months ago
JSON representation
Edit data app POC
- Host: GitHub
- URL: https://github.com/DivadNojnarg/shiny-edit-data
- Owner: DivadNojnarg
- License: other
- Created: 2023-11-27T15:54:51.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-03-13T23:56:12.000Z (about 1 year ago)
- Last Synced: 2024-11-25T11:09:52.457Z (5 months ago)
- Language: R
- Size: 931 KB
- Stars: 9
- Watchers: 3
- Forks: 1
- Open Issues: 6
-
Metadata Files:
- Readme: README.Rmd
- License: LICENSE
Awesome Lists containing this project
- jimsghstars - DivadNojnarg/shiny-edit-data - Edit data app POC (R)
README
---
output: github_document
---```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```# tableEditor
[](https://lifecycle.r-lib.org/articles/stages.html#experimental)
The goal of tableEditor is to provide an interactive data editor.
## Notes
The app is still very much experimental and performances are not optimal.
## Installation
You can install the development version of tableEditor from [GitHub](https://github.com/) with:
``` r
# install.packages("devtools")
devtools::install_github("DivadNojnarg/shiny-edit-data")
```## Example
This package allows to deploy a data editor in few steps.
1. Create a config file `config.yml`:
- `production`: if FALSE, you are allowed to reset the data by clicking on the reset
button (invisible in production). The default data are defined in `data_reset`.
- `version`: Metadata displayed in the footer.
- `db_name`, `db_user`: Database name and user. They are not secrets. Password and host are
stored in environment variables, be careful not to expose them.
- `db_data_name`: Table which contains data to edit. Note: a metadata table is also created
- `db_admins_name`: A table containing admin data. Mandatory.
- `filter_cols`: Leave empty to select all columns. All passed columns will be saved in the database.
- `edit_cols`: Must be a subset of `filter_cols` if the latter is not empty. These columns are editable.
- `hidden_cols`: There might be columns in `filter_cols` that need to be
in the database but not shown in the table. Must be a subset of `filter_cols` if the latter is not empty.
Will error if any of `hidden_cols` is found in `edit_cols`.
- `col_defs`: Pass custom reactable `colDef` options. Expect a named list (see package examples). `col_defs` names must not belong to `hidden_cols` and has to be a subset of `filter_cols` or the data of edit if `filter_cols` is empty.
- `page_size`: control the number of rows to display.
- `status_ok`, `status_review`, ...: The app assumes 4 data states. First, data are in `OK` state, which means they are unchanged. As soon as someone modifies the data, they become `IN REVIEW`. The app supports an admin mode, where one can validate or invalidate the changes resulting in 2 other data states, respectively `ACCEPTED` and `REJECTED`. Once validated any further change will reset the validation state such that data are `IN REVIEW`.
- `data_reset`: dataset used to reset data. Only in development mode when `production` is FALSE.```yaml
# Below are the supported default items.
production: false
version: 0.1.0
db_name: "DB_NAME"
db_user: "DB_USER"
db_data_name: "DATA_TABLE_NAME"
db_admins_name: "ADMINS_TABLE_NAME"
admin_type_col: "type"
admin_user_col: "user"
filter_cols: !expr c()
edit_cols: !expr c()
hidden_cols: !expr c()
col_defs: !expr list()
status_ok: "OK"
status_review: "IN REVIEW"
status_accepted: "ACCEPTED"
status_rejected: "REJECTED"
data_reset: !expr datasets::iris
```2. Create the tables. We need 2 tables: one for admin check and one for the main
data to edit. The admin check is based on the `admin_type_col` and `admin_user_col `config values.
Be careful to pass correct column names in the admin table. Below, the corresponding column is `type` (if you change it,
don't forget to update the config). We also create an example table with iris data.```r
library(DBI)con <- dbConnect(
RPostgres::Postgres(),
dbname = 'DB_NAME',
host = 'HOST', # i.e. 'ec2-54-83-201-96.compute-1.amazonaws.com'
port = PORT, # or any other port specified by your DBA
user = 'USER',
password = 'PSWD'
)# Admin data
admin_dat <- dplyr::tribble(
~user, ~type, ~name, ~department, ~position,
"johndo1", "user", "John Doe", "IT", "Data Scientist",
"admin1", "admin", "Admin", "IT", "Leader"
)dbWriteTable(con, "admins", admin_dat)
# Create dummy table with iris data + an extra metadata table containing
# the columnes types in order to be able to restore factors (in SQL, factors are lost).
prepare_data(con, iris, overwrite = TRUE)
```3. Create an `app.R` script starting by the configuration linking.
```{r eval=FALSE}
options("yaml.eval.expr" = TRUE, "app.config.path" = "")tableEditor::run()
```4. Deploy to a server and enjoy. Don't forget to setup the environment variables
to connect to the database!## App flow
How this app works (WIP):
```mermaid
graph TD;
subgraph database
db[(Database)]
end
subgraph init_mod
init --> con_valid[DB available?] <==> |Ckecking Pool| db
con_valid --x |FALSE| stop[Stop]
init --> get_user[Valid user?] --x |FALSE| user_null[Stop]
get_user --> |TRUE| is_admin[Is admin?]
end
subgraph refresh_mod
con_valid --> |TRUE| refresh_data[Get data] ===> |Polling| db
db ==x |DB not available| stop_refresh[Stop]
db ==> |DB available| refresh_data
refresh_data --> |processing| process_data[App data] --> |update| lock_rows[Lock rows]
end
lock_rows --> table
is_admin --> |conditional display| table
subgraph table
data_table[Table]
end
table --> |Edit button| lock_row
subgraph lock_mod
lock_row[Lock row] --> |save| db
end
unlock_row --> db
subgraph unlock_mod
close_edit_modal[Close edit modal] --> |No DB revision| unlock_row[Unlock row]
end
table --> |update fields| can_save[Can save?]
subgraph allow_save_mod
can_save
end
can_save --> |toggle save| save_data
subgraph save_data_mod
save_data[Save data] --> db
end
subgraph reset_mod[Reset mod: dev only]
reset .-> db
end
table ---> |If admin| validate_mod
save_data --> |reset| validate_mod
subgraph validate_mod
accept[Accept changes] --> db
reject[Reject changes] --> db
end
```