Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow overview lessons #496

Merged
merged 42 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
c2061ef
change criteria for carpentries lesson
zkamvar Aug 8, 2023
a1fb322
update root criteria
zkamvar Aug 8, 2023
7f34eeb
add shortcut to syllabus creation
zkamvar Aug 8, 2023
780836b
add shortcut to format_syllabus
zkamvar Aug 8, 2023
b83278f
add shortcut to build_instructor_notes
zkamvar Aug 8, 2023
6706d5e
only process episode-dependent pages if we are not in an overview lesson
zkamvar Aug 8, 2023
9c51a0b
bump version
zkamvar Aug 8, 2023
676aabd
provision PR version of pegboard for this to work
zkamvar Aug 9, 2023
e7fa55e
first test of overview lessons
zkamvar Aug 9, 2023
3a3695e
fix mac issue
zkamvar Aug 9, 2023
fde80e4
add fix for windows
zkamvar Aug 9, 2023
90fb312
ugh THIS was the windows fix
zkamvar Aug 9, 2023
11e0ed9
do not remove renv folder in overview test
zkamvar Aug 9, 2023
f831cea
modify page_location to account for zero range
zkamvar Aug 9, 2023
2c9d6b5
refactor build_site
zkamvar Aug 9, 2023
e209690
add skip
zkamvar Aug 9, 2023
9c80e87
add setup token so renv stops complaining
zkamvar Aug 9, 2023
d5503c9
attempt to use different template
zkamvar Aug 9, 2023
e470def
add test for fixing overview metadata context
zkamvar Aug 11, 2023
9635169
set overview for metadata to be boolean
zkamvar Aug 11, 2023
55f497b
always set URL for metadata
zkamvar Aug 11, 2023
4270bdc
fix this weird little test thing
zkamvar Aug 11, 2023
ae8582d
set varnish version
zkamvar Aug 11, 2023
eb8ae62
Merge branch 'main' into allow-overview-lessons
zkamvar Aug 21, 2023
6129e7c
vectorize enforce_dir
zkamvar Aug 22, 2023
50ebd6b
copy overview assets if they exist
zkamvar Aug 22, 2023
e2bc41f
update some of the build component docs
zkamvar Aug 22, 2023
6598e16
add fix for weird home file badness
zkamvar Aug 22, 2023
429e9d5
set_config to actually use logical values
zkamvar Aug 22, 2023
40ff1c3
use official config setter in tests
zkamvar Aug 22, 2023
0babf1e
update set_config docs
zkamvar Aug 22, 2023
2f57438
add shortcut for parse_file_matches and update doc
zkamvar Aug 22, 2023
a81e943
set overview status on outset
zkamvar Aug 23, 2023
e1589c5
revamp test
zkamvar Aug 23, 2023
90aa8da
bump versions of varnish and pegboard
zkamvar Aug 24, 2023
e464378
add content tests for varnish home and setup links
zkamvar Aug 24, 2023
f60feed
use released pegboard
zkamvar Aug 29, 2023
43c6735
add dev pegboard
zkamvar Aug 29, 2023
2b13d19
Merge branch 'main' into allow-overview-lessons
zkamvar Aug 30, 2023
b62386b
Merge branch 'main' into allow-overview-lessons
zkamvar Aug 31, 2023
16e270b
use varnish default branch
zkamvar Sep 1, 2023
7af7bed
clean up news a bit
zkamvar Sep 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Description: We provide tools to build a Carpentries-themed lesson repository
License: MIT + file LICENSE
Imports:
pkgdown (>= 1.6.0),
pegboard (>= 0.5.1),
pegboard (>= 0.6.0),
cli (>= 3.4.0),
commonmark,
fs (>= 1.5.0),
Expand Down Expand Up @@ -68,7 +68,7 @@ Suggests:
jsonlite,
sessioninfo,
mockr,
varnish (>= 0.2.1)
varnish (>= 0.3.0)
Additional_repositories: https://carpentries.r-universe.dev/
Remotes:
ropensci/tinkr,
Expand Down
9 changes: 9 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@

## NEW FEATURES

* Overview style lessons that do not have episodic content can now be processed,
analysed, and built by {sandpaper}. To make your lesson an overview lesson,
you can add `overview: true` to your `config.yaml` (reported: @zkamvar,
https://github.com/carpentries/workbench/issues/65;
implemented: @zkamvar, #496)
* The new `spoiler` class of fenced div will allow authors to specify an
expandable section of content that is collapsed by default. This replaces the
former paradigm of using "floating solution" blocks to present options for
installation on different platforms. (implemented: @tobyhodges, #502)

## BUG FIX

* Internal function `root_path()` will no longer fail if the `episodes/` folder
does not exist as long as one of the other four folders (`site/`, `learners/`,
`instructors/`, `profiles/`) exists (fixed: @zkamvar, #496)
* `set_config()` can now properly process logical values into `true` and `false`
* R Markdown documents with modificiations to child documents will now take into
account changes to the child documents (reported @jcolomb, #497; fixed
@zkamvar, #498).
Expand Down
40 changes: 35 additions & 5 deletions R/build_home.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
#' Build a home page for a lesson
#'
#' @param pkg a list generated from [pkgdown::as_pkgdown()] from the `site/`
#' folder of a lesson.
#' @param quiet a boolean passed to [build_html()]. if `TRUE`, this will have
#' pkgdown report what files are being built
#' @param next_page the next page file name. This will allow the navigation
#' element to be set up correctly on the navigation bar
#' @return nothing. This is used for its side-effect
#'
#' @keywords internal
#' @details The index page of the lesson is a combination of two pages:
#'
#' 1. index.md (or README if the index does not exist)
#' 2. learners/setup.md
#'
#' This function uses [render_html()] to convert the page into HTML, which gets
#' passed on to the "syllabus" or "overview" templates in {varnish} (via the
#' [build_html()] function as the `{{{ readme }}}` and `{{{ setup }}}` keys.
build_home <- function(pkg, quiet, next_page = NULL) {
page_globals <- setup_page_globals()
path <- root_path(pkg$src_path)
syl <- format_syllabus(get_syllabus(path, questions = TRUE), use_col = FALSE)
syl <- format_syllabus(get_syllabus(path, questions = TRUE),
use_col = FALSE)
idx <- fs::path(pkg$src_path, "built", "index.md")
readme <- fs::path(pkg$src_path, "built", "README.md")
idx_file <- if (fs::file_exists(idx)) idx else readme
Expand All @@ -21,7 +41,8 @@ build_home <- function(pkg, quiet, next_page = NULL) {
setup <- xml2::read_html(setup)
fix_nodes(setup)

nav <- get_nav_data(idx_file, fs::path_file(idx_file), page_forward = next_page)
idx_src <- fs::path(path, fs::path_file(idx_file))
nav <- get_nav_data(idx_file, idx_src, page_forward = next_page)
needs_title <- nav$pagetitle == ""

if (needs_title) {
Expand All @@ -43,18 +64,27 @@ build_home <- function(pkg, quiet, next_page = NULL) {

nav$pagetitle <- NULL
page_globals$metadata$update(nav)
is_overview <- identical(page_globals$metadata$get()$overview, TRUE)
if (is_overview) {
template <- "overview"
} else {
template <- "syllabus"
}

build_html(template = "syllabus", pkg = pkg, nodes = list(html, setup),
build_html(template = template, pkg = pkg, nodes = list(html, setup),
global_data = page_globals, path_md = "index.html", quiet = quiet)

}


format_syllabus <- function(syl, use_col = TRUE) {
if (nrow(syl) == 0L) {
return("<p></p>")
}
syl$questions <- gsub("\n", "<br/>", syl$questions)
syl$number <- sprintf("%2d\\. ", seq(nrow(syl)))
links <- glue::glue_data(
syl[-nrow(syl), c("number", "episode", "path")],
syl[-nrow(syl), c("number", "episode", "path")],
"{gsub('^[ ]', '&nbsp;', number)}<a href='{fs::path_file(path)}'>{episode}</a>"
)
if (use_col) {
Expand All @@ -73,5 +103,5 @@ format_syllabus <- function(syl, use_col = TRUE) {
tmp <- tempfile(fileext = ".md")
on.exit(unlink(tmp), add = TRUE)
writeLines(out, tmp)
render_html(tmp)
return(render_html(tmp))
}
46 changes: 43 additions & 3 deletions R/build_html.R
Original file line number Diff line number Diff line change
@@ -1,11 +1,51 @@
#' Build instructor and learner HTML page
#'
#' @param template the name of the {varnish} template to use. Defaults to
#' "chapter"
#' @param pkg an object created from [pkgdown::as_pkgdown()]
#' @param nodes an `xml_document` object. In the case of using this for the
#' index page (from [build_home()]), `nodes` will be a list of two
#' `xml_documents`; one for instructors and one for learners so that the
#' instructors have the schedule available to them (however, this might be a
#' relic, Zhian needs to inspect it).
#' @param global_data a list store object that contains copies of the global
#' variables for the page, including metadata, navigation, and variables for
#' the {varnish} templates.
#' @param path_md the path (absolute, relative, or filename) the current
#' markdown file being processed.
#' @param quiet This parameter is passed to [pkgdown::render_page()] and will
#' print the progress if `TRUE` (default).
#' @return `TRUE` if the page was built and `NULL` if it did not need to be
#' rebuilt
#' @keywords internal
#'
#' @details This function is a central workhorse that connects the global
#' lesson metadata and the global variables for each page to the rendering
#' engine: {pkgdown}. It will perform the global operations that includes
#' setting up the navigation, adding metadata, and building both the instructor
#' and learner versions of the page.
#'
#' In the Workbench, there are three types of pages:
#'
#' 1. primary content pages: these are primary content with a 1:1 relationship
#' between the source and the output. These are episodes along with custom
#' learner and instructor content
#' 2. aggregate content pages: pages that are aggregated from other pages such
#' as key points, all-in-one, images
#' 3. concatenated content pages: concatenations of source files and potentially
#' aggregate data. Examples are index, learner profiles, and the instructor
#' notes pages.
#'
#' Each of these types of pages have their own process for setting up content,
#' which gets processed before its passed here.
build_html <- function(template = "chapter", pkg, nodes, global_data, path_md, quiet = TRUE) {
ipath <- fs::path(pkg$dst_path, "instructor")
if (!fs::dir_exists(ipath)) fs::dir_create(ipath)

this_page <- as_html(path_md, instructor = TRUE)
meta <- global_data$metadata
base_url <- meta$get()$url

# Handle the differences between instructor and learner views for the index page
if (inherits(nodes, "xml_document")) {
instructor_nodes <- nodes
Expand All @@ -19,7 +59,7 @@ build_html <- function(template = "chapter", pkg, nodes, global_data, path_md, q
update_sidebar(global_data$instructor, instructor_nodes, path_md)
meta$set("url", paste0(base_url, this_page))
global_data$instructor$set("json", fill_metadata_template(meta))
modified <- pkgdown::render_page(pkg,
modified <- pkgdown::render_page(pkg,
template,
data = global_data$instructor$get(),
depth = 1L,
Expand All @@ -33,7 +73,7 @@ build_html <- function(template = "chapter", pkg, nodes, global_data, path_md, q
update_sidebar(global_data$learner, learner_nodes, path_md)
meta$set("url", paste0(base_url, this_page))
global_data$learner$set("json", fill_metadata_template(meta))
pkgdown::render_page(pkg,
pkgdown::render_page(pkg,
template,
data = global_data$learner$get(),
depth = 0L,
Expand Down
7 changes: 6 additions & 1 deletion R/build_instructor_notes.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#' (for future use)
build_instructor_notes <- function(pkg, pages = NULL, built = NULL, quiet) {
path <- root_path(pkg$src_path)
this_lesson(path)
lsn <- this_lesson(path)
outpath <- fs::path(pkg$dst_path, "instructor-notes.html")
already_built <- template_check$valid() &&
fs::file_exists(outpath) &&
Expand Down Expand Up @@ -37,6 +37,11 @@ build_instructor_notes <- function(pkg, pages = NULL, built = NULL, quiet) {
build_html(template = "extra", pkg = pkg, nodes = html,
global_data = page_globals, path_md = "instructor-notes.html", quiet = TRUE)
}
# shortcut if we don't have any episodes
is_overview <- lsn$overview && length(lsn$episodes) == 0
if (is_overview) {
return(invisible(NULL))
}
agg <- "/div[contains(@class, 'instructor-note')]//*[@class='accordion-body' or @class='accordion-header']"
build_agg_page(pkg = pkg,
pages = pages,
Expand Down
37 changes: 24 additions & 13 deletions R/build_markdown.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ build_markdown <- function(path = ".", rebuild = FALSE, quiet = FALSE, slug = NU
create_site(path)
}
# check if the lesson needs to be reset
this_lesson(path)
lsn <- this_lesson(path)

episode_path <- path_episodes(path)
outdir <- path_built(path)
outdir <- path_built(path)

# Determine build status for the episodes ------------------------------------
sources <- get_build_sources(path, outdir, slug, quiet)
Expand Down Expand Up @@ -56,16 +55,7 @@ build_markdown <- function(path = ".", rebuild = FALSE, quiet = FALSE, slug = NU
}, add = TRUE)

# Copy the files to the assets directory -------------------------------------
artifacts <- get_artifacts(path, "episodes")
to_copy <- vapply(
c("data", "files", "fig"),
FUN = function(i) enforce_dir(fs::path(episode_path, i)),
FUN.VALUE = character(1)
)
to_copy <- c(to_copy, artifacts)
for (f in to_copy) {
copy_assets(f, outdir)
}
copy_build_assets(path, outdir, overview = lsn$overview)

# Remove detritus ------------------------------------------------------------
remove <- db$remove
Expand Down Expand Up @@ -146,6 +136,27 @@ build_markdown <- function(path = ".", rebuild = FALSE, quiet = FALSE, slug = NU
invisible(db$build)
}

copy_build_assets <- function(path, outdir, overview = FALSE) {
path <- root_path(path)
# get all the non-markdown files
artifacts <- get_source_artifacts(path, "episodes")
resource_folders <- c("data", "files", "fig")
# enforce dir will create a directory if it doesn't exist, so that it's
# always available for the user, even if git is not tracking it.
to_copy <- enforce_dir(fs::path(path, "episodes", resource_folders))
to_copy <- c(to_copy, artifacts)
if (overview) {
# overview lessons are special, so we are going to explicitly search the top
# directory for the resource folders and then copy them only if they exist
needed <- fs::dir_ls(path, type = "directory")
needed <- needed[fs::path_file(needed) %in% resource_folders]
to_copy <- c(needed, to_copy)
}
for (f in to_copy) {
copy_assets(f, outdir)
}
}

remove_rendered_html <- function(episodes) {
htmls <- fs::path_ext_set(episodes, "html")
exists <- fs::file_exists(htmls)
Expand Down
42 changes: 27 additions & 15 deletions R/build_site.R
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ build_site <- function(path = ".", quiet = !interactive(), preview = TRUE, overr
# that pandoc exists and to provision the global lesson components if they do
# not yet exist.
check_pandoc(quiet)
this_lesson(path)
lsn <- this_lesson(path)
not_overview <- !(lsn$overview && length(lsn$episodes) == 0L)
# One feature of The Workbench is a global common links file that will be
# appended to the markdown files before they are sent to be rendered into
# HTML so that they will render the links correctly.
Expand Down Expand Up @@ -54,12 +55,20 @@ build_site <- function(path = ".", quiet = !interactive(), preview = TRUE, overr
db <- get_built_db(fs::path(built_path, "md5sum.txt"))
# filter out files that we will combine to generate
db <- reserved_db(db)
# Find all the episodes and get their range
er <- range(grep("episodes/", db$file, fixed = TRUE))
# Get absolute paths for pandoc to understand
abs_md <- fs::path(path, db$built)
abs_src <- fs::path(path, db$file)
chapters <- abs_md[seq(er[1], er[2])]
if (not_overview) {
# Find all the episodes and get their range
er <- range(grep("episodes/", db$file, fixed = TRUE))
# get percentages from the syllabus table
pct <- get_syllabus(path, questions = TRUE)$percents
names(pct) <- db$file[er[1]:er[2]]
} else {
# otherwise, the expected range for episodes is zero
er <- c(0, 0)
pct <- NULL
}
# If we are only processing one file, then the output should be that one file
if (is.null(slug)) {
out <- "index.html"
Expand All @@ -70,9 +79,6 @@ build_site <- function(path = ".", quiet = !interactive(), preview = TRUE, overr
}

# Rebuilding Episodes and generated files ------------------------------------
# Get percentages from the syllabus table
pct <- get_syllabus(path, questions = TRUE)$percents
names(pct) <- db$file[er[1]:er[2]]
# ------------------------ shim for downlit ----------------------------
# Bypass certain downlit functions that produce unintented effects such
# as linking function documentation.
Expand All @@ -88,12 +94,13 @@ build_site <- function(path = ".", quiet = !interactive(), preview = TRUE, overr
# ------------------------ end downlit shim ----------------------------
for (i in files_to_render) {
location <- page_location(i, abs_md, er)
progress <- if (not_overview) pct[db$file[i]] else pct
build_episode_html(
path_md = abs_md[i],
path_src = abs_src[i],
page_back = location["back"],
page_forward = location["forward"],
page_progress = pct[db$file[i]],
page_progress = progress,
date = db$date[i],
pkg = pkg,
quiet = quiet
Expand All @@ -116,7 +123,8 @@ build_site <- function(path = ".", quiet = !interactive(), preview = TRUE, overr
#
# 2. home page which concatenates index.md and learners/setup.md
describe_progress("Creating homepage", quiet = quiet)
build_home(pkg, quiet = quiet, next_page = abs_md[er[1]])
home_next <- if (not_overview) abs_md[er[1]] else NULL
build_home(pkg, quiet = quiet, next_page = home_next)

# Generated content ----------------------------------------------------------
#
Expand All @@ -140,12 +148,16 @@ build_site <- function(path = ".", quiet = !interactive(), preview = TRUE, overr

# Once we have the pre-processed templates and HTML content, we can pass these
# to our aggregator functions:
describe_progress("Creating keypoints summary", quiet = quiet)
build_keypoints(pkg, pages = html_pages, quiet = quiet)
describe_progress("Creating All-in-one page", quiet = quiet)
build_aio(pkg, pages = html_pages, quiet = quiet)
describe_progress("Creating Images page", quiet = quiet)
build_images(pkg, pages = html_pages, quiet = quiet)
if (not_overview) {
describe_progress("Creating keypoints summary", quiet = quiet)
build_keypoints(pkg, pages = html_pages, quiet = quiet)

describe_progress("Creating All-in-one page", quiet = quiet)
build_aio(pkg, pages = html_pages, quiet = quiet)

describe_progress("Creating Images page", quiet = quiet)
build_images(pkg, pages = html_pages, quiet = quiet)
}
describe_progress("Creating Instructor Notes", quiet = quiet)
build_instructor_notes(pkg, pages = html_pages, built = built, quiet = quiet)

Expand Down
10 changes: 10 additions & 0 deletions R/get_syllabus.R
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ get_syllabus <- function(path = ".", questions = FALSE, use_built = TRUE) {
}

create_syllabus <- function(episodes, lesson, path, questions = TRUE) {
if (is.null(episodes)) {
out <- data.frame(
episode = character(0),
timings = character(0),
path = character(0),
percents = character(0),
stringsAsFactors = FALSE
)
return(out)
}
sched <- fs::path_file(episodes)
# We have to invalidate the cache if the syllabus is mis-matched
cache_invalid <- !setequal(sched, names(lesson$episodes))
Expand Down
Loading