Skip to content

Commit 3295a21

Browse files
authored
Merge pull request #597 from massimoaria/develop
Develop
2 parents 450bb19 + 67db936 commit 3295a21

3 files changed

Lines changed: 252 additions & 8 deletions

File tree

inst/biblioshiny/openalex_api.R

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,19 @@ resolve_openalex_references <- function(oa_data, progress_id = NULL,
690690

691691
if (length(all_ref_ids) == 0) return(list())
692692

693+
# Update progress with actual count after filtering
694+
if (!is.null(progress_id)) {
695+
filter_label <- if (isTRUE(only_multiple)) " (cited > 1)" else ""
696+
shinyjs::html(
697+
progress_id,
698+
sprintf(
699+
"Resolving %s unique references%s...",
700+
format(length(all_ref_ids), big.mark = ","),
701+
filter_label
702+
)
703+
)
704+
}
705+
693706
# Batch fetch referenced works (50 per batch to stay within URL limits)
694707
batch_size <- 50
695708
n_batches <- ceiling(length(all_ref_ids) / batch_size)

inst/biblioshiny/server.R

Lines changed: 238 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,7 +1527,7 @@ To ensure the functionality of Biblioshiny,
15271527
if (isTRUE(input$importFetchRefs)) {
15281528
# Check if CR column has actual reference IDs (old format) or is empty/NA (new format)
15291529
has_cr_ids <- "CR" %in% names(M) && any(!is.na(M$CR) & M$CR != "")
1530-
only_multiple <- isTRUE(input$importRefsFilter == "multiple")
1530+
only_multiple <- is.null(input$importRefsFilter) || input$importRefsFilter == "multiple"
15311531

15321532
showModal(modalDialog(
15331533
title = "Resolving Cited References",
@@ -1770,6 +1770,230 @@ To ensure the functionality of Biblioshiny,
17701770
dbsource = input$dbsource,
17711771
format = "api"
17721772
)
1773+
1774+
# Resolve cited references if requested
1775+
if (isTRUE(input$importFetchRefs)) {
1776+
has_cr_ids <- "CR" %in% names(M) && any(!is.na(M$CR) & M$CR != "")
1777+
only_multiple <- is.null(input$importRefsFilter) || input$importRefsFilter == "multiple"
1778+
1779+
showModal(modalDialog(
1780+
title = "Resolving Cited References",
1781+
div(
1782+
div(
1783+
style = "text-align: center; margin: 20px 0;",
1784+
icon("spinner", class = "fa-spin fa-3x")
1785+
),
1786+
div(
1787+
id = "import-ref-progress",
1788+
style = "text-align: center; font-size: 14px;",
1789+
"Collecting reference IDs..."
1790+
),
1791+
div(
1792+
style = "margin-top: 10px; background-color: #e9ecef; border-radius: 4px; height: 20px; width: 100%;",
1793+
div(
1794+
id = "import-ref-bar",
1795+
style = "background-color: #007bff; height: 100%; border-radius: 4px; width: 0%; transition: width 0.3s ease;"
1796+
)
1797+
),
1798+
div(
1799+
id = "import-ref-pct",
1800+
style = "text-align: center; margin-top: 5px; font-size: 12px; color: #666;",
1801+
"0%"
1802+
)
1803+
),
1804+
footer = NULL,
1805+
easyClose = FALSE
1806+
))
1807+
1808+
tryCatch(
1809+
{
1810+
if (has_cr_ids) {
1811+
# CR column contains OpenAlex reference IDs (e.g. W1234567890)
1812+
all_cr <- M$CR[!is.na(M$CR) & M$CR != ""]
1813+
all_ref_ids <- unique(trimws(unlist(strsplit(all_cr, ";\\s*"))))
1814+
# Add OpenAlex URL prefix if missing
1815+
all_ref_ids <- ifelse(
1816+
grepl("^https://openalex\\.org/", all_ref_ids),
1817+
all_ref_ids,
1818+
paste0("https://openalex.org/", all_ref_ids)
1819+
)
1820+
all_ref_ids <- unique(all_ref_ids[grepl("^https://openalex\\.org/W", all_ref_ids)])
1821+
1822+
if (length(all_ref_ids) > 0) {
1823+
shinyjs::html(
1824+
"import-ref-progress",
1825+
sprintf(
1826+
"Resolving %s unique references...",
1827+
format(length(all_ref_ids), big.mark = ",")
1828+
)
1829+
)
1830+
1831+
oa_data_fake <- lapply(seq_len(nrow(M)), function(i) {
1832+
cr <- M$CR[i]
1833+
if (is.na(cr) || cr == "") {
1834+
list(referenced_works = character(0))
1835+
} else {
1836+
refs <- trimws(unlist(strsplit(cr, ";\\s*")))
1837+
refs <- ifelse(
1838+
grepl("^https://openalex\\.org/", refs),
1839+
refs,
1840+
paste0("https://openalex.org/", refs)
1841+
)
1842+
refs <- refs[grepl("^https://openalex\\.org/W", refs)]
1843+
list(referenced_works = refs)
1844+
}
1845+
})
1846+
1847+
ref_lookup <- resolve_openalex_references(
1848+
oa_data_fake,
1849+
progress_id = "import-ref-progress",
1850+
progress_bar_id = "import-ref-bar",
1851+
progress_pct_id = "import-ref-pct",
1852+
only_multiple = only_multiple
1853+
)
1854+
1855+
if (length(ref_lookup) > 0) {
1856+
shinyjs::html(
1857+
"import-ref-progress",
1858+
"Building citation strings..."
1859+
)
1860+
cr_col <- build_cr_column(oa_data_fake, ref_lookup)
1861+
M$CRids <- M$CR
1862+
M$CR <- cr_col
1863+
}
1864+
}
1865+
} else {
1866+
# No CR column: fetch referenced_works via API using id_oa
1867+
work_ids <- M$id_oa[!is.na(M$id_oa) & M$id_oa != ""]
1868+
if (length(work_ids) > 0) {
1869+
shinyjs::html(
1870+
"import-ref-progress",
1871+
sprintf(
1872+
"Fetching referenced works for %s publications...",
1873+
format(length(work_ids), big.mark = ",")
1874+
)
1875+
)
1876+
1877+
batch_size <- 50
1878+
n_batches <- ceiling(length(work_ids) / batch_size)
1879+
ref_map <- setNames(
1880+
vector("list", length(work_ids)),
1881+
work_ids
1882+
)
1883+
1884+
for (b in seq_len(n_batches)) {
1885+
start_idx <- (b - 1) * batch_size + 1
1886+
end_idx <- min(b * batch_size, length(work_ids))
1887+
batch_ids <- work_ids[start_idx:end_idx]
1888+
1889+
pct <- round(b / n_batches * 50)
1890+
shinyjs::runjs(sprintf(
1891+
"$('#import-ref-bar').css('width', '%d%%');",
1892+
pct
1893+
))
1894+
shinyjs::html(
1895+
"import-ref-pct",
1896+
sprintf(
1897+
"Fetching references... batch %d/%d (%d%%)",
1898+
b, n_batches, pct
1899+
)
1900+
)
1901+
1902+
tryCatch(
1903+
{
1904+
result <- openalexR::oa_fetch(
1905+
entity = "works",
1906+
openalex_id = paste(batch_ids, collapse = "|"),
1907+
output = "list",
1908+
verbose = FALSE
1909+
)
1910+
if (is.list(result)) {
1911+
for (work in result) {
1912+
wid <- gsub("https://openalex.org/", "", work$id)
1913+
if (!is.null(wid) && !is.null(work$referenced_works)) {
1914+
ref_map[[wid]] <- work$referenced_works
1915+
}
1916+
}
1917+
}
1918+
},
1919+
error = function(e) {}
1920+
)
1921+
}
1922+
1923+
oa_data_fake <- lapply(seq_len(nrow(M)), function(i) {
1924+
refs <- ref_map[[M$id_oa[i]]]
1925+
if (is.null(refs) || length(refs) == 0) {
1926+
list(referenced_works = character(0))
1927+
} else {
1928+
list(referenced_works = refs)
1929+
}
1930+
})
1931+
1932+
all_ref_ids <- unique(unlist(lapply(
1933+
oa_data_fake,
1934+
function(w) w$referenced_works
1935+
)))
1936+
all_ref_ids <- all_ref_ids[!is.na(all_ref_ids) & all_ref_ids != ""]
1937+
1938+
if (length(all_ref_ids) > 0) {
1939+
shinyjs::html(
1940+
"import-ref-progress",
1941+
sprintf(
1942+
"Resolving %s unique references...",
1943+
format(length(all_ref_ids), big.mark = ",")
1944+
)
1945+
)
1946+
1947+
ref_lookup <- resolve_openalex_references(
1948+
oa_data_fake,
1949+
progress_id = "import-ref-progress",
1950+
progress_bar_id = "import-ref-bar",
1951+
progress_pct_id = "import-ref-pct",
1952+
only_multiple = only_multiple
1953+
)
1954+
1955+
if (length(ref_lookup) > 0) {
1956+
shinyjs::html(
1957+
"import-ref-progress",
1958+
"Building citation strings..."
1959+
)
1960+
cr_col <- build_cr_column(oa_data_fake, ref_lookup)
1961+
M$CRids <- vapply(
1962+
oa_data_fake,
1963+
function(w) {
1964+
ids <- gsub("https://openalex.org/", "", w$referenced_works)
1965+
if (length(ids) == 0) NA_character_ else paste(ids, collapse = ";")
1966+
},
1967+
character(1)
1968+
)
1969+
M$CR <- cr_col
1970+
M$NR <- vapply(
1971+
oa_data_fake,
1972+
function(w) length(w$referenced_works),
1973+
integer(1)
1974+
)
1975+
}
1976+
}
1977+
}
1978+
}
1979+
1980+
removeModal()
1981+
},
1982+
error = function(e) {
1983+
removeModal()
1984+
showModal(modalDialog(
1985+
title = "Warning",
1986+
paste(
1987+
"Reference resolution failed:",
1988+
e$message,
1989+
"\nThe collection was imported without resolved references."
1990+
),
1991+
easyClose = TRUE,
1992+
footer = modalButton("OK")
1993+
))
1994+
}
1995+
)
1996+
}
17731997
},
17741998
lens = {
17751999
switch(
@@ -2271,44 +2495,51 @@ To ensure the functionality of Biblioshiny,
22712495
# Pre-processing del dataframe per aggiungere colori e formattazione
22722496
df_formatted <- df %>%
22732497
mutate(
2498+
# Bold formatting for Metadata and Description
2499+
Metadata = paste0('<strong style="font-size: 14px;">', Metadata, '</strong>'),
2500+
Description = paste0('<strong style="font-size: 14px;">', Description, '</strong>'),
2501+
`Missing Counts` = as.character(`Missing Counts`),
2502+
`Missing Counts` = paste0('<span style="font-size: 14px; font-weight: 600;">', `Missing Counts`, '</span>'),
2503+
22742504
# Arrotonda la colonna "Missing %" a 2 decimali
22752505
`Missing %` = round(`Missing %`, 2),
2506+
`Missing %` = paste0('<span style="font-size: 14px; font-weight: 600;">', `Missing %`, '</span>'),
22762507

22772508
# Aggiungi colori di background alla colonna Status basandosi sul valore
22782509
Status = case_when(
22792510
Status == "Completely missing" ~
22802511
paste0(
2281-
'<span style="display: block; background-color: #b22222; color: white; padding: 5px; text-align: center; border-radius: 3px;">',
2512+
'<span style="display: block; background-color: #b22222; color: white; padding: 5px; text-align: center; border-radius: 3px; font-size: 14px; font-weight: 700;">',
22822513
Status,
22832514
'</span>'
22842515
),
22852516
Status == "Critical" ~
22862517
paste0(
2287-
'<span style="display: block; background-color: #f08080; color: white; padding: 5px; text-align: center; border-radius: 3px;">',
2518+
'<span style="display: block; background-color: #f08080; color: white; padding: 5px; text-align: center; border-radius: 3px; font-size: 14px; font-weight: 700;">',
22882519
Status,
22892520
'</span>'
22902521
),
22912522
Status == "Poor" ~
22922523
paste0(
2293-
'<span style="display: block; background-color: lightgrey; color: black; padding: 5px; text-align: center; border-radius: 3px;">',
2524+
'<span style="display: block; background-color: lightgrey; color: black; padding: 5px; text-align: center; border-radius: 3px; font-size: 14px; font-weight: 700;">',
22942525
Status,
22952526
'</span>'
22962527
),
22972528
Status == "Acceptable" ~
22982529
paste0(
2299-
'<span style="display: block; background-color: #f0e68c; color: black; padding: 5px; text-align: center; border-radius: 3px;">',
2530+
'<span style="display: block; background-color: #f0e68c; color: black; padding: 5px; text-align: center; border-radius: 3px; font-size: 14px; font-weight: 700;">',
23002531
Status,
23012532
'</span>'
23022533
),
23032534
Status == "Good" ~
23042535
paste0(
2305-
'<span style="display: block; background-color: #90ee90; color: black; padding: 5px; text-align: center; border-radius: 3px;">',
2536+
'<span style="display: block; background-color: #90ee90; color: black; padding: 5px; text-align: center; border-radius: 3px; font-size: 14px; font-weight: 700;">',
23062537
Status,
23072538
'</span>'
23082539
),
23092540
Status == "Excellent" ~
23102541
paste0(
2311-
'<span style="display: block; background-color: #32cd32; color: white; padding: 5px; text-align: center; border-radius: 3px;">',
2542+
'<span style="display: block; background-color: #32cd32; color: white; padding: 5px; text-align: center; border-radius: 3px; font-size: 14px; font-weight: 700;">',
23122543
Status,
23132544
'</span>'
23142545
),

inst/biblioshiny/ui.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,7 @@ body <- dashboardBody(
11921192
)
11931193
),
11941194
conditionalPanel(
1195-
condition = "input.dbsource == 'openalex'",
1195+
condition = "input.dbsource == 'openalex' || input.dbsource == 'openalex_api'",
11961196
div(
11971197
style = "margin-bottom: 15px; padding: 12px; background-color: #d6eaf8; border-radius: 5px; border-left: 4px solid #3498db;",
11981198
checkboxInput(

0 commit comments

Comments
 (0)