--- title: "Manage tabs" linkTitle: "Manage tabs" type: docs weight: 2 --- ***** ## SPS tabs In SPS, **tab** is the basic component of a functionality unit. For example, all the [Modules](/sps/modules/) in SPS are complex tabs with many small sub-tabs, the [Canvas](/sps/canvas/) is another independent tab providing image editing features and an *user custom tab* is also a SPS tab. From the developer's view, all SPS tabs are [Shiny Modules{blk}](https://shiny.rstudio.com/articles/modules.html). To understand how SPS tabs work, we will demonstrate with a SPS project. For demo purpose, we are using the `/tmp` folder but one should use a regular location instead of the temp in a real case. ```{r collapse=TRUE} suppressPackageStartupMessages(library(systemPipeShiny)) spsInit(app_path = tempdir(), project_name = "tab_demo", overwrite = TRUE, change_wd = FALSE) ## save project path (sps_dir <- file.path(tempdir(), "tab_demo")) ``` To reproduce code locally, run the following chunk instead. ```{r eval=FALSE} library(systemPipeShiny) spsInit() sps_dir <- normalizePath(".") ``` ## Tab registration In SPS, all tabs are controlled by the *config/tabs.csv* file. To see what kind of tabs you have with current project. use the `spsTabInfo` function. It returns a tibble of current tab information. ```{r} spsTabInfo(app_path = sps_dir) ``` - **tab_id**: A unique string ID - **display_label**: for type is "core" or "module", this is only some description, but for you own custom tabs, this value will be used as a display tab name on left sidebar on SPS UI. - **type**: tab category, "core", "module" and "vs" (visualization). - **type_sub**: more specific category, current only "plot" (plotting) - **image**: If this is an user custom tab, providing an image path will display the image in visualization main tab gallery. If it not provided, a warning will be given on app starts and an "No image" image will be used like the following: ![vs_main](../vs_main.png) - **displayed**: Internal use only - **tab_file_name**: where the tab file is relative to the `R` folder. - **plugin**: Internal use only ## Add a new custom tab SPS provides templates to help developers to create a small SPS tab that 1. The main purpose is to generate some plots 2. can be loaded into SPS framework easily 3. can interact with other SPS tabs (components), like the Canvas tab. When you initiate a SPS project, an example custom tab is created for you already. You can find the tab file inside the `R` folder of the project root. When you start the app for the first time, you can easily find it from the left sidebar, or click on the "Custom tabs" to go to custom tab main tab.
![](../new_tab_before.png) Example custom tab
### Simple template Under current SPS version, users are able to add custom tabs with the `spsNewTab` function. This function: 1. creates the tab file. 2. provides a nice template. 3. Helps you to register tab information to `tabs.csv` ```{r collapse=TRUE} spsNewTab(tab_id = "vs_new", tab_displayname = "New tab demo", app_path = sps_dir) ``` If you are running the code locally, and are using Rstudio, the tab file will be opened automatically for you. In your `global.R`, add the new tab to confirm you want to load it, and then restart you app. Scroll down to the bottom, you should see: ```{r, eval=FALSE} # add "vs_new" in `tabs` sps_app <- sps( tabs = c("vs_example", "vs_new"), server_expr = { msg("Custom expression runs -- Hello World", "GREETING", "green") } ) ```
![](../new_tab_after.png) Load new custom tabs
By default, it uses the simple template, which contains the `spsEzUI` and `spsEzServer` functions. We have provided commented instructions on how to fill each argument. #### UI ```{r eval=FALSE} spsEzUI( desc = "xxx", tab_title = "xxx", plot_title = "xxx", plot_control = shiny::tagList( xxx ) ) ``` The only augment new users need to take some time to learn is adding `plot_control`. Developers need to add some Shiny UI components to let users control how the plotting is done with interactive options. Basic use can be learned in 5 minutes on [Shiny website{blk}](https://shiny.rstudio.com/articles/basics.html) and [Shiny book{blk}](https://mastering-shiny.org/basic-ui.html) #### Server ```{r eval=FALSE} spsEzServer( plot_code = { # data passed from data loading is a reactiveValues object, data stored in `mydata$data` plot_data <- mydata$data # some validations, make sure users give you the right data format spsValidate({ stopifnot(inherits(plot_data, "data.frame")) # require a dataframe stopifnot(nrow(plot_data) > 1) # has least one row if (!all(c("Sepal.Length", "Sepal.Width") %in% colnames(plot_data)))# has two required columns stop("Require column 'Sepal.Length' and 'Sepal.Width'") TRUE # give it a TRUE if all checks passed. }, verbose = FALSE # only show messages when fail ) # actual plot code ggplot2::ggplot(plot_data) + ggplot2::geom_point(ggplot2::aes(x = Sepal.Length, y = Sepal.Width)) + # grab user defined title from plot control by `input$+control_ID`, # no need to add `ns()` on server end. ggplot2::ggtitle(input$plot_title) }, other_server_code = {} ) ``` For the server code, users only need to focus on the plotting code. The only very important thing developers need to remember is that the plotting data been passed to this function is stored in a [reactiveValues{blk}](https://shiny.rstudio.com/reference/shiny/0.11/reactiveValues.html) object and it is called `mydata$data`. Usually we assign it to a new value so it can be used easily downstream, like `plot_data <- mydata$data`. Some validation is recommended before reaching the plotting code. You would never know what kind of dataset users upload. It is always good to check if users' uploads meet the requirements. In SPS you can use the `spsValidate` function or use Shiny's default [validate{blk}](https://shiny.rstudio.com/reference/shiny/0.14/validate.html) function (`spsValidate` is discussed in [developer tools](/sps/dev/spscomps/server/)). ### Full template For some developers who already has experience with Shiny, and would like to make more complex customization, using the full template enables you to change every detail on the new tab. Simply add the `template = "full"` argument. ```{r collapse=TRUE} spsNewTab( tab_id = "vs_new_full", tab_displayname = "New tab demo", template = "full", app_path = sps_dir) ``` You can see the full template is a lot longer than the simple template: ```{r} simple_len <- R.utils::countLines(file.path(sps_dir, "R", "tab_vs_new.R")) full_len <- R.utils::countLines(file.path(sps_dir, "R", "tab_vs_new_full.R")) spsinfo(glue::glue("Simple template has {simple_len} lines"), TRUE) spsinfo(glue::glue("Full template has {full_len} lines"), TRUE) ``` ## Tab registeration In your *global.R*, scroll down to the bottom, you should see: ```{r, eval=FALSE} sps_app <- sps( tabs = c("vs_example"), server_expr = { msg("Custom expression runs -- Hello World", "GREETING", "green") } ) ``` This is the SPS main function. You can load/unload custom tabs by providing tab IDs in `tabs` argument, like `c("tab1", "tab2)`. Open `config/tabs.csv` or use `spsTabInfo()` to see what tabs IDs can be load and other tab information. Essential framework tabs (*core*) and built-in modules (*modules*) are loaded automatically. However, you can choose to [unload core and modules tabs](../displaytabs), and [overwrite core tabs](../overwritetabs) by changing some [SPS options](../config). ## Tab naming Once a tab ID is provided in the `sps` function `tabs` argument, when the function runs, it is looking for tab information inside this `tabs.csv`, like the display name and tab image. Then it will search for the UI and server function in the enviornment. It is expecting a UI function named `tab_id` + `UI` -> `tab_idUI` and the server `tab_id` + `Server` -> `tab_idServer`. If you did not use the `spsNewTab` function to generate the new tab, make sure you name your tab UI and server in this pattern.