@@ -17,12 +17,86 @@ tags:
1717# 1. Add code blocks for [ loc] ( https://github.com/LabOnoM/ShinyAppsManager )
1818
1919## Basic functions
20- 1 . Handle crash
21- 2 . Email notification
22- 3 . Communications with [ loc] ( https://github.com/LabOnoM/ShinyAppsManager ) based on [ jwt] ( https://en.wikipedia.org/wiki/JSON_Web_Token )
20+ 1 . Handle crash (inside ** header** of navbarPage)
21+ 2 . Handle shiny theme selection
22+ 3 . Handle live console
23+ 4 . Email notification (inside ** header** of navbarPage)
24+ 5 . Live Console (inside ** footer** of navbarPage)
25+ 6 . Communications with [ loc] ( https://github.com/LabOnoM/ShinyAppsManager ) based on [ jwt] ( https://en.wikipedia.org/wiki/JSON_Web_Token ) (inside ** header** of navbarPage)
2326
24- Example codes:
27+ Helper functions (global.R)
2528``` R
29+ # Get Info ----
30+ print_to_console <- function (msg ) {
31+ js_line <- gsub(" \\\\ " , " \\\\\\\\ " , msg )
32+ js_line <- gsub(" \" " , " \\\\\" " , js_line )
33+ shinyjs :: runjs(sprintf(
34+ " if (document.getElementById('console')) {
35+ let el = document.getElementById('console');
36+ let lines = el.innerText.split('\\ n');
37+ if (lines.length > 2000) {
38+ lines = lines.slice(lines.length - 1999); // keep last 1999 lines
39+ }
40+ lines.push(\" %s\" );
41+ el.innerText = lines.join('\\ n');
42+ el.scrollTop = el.scrollHeight;
43+ } else {
44+ console.warn('#console element not found!');
45+ }" ,
46+ js_line
47+ ))
48+ return (js_line )
49+ }
50+ # 获取当前登录用户邮箱
51+ get_user_email <- function (token ){
52+ headers <- add_headers(`Token` = token , `Content-Type` = " application/json" )
53+ res <- try(GET(' http://10.2.26.152:7156/sqx_fast/app/user/info' , headers ), silent = TRUE )
54+ if (! inherits(res , " try-error" ) && status_code(res ) == 200 ){
55+ res_data <- fromJSON(content(res , " text" , encoding = " UTF-8" ))
56+ return (res_data $ data $ email )
57+ }
58+ return (NA )
59+ }
60+ if (! is.na(Sys.getenv(" SHINY_SERVER_VERSION" , unset = NA ))){
61+ smtp_creds <- creds_envvar(
62+ user = Sys.getenv(" EMAIL_USER" ),
63+ pass_envvar = " EMAIL_PASS" ,
64+ host = " smtp.gmail.com" ,
65+ port = 587 ,
66+ use_ssl = TRUE
67+ )
68+ email <- " Email_Template.html" %> % file.path(" .." , " GlobalEnvironment" , . ) %> % readLines(. , , warn = FALSE ) %> %
69+ paste(. , collapse = " \n " ) %> % HTML() %> % compose_email(body = . )
70+ email_fail <- " Email_Template_fail.html" %> % file.path(" .." , " GlobalEnvironment" , . ) %> % readLines(. , , warn = FALSE ) %> %
71+ paste(. , collapse = " \n " ) %> % HTML() %> % compose_email(body = . )
72+ # get user home
73+ UsrHome <- file.path(" /mnt" ," Public" )
74+ }else {
75+ UsrHome <- path_home() %> % as.character()
76+ }
77+ options(shiny.fullstacktrace = TRUE )
78+ ```
79+
80+ Example codes: Error Trigger (server.R):
81+ ``` R
82+ tryCatch(
83+ . , error = function (e ) {
84+ isolate(values $ error_state <- paste0(" Error:\n " , e $ message ))
85+ showNotification(e $ message , type = " error" )
86+ return (NULL )
87+ })
88+ ```
89+
90+ Example codes (server.R):
91+ ``` R
92+ # Initiation ----
93+ px <- reactiveVal(NULL )
94+ # Make reactive values ----
95+ values <- reactiveValues(
96+ is_on_shiny_server = ! is.na(Sys.getenv(" SHINY_SERVER_VERSION" , unset = NA ))
97+ )
98+ para <- reactiveValues()
99+
26100 # Fetch information if running on BSGOU loc (local allocation controller) system.
27101 observe({
28102 req(values $ is_on_shiny_server )
@@ -96,7 +170,120 @@ Example codes:
96170 observeEvent(input $ Crash_modal_ok , {
97171 shiny :: removeModal()
98172 })
173+ # Handle shiny theme selection ----
174+ observe({
175+ req(is.null(para $ UI_Init ))
176+ updateSelectInput(
177+ session = session , inputId = " shinytheme-selector" ,
178+ selected = " yeti"
179+ )
180+ isolate(para $ UI_Init <- " Done" )
181+ })
182+ # Handle live console----
183+ # Clean console history
184+ observeEvent(input $ clear_console , {
185+ runjs("
186+ var consoleEl = document.getElementById('console');
187+ if (consoleEl) {
188+ consoleEl.innerText = '';
189+ } else {
190+ console.warn('#console element not found!');
191+ }
192+ " )
193+ isolate({values $ console_log <- NULL })
194+ })
195+ # Download console monitor log
196+ output $ download_console <- downloadHandler(
197+ filename = function () {
198+ paste0(" console_log_" , Sys.Date(), " .log" )
199+ },
200+ content = function (file ) {
201+ writeLines(values $ console_log , file )
202+ }
203+ )
204+
205+
206+ # Session End Function ----
207+ # Shutdown everything if connection closed
208+ session $ onSessionEnded(function () {
209+ if (! is.na(Sys.getenv(" SHINY_SERVER_VERSION" ))){
210+ headers <- add_headers(`Token` = session $ userData $ token , `Content-Type` = " application/json" )
211+ connect_req_end = list (`appName` = session $ userData $ appName , `action` = " disconnect" , `id` = session $ userData $ id )
212+ connect_end_data <- try(
213+ url_execute(
214+ 2 , ' http://10.2.26.152/sqx_fast/app/workstation/shiny-connect-action' ,
215+ toJSON(connect_req_end , pretty = FALSE , auto_unbox = TRUE ), headers
216+ ), silent = TRUE
217+ )
218+ }
219+ stopApp()
220+ })
99221```
100222
223+ Example codes (ui.R):
224+ ``` R
225+ # # For BSGOU ----
226+ header = tagList(
227+ # ## For lac system----
228+ uiOutput(" conditional_head" ), # # start-1嵌入代码开始,作用:异常跳转到预约系统首页
229+ # # Costume CSS----
230+ tags $ style(HTML(
231+ ' .navbar-nav > li > a, .navbar-brand {
232+ padding-top: 3px !important;
233+ padding-bottom: 0px !important;
234+ margin-top: 2px;
235+ margin-bottom: 0px;
236+ height: 25px;
237+ }
238+ .navbar {
239+ min-height:26px !important;
240+ z-index:99999 !important;
241+ margin-top: 1px;
242+ margin-bottom: 1px;
243+ }'
244+ )),
245+ tags $ head(
246+ # # Google Analytics----
247+ # Embed Google Analytics
248+ tags $ script(async = NA , src = " https://www.googletagmanager.com/gtag/js?id=G-RWF876HNKW" ),
249+ tags $ script(HTML("
250+ window.dataLayer = window.dataLayer || [];
251+ function gtag(){dataLayer.push(arguments);}
252+ gtag('js', new Date());
253+ gtag('config', 'G-RWF876HNKW');
254+ " )),
255+ # # Favicons----
256+ tags $ link(rel = " icon" , type = " image/png" , sizes = " 32x32" , href = " GREP1_Logo_32x32.png" ),
257+ tags $ link(rel = " icon" , type = " image/png" , sizes = " 16x16" , href = " GREP1_Logo_32x32.png" )
258+ ),
259+ h5(HTML(
260+ " <strong>B</strong>ulk <strong>R</strong>NA-seq <strong>A</strong>uto-<strong>P</strong>ipeline"
261+ ))
262+ ),
263+ # # Live Console----
264+ footer = absolutePanel(
265+ id = " ConsoleRealTime" , class = " panel panel-default" ,
266+ bottom = 50 , left = 25 , width = " 75%" , fixed = FALSE ,
267+ draggable = TRUE , height = " 100px" ,
268+ style = " opacity: 0.95; z-index: 20;" , # # z-index modification
269+ uiOutput(" EmailNotif_ui" ),
270+ # Horizontal bar
271+ tags $ div(
272+ style = " display: flex; align-items: center; gap: 10px; padding-left: 5px;" ,
273+ HTML(' <button data-toggle="collapse" data-target="#GlobalSettingMainPanel">Collapse</button>' ),
274+ tags $ a(" Console Monitor" ),
275+ downloadButton(" download_console" , " 💾 Download Console Log" ),
276+ actionButton(" clear_console" , " 🧹 Clear Console" , icon = icon(" eraser" ), class = " btn-danger" )
277+ ),
278+ tags $ div(
279+ id = " GlobalSettingMainPanel" ,
280+ style = " max-height: 300px; overflow-y: auto; padding: 5px;" ,
281+ tags $ div(
282+ id = " console" ,
283+ style = " white-space: pre-wrap; font-family: monospace; background-color: #111; color: #0f0; height: 280px; overflow-y: scroll; padding: 10px; border: 1px solid #333;"
284+ )
285+ )
286+ ),
287+ ```
101288# 2. Convert Main loop with [ processx] ( https://github.com/r-lib/processx )
102289
0 commit comments