CEC Notion Deployment 2024-08-23

Author

Ran Li

Published

July 15, 2024

1 Introduction

If we start with data (a table or dataframe) we can write it to many digital formats: Notion Pages, Quarto Web Pages or Custom web pages like SALURBAL Portal. Here we demonstrate a workflow for writing data to Notion pages. This is a proof of concept for the CEC team to show how we can write data to Notion pages.

We can write page content to Notion pages via API. The inputs for these could be any database. In this example, we will actually use the page’s own Notion properties as ‘data’ to populate the page. So for each page there are actually two steps: 1) import page properties and 2) writing the properties as Notion blocks.

Before we start, lets just do some quick setup.

2 Setup

We will need three packages.

library(tidyverse) ## for data manipulation
library(dotenv)    ## for loading environment secrets
library(httr)      ## for doing API requetss
library(whisker)  ## for rendering templates
library(glue)     ## for string interpolation
library(jsonlite)  ## Working with JSON
library(cli)      ## for nice console output messages

You will also need an .env file in the root of your project that has an Notion API key. Do NOT SHARE this or have this under version control. It should be in your gitignore folder! From here we can load ‘secrets’ for R to use but not exposed to anyone else.

## Load .env file into local environment
dotenv::load_dot_env(file = ".env")

## Assign secret to a variabel
secret_notion_api_key <- Sys.getenv("NOTION_API_KEY")

We will also need to reuse some functions which were informed by the NotionR package but essentially build again to be more lightweight and maintainable in by the CCUH/SALURBAL infrastructure team. Feel free to modify it for your own needs - maybe we can publish it as a packge one day if matures =)

source('R/read_notion_database.R')
source('R/make_notion_request.R')

3 Import Data

In this case, the data is a Notion database which is uniquely identified with a database id which can be found in the URL between the account id (drexel-ccuh) and the first ? - as highlighted in the snip below.

Once we have this we can just use the read_notion_database function to get the data.

df_policies_main_table = read_notion_database(database = '6ac8fe17c3ec4c7d9f2f1d3068d7d877')
dim(df_policies_main_table)
[1] 150 220

This is a big table with 150 rows (one per database row) and 206 columns. Notion API returns a lot of information about each page and a lot of metadata for each property. While this is all very useful and makes for a very flexible API, it can be a bit overwhelming. So one challenge is looking through and picking out the information we are interested in; we’ll do that in the next section data cleaning.

4 Clean Data

4.1 Subset for ‘1-pager test case’

We will test this out with a few of the rows with this TODO tag. Let’s take a loko at what type of information we have on this property.

df_policies_main_table %>% 
  select(contains('TODO')) %>% 
  View()

It looks like what we want is in the properties.TODO's.multi_select.name column. Lets filter this dataframe to only include those that have the tag of interest.

df_db_subset_rows = df_policies_main_table %>% 
  filter(str_detect(`properties.TODO's.multi_select.name`, '1-pager'))
dim(df_db_subset_rows)
[1]   5 220

Indeed we are down to 5 rows!

Lets initialize a new dataframe to store cleaned results.

df_parsed = df_db_subset_rows %>% 
  select(id) %>% 
  as_tibble()

4.2 Identify properties of interest

So the request was originally for a template that had some ‘keys’ to render property values which include:

  • [Title]
  • [Sectors]
  • [Governance level]
  • [Primary effect(s)]
  • [Relevance to health]
  • [Description]
  • [Additional description]
  • [Climate change scope]
  • [Climate narrative]
  • [Health impact pathways]
  • [Exposures affected]
  • [Health narrative]
  • [Related policies]
  • [Feasibility]
  • [Timeframe]
  • [One pager]
  • [Image files]

4.3 Example code for parsing properties

Okay. For Notion each property type has its own types of columns returned. Below is a list of the properties we are interested in and the column names that contain the information we want. Below that are some subsections show how that process works for each type of property in the requets - just to give example code for how to handle/process.

  • Text: Title
  • Relation: Sectors
  • Multi-select: Primary effect(s)
  • Image: Image files

4.3.1 Text - [Title]

df_db_subset_rows %>% 
  select(contains('Title')) %>% 
  glimpse()
Rows: 5
Columns: 20
$ properties.Policies.title.annotations.bold           <chr> "FALSE", "FALSE",…
$ properties.Policies.title.annotations.code           <chr> "FALSE", "FALSE",…
$ properties.Policies.title.annotations.color          <chr> "default", "defau…
$ properties.Policies.title.annotations.italic         <chr> "FALSE", "FALSE",…
$ properties.Policies.title.annotations.strikethrough  <chr> "FALSE", "FALSE",…
$ properties.Policies.title.annotations.underline      <chr> "FALSE", "FALSE",…
$ properties.Policies.title.plain_text                 <chr> "Complete streets…
$ properties.Policies.title.text.content               <chr> "Complete streets…
$ properties.Policies.title.type                       <chr> "text", "text", "…
$ properties.Title.id                                  <chr> "ASrg", "ASrg", "…
$ properties.Title.type                                <chr> "rich_text", "ric…
$ properties.Title.rich_text.annotations.bold          <chr> "FALSE", "FALSE",…
$ properties.Title.rich_text.annotations.code          <chr> "FALSE", "FALSE",…
$ properties.Title.rich_text.annotations.color         <chr> "default", "defau…
$ properties.Title.rich_text.annotations.italic        <chr> "TRUE", "TRUE", "…
$ properties.Title.rich_text.annotations.strikethrough <chr> "FALSE", "FALSE",…
$ properties.Title.rich_text.annotations.underline     <chr> "FALSE", "FALSE",…
$ properties.Title.rich_text.plain_text                <chr> "Complete Streets…
$ properties.Title.rich_text.text.content              <chr> "Complete Streets…
$ properties.Title.rich_text.type                      <chr> "text", "text", "…

Looks like rich text, we will just take the plain text!

## Select column of interest
df_title = df_db_subset_rows %>% 
              select(id, title = `properties.Title.rich_text.plain_text`)

## Merge into results
df_parsed = df_parsed %>% 
  left_join(df_title) 

4.3.2 Relation to other db pages - [Sectors]

df_db_subset_rows %>% 
  select(id, contains('.Sectors')) %>%
  glimpse()
Rows: 5
Columns: 5
$ id                             <chr> "df0ef29f-da8a-4e74-8713-f30f19727503",…
$ properties.Sectors.has_more    <chr> "FALSE", "FALSE", "FALSE", "FALSE", "FA…
$ properties.Sectors.id          <chr> "TVp%3A", "TVp%3A", "TVp%3A", "TVp%3A",…
$ properties.Sectors.type        <chr> "relation", "relation", "relation", "re…
$ properties.Sectors.relation.id <chr> "6b2c4777-339f-4898-a849-8b6190ba7865 |…

This is one is more complex, because this is a relation. See the relation information above really just gives a link to the other table via properties.Sectors.relation.id. So there are two ways of handling it:

  • Easy:
    • Create a Notion Rollup of in Policy Main with the value of the relation
  • Hard:
    • Import the Sectors table in R
    • Link the Sectors table to the Policy Main table in R

Lets do the hard way first; we can got rhough easy example later. Lets read in the Sectors table to get the sector name.

df_sectors = read_notion_database(database = '09b80694ea9d4fd7bffe8fd0cd4df489')
glimpse(df_sectors)
Rows: 18
Columns: 30
$ archived                                          <chr> "FALSE", "FALSE", "F…
$ created_by.id                                     <chr> "9711549e-0df7-4268-…
$ created_by.object                                 <chr> "user", "user", "use…
$ created_time                                      <chr> "2024-08-23T00:34:00…
$ id                                                <chr> "4fca3b06-d65f-4200-…
$ in_trash                                          <chr> "FALSE", "FALSE", "F…
$ last_edited_by.id                                 <chr> "9711549e-0df7-4268-…
$ last_edited_by.object                             <chr> "user", "user", "use…
$ last_edited_time                                  <chr> "2024-08-23T00:34:00…
$ object                                            <chr> "page", "page", "pag…
$ parent.database_id                                <chr> "09b80694-ea9d-4fd7-…
$ parent.type                                       <chr> "database_id", "data…
$ properties.Policies.has_more                      <chr> "FALSE", "FALSE", "F…
$ properties.Policies.id                            <chr> "gCBj", "gCBj", "gCB…
$ properties.Policies.type                          <chr> "relation", "relatio…
$ properties.Sector.id                              <chr> "title", "title", "t…
$ properties.Sector.title.annotations.bold          <chr> "FALSE", "FALSE", "F…
$ properties.Sector.title.annotations.code          <chr> "FALSE", "FALSE", "F…
$ properties.Sector.title.annotations.color         <chr> "default", "default"…
$ properties.Sector.title.annotations.italic        <chr> "FALSE", "FALSE", "F…
$ properties.Sector.title.annotations.strikethrough <chr> "FALSE", "FALSE", "F…
$ properties.Sector.title.annotations.underline     <chr> "FALSE", "FALSE", "F…
$ properties.Sector.title.plain_text                <chr> "Technology developm…
$ properties.Sector.title.text.content              <chr> "Technology developm…
$ properties.Sector.title.type                      <chr> "text", "text", "tex…
$ properties.Sector.type                            <chr> "title", "title", "t…
$ properties.Tags.id                                <chr> "wUd%5C", "wUd%5C", …
$ properties.Tags.type                              <chr> "multi_select", "mul…
$ url                                               <chr> "https://www.notion.…
$ properties.Policies.relation.id                   <chr> NA, NA, NA, NA, NA, …

Okay. lets operataionzlie some templating data with just the sector page id and the sector name as as a hyperlink to the Notion page. I mean we could do text, but this just shows we can do a hyperlink to increase findability (in case you have SEctor specific dcumentaiton on Notion).

df_sectors_processed = df_sectors %>% 
  mutate(sector_value = glue("[{properties.Sector.title.plain_text}]({url})")) %>%
  select(id, sector_value)
templating_data_sectors = as.list(df_sectors_processed$sector_value) %>% 
  setNames(df_sectors_processed$id)
head(templating_data_sectors)
$`4fca3b06-d65f-4200-bdb6-faf70292a11a`
[1] "[Technology development and innovation](https://www.notion.so/Technology-development-and-innovation-4fca3b06d65f4200bdb6faf70292a11a)"

$`cf0a3883-40b3-4194-9471-449731df87bc`
[1] "[Finance and insurance](https://www.notion.so/Finance-and-insurance-cf0a388340b341949471449731df87bc)"

$`0d0f82e1-d8bb-49fe-9d12-579da1869e1b`
[1] "[Education](https://www.notion.so/Education-0d0f82e1d8bb49fe9d12579da1869e1b)"

$`ad3364a0-6eca-42fe-a9ee-08b2fa043c2d`
[1] "[Health](https://www.notion.so/Health-ad3364a06eca42fea9ee08b2fa043c2d)"

$`373fb372-2455-40d0-90d1-ac7ba6000a93`
[1] "[Social welfare and services](https://www.notion.so/Social-welfare-and-services-373fb372245540d090d1ac7ba6000a93)"

$`41225582-438d-49a1-8443-4b3e06cdd94b`
[1] "[Governance and regulation](https://www.notion.so/Governance-and-regulation-41225582438d49a184434b3e06cdd94b)"

Now lets prep the df_db_subset_rows to adhere to templating syntax.

prepare_render_ready_relation_id_string = function(relation_id_string) {
  # relation_id_string = "6b2c4777-339f-4898-a849-8b6190ba7865 | 997e4a17-4b08-4f35-b86e-a5028c9910e4"
  render_ready_string = relation_id_string %>% 
    str_split("\\|") %>% 
    unlist() %>% 
    str_trim() %>% 
    paste0("{{",.,"}}") %>% 
    paste(collapse = ', ')
  
  return(render_ready_string)
}

df_db_subset_rows_sectors_prerender = df_db_subset_rows %>% 
  rowwise() %>% 
  mutate(sectors =  prepare_render_ready_relation_id_string(properties.Sectors.relation.id)) %>%
  ungroup() %>% 
  select(id, sectors) 

df_db_subset_rows_sectors_prerender
# A tibble: 5 × 2
  id                                   sectors                                  
  <chr>                                <chr>                                    
1 df0ef29f-da8a-4e74-8713-f30f19727503 {{6b2c4777-339f-4898-a849-8b6190ba7865}}…
2 81b63652-a8be-48ea-a1b2-fcfb8aa8165e {{43e35fb1-0303-4094-92b9-d37dcc71816a}}…
3 f8f99d62-9bfc-4668-8379-67406ad3a01b {{997e4a17-4b08-4f35-b86e-a5028c9910e4}} 
4 3f0c1c1b-a26a-4636-9aaa-64c8c0a3bdbd {{997e4a17-4b08-4f35-b86e-a5028c9910e4}} 
5 c3e2e324-4a3f-4cf0-9a82-c28365bd0a3e {{fa03fd40-ea99-4bfe-af51-c7f573360550}} 

Now lets render

## Render
df_db_subset_rows_sectors_rendered = df_db_subset_rows_sectors_prerender %>% 
  rowwise() %>% 
  mutate(sectors = whisker::whisker.render(sectors, templating_data_sectors)) %>% 
  ungroup()

## Preview render results
df_db_subset_rows_sectors_rendered
# A tibble: 5 × 2
  id                                   sectors                                  
  <chr>                                <chr>                                    
1 df0ef29f-da8a-4e74-8713-f30f19727503 [Urban planning and land use](https://ww…
2 81b63652-a8be-48ea-a1b2-fcfb8aa8165e [Architecture and Housing](https://www.n…
3 f8f99d62-9bfc-4668-8379-67406ad3a01b [Transportation](https://www.notion.so/T…
4 3f0c1c1b-a26a-4636-9aaa-64c8c0a3bdbd [Transportation](https://www.notion.so/T…
5 c3e2e324-4a3f-4cf0-9a82-c28365bd0a3e [Thermal governance](https://www.notion.…
## Merge into results
df_parsed = df_parsed %>% 
  left_join(df_db_subset_rows_sectors_rendered) 

4.3.3 Multiselect - [Primary effect]

df_db_subset_rows %>% 
  select(id, contains('.Primary')) %>%
  glimpse()
Rows: 5
Columns: 6
$ id                                                <chr> "df0ef29f-da8a-4e74-…
$ `properties.Primary effect(s).id`                 <chr> "O%3BA%7B", "O%3BA%7…
$ `properties.Primary effect(s).type`               <chr> "multi_select", "mul…
$ `properties.Primary effect(s).multi_select.color` <chr> "green | default", N…
$ `properties.Primary effect(s).multi_select.id`    <chr> "^kTo | Au~q", NA, "…
$ `properties.Primary effect(s).multi_select.name`  <chr> "Traffic safety impr…

Primary effect is a multi-select. The columnn of interest seems to be properties.Primary effect(s).multi_select.name. Lets take a look at hte values.

df_db_subset_rows %>% 
  count(`properties.Primary effect(s).multi_select.name`)
# A tibble: 4 × 2
  `properties.Primary effect(s).multi_select.name`     n
  <chr>                                            <int>
1 GHG reduction                                        1
2 GHG reduction | Traffic safety improvements          1
3 Traffic safety improvements | GHG reduction          1
4 <NA>                                                 2

This is just slightly more complex than text, we just need to replace the API seperator | with what ever you want. Lets do a comma.

df_primary_effect = df_db_subset_rows %>% 
  mutate(primary_effects =  str_replace_all( `properties.Primary effect(s).multi_select.name`, "\\|", ", ")) %>% 
  select(id,primary_effects)


## Merge into results
df_parsed = df_parsed %>% 
  left_join(df_primary_effect) 

4.3.4 Image - [Image files]

df_db_subset_rows %>% 
  select(id, contains('.Image')) %>%
  glimpse()
Rows: 5
Columns: 6
$ id                                          <chr> "df0ef29f-da8a-4e74-8713-f…
$ `properties.Image files.id`                 <chr> "QMLZ", "QMLZ", "QMLZ", "Q…
$ `properties.Image files.type`               <chr> "files", "files", "files",…
$ `properties.Image files.files.external.url` <chr> "https://www.mdpi.com/sust…
$ `properties.Image files.files.name`         <chr> "https://www.mdpi.com/sust…
$ `properties.Image files.files.type`         <chr> "external", "external", NA…

For images we just need where the file is located which is properties.Image files.files.external.url.

df_image_files = df_db_subset_rows %>% 
  select(id,image = `properties.Image files.files.external.url`)


## Merge into results
df_parsed = df_parsed %>% 
  left_join(df_image_files) 

4.4 Parse minimal properties

Here we apply the above logic across a few other properties - just so we have a basic amount of data for generating a Proof of concept.

4.4.1 [Descrption]

df_description = df_db_subset_rows %>% 
  select(id, description = `properties.Description.rich_text.plain_text`)
df_description
# A tibble: 5 × 2
  id                                   description                              
  <chr>                                <chr>                                    
1 df0ef29f-da8a-4e74-8713-f30f19727503 "Complete Streets policies aim for all p…
2 81b63652-a8be-48ea-a1b2-fcfb8aa8165e "Green roofs, or living roofs, vegetated…
3 f8f99d62-9bfc-4668-8379-67406ad3a01b "Reducing speed limits on streets helps …
4 3f0c1c1b-a26a-4636-9aaa-64c8c0a3bdbd  <NA>                                    
5 c3e2e324-4a3f-4cf0-9a82-c28365bd0a3e "Air conditioning inside buildings and h…

Looks okay, lets bind.

## Merge into results
df_parsed = df_parsed %>% 
  left_join(df_description) 

4.4.2 [Climate narrative]

df_climate_narrative = df_db_subset_rows %>% 
  select(id, climate_narrative = `properties.Climate narrative.rich_text.plain_text`)

Looks okay, lets bind.

## Merge into results
df_parsed = df_parsed %>% 
  left_join(df_climate_narrative) 

4.5 Review Templating Data

Now we have a minimum amount of data to show the workflow.

df_parsed = df_parsed %>%
  mutate(id_clean = stringr::str_remove_all(id, "-")) %>%
  glimpse()
Rows: 5
Columns: 8
$ id                <chr> "df0ef29f-da8a-4e74-8713-f30f19727503", "81b63652-a8…
$ title             <chr> "Complete Streets policy approach for safe and equit…
$ sectors           <chr> "[Urban planning and land use](https://www.notion.so…
$ primary_effects   <chr> "Traffic safety improvements ,  GHG reduction", NA, …
$ image             <chr> "https://www.mdpi.com/sustainability/sustainability-…
$ description       <chr> "Complete Streets policies aim for all people regard…
$ climate_narrative <chr> "Complete Street policies play a role in larger clim…
$ id_clean          <chr> "df0ef29fda8a4e748713f30f19727503", "81b63652a8be48e…

Lets do the writing to Notion pages

5 Functions for Writing to Notion

The Logic here adopted from a few CCUH pieces of work:

The basic idea is that for each block we have an R function that generates the content in JSON format. When the compose a JSON request that contains all these individual pieces of logic. Here we draft the functions for the first few blocks of the template - the CEC can do the rest.

Notion has good documentation about how to write blocks here: https://developers.notion.com/reference/block

5.1 Content functions

Here we have functions you can edit for the property types you requsted.

5.1.1 H1 block

make_h1_block <- function(title) {
  glue('
  {{
    "object": "block",
    "type": "heading_1",
    "heading_1": {{
      "rich_text": [
        {{
          "type": "text",
          "text": {{
            "content": "{title}"
          }}
        }}
      ]
    }}
  }}
')
}

5.1.2 Notion Mentions Block

This is use to display relations - links to other notion db pages. We will use this for the sectors and other relations. See official notion docs here: https://developers.notion.com/reference/block#mention.

make_notion_mention_block <- function(text) {
  # Split the markdown text into parts
  parts <- strsplit(text, "\\[|\\]\\(|\\)")[[1]]
  
  rich_text <- list()
  
  for (i in seq_along(parts)) {
    if (i %% 3 == 1) {
      # Plain text
      if (nchar(parts[i]) > 0) {
        rich_text <- c(rich_text, list(list(
          type = "text",
          text = list(content = parts[i])
        )))
      }
    } else if (i %% 3 == 2) {
      # Page mention
      url <- parts[i + 1]
      page_id <- sub(".*-", "", url)  # Extract the ID from the end of the URL
      rich_text <- c(rich_text, list(list(
        type = "mention",
        mention = list(
          type = "page",
          page = list(id = page_id)
        )
      )))
    }
  }
  
  json <- jsonlite::toJSON(list(
    object = "block",
    type = "paragraph",
    paragraph = list(
      rich_text = rich_text
    )
  ), auto_unbox = TRUE, pretty = TRUE)
  
  # Remove escaped forward slashes
  json <- gsub("\\\\/", "/", json)
  
  return(json)
}

5.1.3 Text block

This is the easiet, just text.

make_text_block <- function(text) {
  text_escaped <- gsub("\n", "\\\\n", text)
  glue('
  {{
    "object": "block",
    "type": "paragraph",
    "paragraph": {{
      "rich_text": [
        {{
          "type": "text",
          "text": {{
            "content": "{text_escaped}"
          }}
        }}
      ]
    }}
  }}
  ')
}

5.1.4 Image

As per https://developers.notion.com/reference/block#image

make_image_block <- function(image_url) {
  
  ## If no image just return empty text
  text_if_no_image =  glue('
  {{
    "object": "block",
    "type": "paragraph",
    "paragraph": {{
      "rich_text": [
        {{
          "type": "text",
          "text": {{
            "content": ""
          }}
        }}
      ]
    }}
  }}
  ')
  
  image_if_available = glue('
  {{
    "object": "block",
    "type": "image",
    "image": {{
      "type": "external",
      "external": {{
        "url": "{image_url}"
      }}
    }}
  }}
  ')
  
  if (is.na(image_url) | image_url == "") {
    return(text_if_no_image)
  } else {
    return(image_if_available)
  }
}

5.2 Writing funcitons

These fucntions will be used to edit content on a page. We test with the Green Roofs page

test_page = 'df0ef29fda8a4e748713f30f19727503'

5.2.1 Clear Page Blocks

This funciton will clear a all blocks in a page. Just used to clear thigns if needed.

clear_page_children <- function(page_id) {
  # First, retrieve all children blocks
  get_children_response <- make_request(
    endpoint = glue("blocks/{page_id}/children"),
    method = "GET"
  )
  
  # Extract block IDs
  block_ids <- sapply(get_children_response$results, function(block) block$id)
  
  # If there are no children, we're done
  if (length(block_ids) == 0) {
    cat("Page is already empty.\n")
    return(invisible(NULL))
  }
  
  # Delete each block
  for (block_id in block_ids) {
    make_request(
      endpoint = glue("blocks/{block_id}"),
      method = "DELETE"
    )
    cat(glue("Deleted block {block_id}\n"))
  }
  
  cat(glue("Cleared {length(block_ids)} blocks from page {page_id}\n"))
}


clear_page_children(test_page)
Deleted block 5626e666-1cbd-4d94-8c5f-3123ecd77e6cDeleted block 8eced27b-b67d-4fe1-a70f-0159aa31fd5bDeleted block 22b0231d-d421-4f3b-b21c-c983d78dc6f5Deleted block f56881ba-03f0-426f-be47-259b2deb5282Deleted block c6343a23-1d68-4e9a-97a2-b0cdb7de7b55Deleted block 45575f08-d7e8-4e6c-9b8f-9455d9f99a74Deleted block 5acc8d5b-f5e6-455f-851f-4391ebbefef9Deleted block 68d7f884-f2a2-49a1-8a6d-8edf6e6e6cc3Deleted block 4883dd52-56f0-4669-8ed7-82712bdf427bCleared 9 blocks from page df0ef29fda8a4e748713f30f19727503

5.2.2 write_cec_template_poc()

This will add children blocks to specified page. We compose the content here. We assume we have a input data frame hwere each row is a page with content to write.

## Prep Input data
page_row = df_parsed %>%
  filter(id_clean == test_page) 
page_row
# A tibble: 1 × 8
  id           title sectors primary_effects image description climate_narrative
  <chr>        <chr> <chr>   <chr>           <chr> <chr>       <chr>            
1 df0ef29f-da… Comp… [Urban… Traffic safety… http… "Complete … Complete Street …
# ℹ 1 more variable: id_clean <chr>
## Function to compose template
write_cec_template_poc <- function(page_row) {
  
  
  body_json =  glue('
    {{
      "children": [
        {make_h1_block(page_row$title)},
        {make_notion_mention_block(glue("Sectors: {page_row$sectors}"))},
        {make_notion_mention_block(glue("Primarily intended effect of policy:: {page_row$sectors}"))},
        {make_h1_block("Description")},
        {make_text_block(page_row$description)},
        {make_h1_block("How this policy relates to climate change")},
        {make_text_block(page_row$climate_narrative)},
        {make_h1_block("Image")},
        {make_image_block(page_row$image)}

      ]
    }}
    ')
  

  make_request(
    endpoint = glue("blocks/{page_row$id_clean}/children"),
    method = "PATCH",
    body = body_json,
    body_format_json = TRUE
  )
}

clear_page_children(test_page)
Page is already empty.
write_cec_template_poc(page_row)
$object
[1] "list"

$results
$results[[1]]
$results[[1]]$object
[1] "block"

$results[[1]]$id
[1] "0cec0e78-1c5d-443c-906d-571d6f97151e"

$results[[1]]$parent
$results[[1]]$parent$type
[1] "page_id"

$results[[1]]$parent$page_id
[1] "df0ef29f-da8a-4e74-8713-f30f19727503"


$results[[1]]$created_time
[1] "2024-08-26T12:23:00.000Z"

$results[[1]]$last_edited_time
[1] "2024-08-26T12:23:00.000Z"

$results[[1]]$created_by
$results[[1]]$created_by$object
[1] "user"

$results[[1]]$created_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[1]]$last_edited_by
$results[[1]]$last_edited_by$object
[1] "user"

$results[[1]]$last_edited_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[1]]$has_children
[1] FALSE

$results[[1]]$archived
[1] FALSE

$results[[1]]$in_trash
[1] FALSE

$results[[1]]$type
[1] "heading_1"

$results[[1]]$heading_1
$results[[1]]$heading_1$rich_text
$results[[1]]$heading_1$rich_text[[1]]
$results[[1]]$heading_1$rich_text[[1]]$type
[1] "text"

$results[[1]]$heading_1$rich_text[[1]]$text
$results[[1]]$heading_1$rich_text[[1]]$text$content
[1] "Complete Streets policy approach for safe and equitable mobility"

$results[[1]]$heading_1$rich_text[[1]]$text$link
NULL


$results[[1]]$heading_1$rich_text[[1]]$annotations
$results[[1]]$heading_1$rich_text[[1]]$annotations$bold
[1] FALSE

$results[[1]]$heading_1$rich_text[[1]]$annotations$italic
[1] FALSE

$results[[1]]$heading_1$rich_text[[1]]$annotations$strikethrough
[1] FALSE

$results[[1]]$heading_1$rich_text[[1]]$annotations$underline
[1] FALSE

$results[[1]]$heading_1$rich_text[[1]]$annotations$code
[1] FALSE

$results[[1]]$heading_1$rich_text[[1]]$annotations$color
[1] "default"


$results[[1]]$heading_1$rich_text[[1]]$plain_text
[1] "Complete Streets policy approach for safe and equitable mobility"

$results[[1]]$heading_1$rich_text[[1]]$href
NULL



$results[[1]]$heading_1$is_toggleable
[1] FALSE

$results[[1]]$heading_1$color
[1] "default"



$results[[2]]
$results[[2]]$object
[1] "block"

$results[[2]]$id
[1] "59b021f4-1944-422c-abd0-bc982dc1ea63"

$results[[2]]$parent
$results[[2]]$parent$type
[1] "page_id"

$results[[2]]$parent$page_id
[1] "df0ef29f-da8a-4e74-8713-f30f19727503"


$results[[2]]$created_time
[1] "2024-08-26T12:23:00.000Z"

$results[[2]]$last_edited_time
[1] "2024-08-26T12:23:00.000Z"

$results[[2]]$created_by
$results[[2]]$created_by$object
[1] "user"

$results[[2]]$created_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[2]]$last_edited_by
$results[[2]]$last_edited_by$object
[1] "user"

$results[[2]]$last_edited_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[2]]$has_children
[1] FALSE

$results[[2]]$archived
[1] FALSE

$results[[2]]$in_trash
[1] FALSE

$results[[2]]$type
[1] "paragraph"

$results[[2]]$paragraph
$results[[2]]$paragraph$rich_text
$results[[2]]$paragraph$rich_text[[1]]
$results[[2]]$paragraph$rich_text[[1]]$type
[1] "text"

$results[[2]]$paragraph$rich_text[[1]]$text
$results[[2]]$paragraph$rich_text[[1]]$text$content
[1] "Sectors: "

$results[[2]]$paragraph$rich_text[[1]]$text$link
NULL


$results[[2]]$paragraph$rich_text[[1]]$annotations
$results[[2]]$paragraph$rich_text[[1]]$annotations$bold
[1] FALSE

$results[[2]]$paragraph$rich_text[[1]]$annotations$italic
[1] FALSE

$results[[2]]$paragraph$rich_text[[1]]$annotations$strikethrough
[1] FALSE

$results[[2]]$paragraph$rich_text[[1]]$annotations$underline
[1] FALSE

$results[[2]]$paragraph$rich_text[[1]]$annotations$code
[1] FALSE

$results[[2]]$paragraph$rich_text[[1]]$annotations$color
[1] "default"


$results[[2]]$paragraph$rich_text[[1]]$plain_text
[1] "Sectors: "

$results[[2]]$paragraph$rich_text[[1]]$href
NULL


$results[[2]]$paragraph$rich_text[[2]]
$results[[2]]$paragraph$rich_text[[2]]$type
[1] "mention"

$results[[2]]$paragraph$rich_text[[2]]$mention
$results[[2]]$paragraph$rich_text[[2]]$mention$type
[1] "page"

$results[[2]]$paragraph$rich_text[[2]]$mention$page
$results[[2]]$paragraph$rich_text[[2]]$mention$page$id
[1] "6b2c4777-339f-4898-a849-8b6190ba7865"



$results[[2]]$paragraph$rich_text[[2]]$annotations
$results[[2]]$paragraph$rich_text[[2]]$annotations$bold
[1] FALSE

$results[[2]]$paragraph$rich_text[[2]]$annotations$italic
[1] FALSE

$results[[2]]$paragraph$rich_text[[2]]$annotations$strikethrough
[1] FALSE

$results[[2]]$paragraph$rich_text[[2]]$annotations$underline
[1] FALSE

$results[[2]]$paragraph$rich_text[[2]]$annotations$code
[1] FALSE

$results[[2]]$paragraph$rich_text[[2]]$annotations$color
[1] "default"


$results[[2]]$paragraph$rich_text[[2]]$plain_text
[1] "Urban planning and land use"

$results[[2]]$paragraph$rich_text[[2]]$href
[1] "https://www.notion.so/6b2c4777339f4898a8498b6190ba7865"


$results[[2]]$paragraph$rich_text[[3]]
$results[[2]]$paragraph$rich_text[[3]]$type
[1] "text"

$results[[2]]$paragraph$rich_text[[3]]$text
$results[[2]]$paragraph$rich_text[[3]]$text$content
[1] ", "

$results[[2]]$paragraph$rich_text[[3]]$text$link
NULL


$results[[2]]$paragraph$rich_text[[3]]$annotations
$results[[2]]$paragraph$rich_text[[3]]$annotations$bold
[1] FALSE

$results[[2]]$paragraph$rich_text[[3]]$annotations$italic
[1] FALSE

$results[[2]]$paragraph$rich_text[[3]]$annotations$strikethrough
[1] FALSE

$results[[2]]$paragraph$rich_text[[3]]$annotations$underline
[1] FALSE

$results[[2]]$paragraph$rich_text[[3]]$annotations$code
[1] FALSE

$results[[2]]$paragraph$rich_text[[3]]$annotations$color
[1] "default"


$results[[2]]$paragraph$rich_text[[3]]$plain_text
[1] ", "

$results[[2]]$paragraph$rich_text[[3]]$href
NULL


$results[[2]]$paragraph$rich_text[[4]]
$results[[2]]$paragraph$rich_text[[4]]$type
[1] "mention"

$results[[2]]$paragraph$rich_text[[4]]$mention
$results[[2]]$paragraph$rich_text[[4]]$mention$type
[1] "page"

$results[[2]]$paragraph$rich_text[[4]]$mention$page
$results[[2]]$paragraph$rich_text[[4]]$mention$page$id
[1] "997e4a17-4b08-4f35-b86e-a5028c9910e4"



$results[[2]]$paragraph$rich_text[[4]]$annotations
$results[[2]]$paragraph$rich_text[[4]]$annotations$bold
[1] FALSE

$results[[2]]$paragraph$rich_text[[4]]$annotations$italic
[1] FALSE

$results[[2]]$paragraph$rich_text[[4]]$annotations$strikethrough
[1] FALSE

$results[[2]]$paragraph$rich_text[[4]]$annotations$underline
[1] FALSE

$results[[2]]$paragraph$rich_text[[4]]$annotations$code
[1] FALSE

$results[[2]]$paragraph$rich_text[[4]]$annotations$color
[1] "default"


$results[[2]]$paragraph$rich_text[[4]]$plain_text
[1] "Transportation"

$results[[2]]$paragraph$rich_text[[4]]$href
[1] "https://www.notion.so/997e4a174b084f35b86ea5028c9910e4"



$results[[2]]$paragraph$color
[1] "default"



$results[[3]]
$results[[3]]$object
[1] "block"

$results[[3]]$id
[1] "5a65ff61-8b18-48e3-97e0-95a0f7dccdc3"

$results[[3]]$parent
$results[[3]]$parent$type
[1] "page_id"

$results[[3]]$parent$page_id
[1] "df0ef29f-da8a-4e74-8713-f30f19727503"


$results[[3]]$created_time
[1] "2024-08-26T12:23:00.000Z"

$results[[3]]$last_edited_time
[1] "2024-08-26T12:23:00.000Z"

$results[[3]]$created_by
$results[[3]]$created_by$object
[1] "user"

$results[[3]]$created_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[3]]$last_edited_by
$results[[3]]$last_edited_by$object
[1] "user"

$results[[3]]$last_edited_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[3]]$has_children
[1] FALSE

$results[[3]]$archived
[1] FALSE

$results[[3]]$in_trash
[1] FALSE

$results[[3]]$type
[1] "paragraph"

$results[[3]]$paragraph
$results[[3]]$paragraph$rich_text
$results[[3]]$paragraph$rich_text[[1]]
$results[[3]]$paragraph$rich_text[[1]]$type
[1] "text"

$results[[3]]$paragraph$rich_text[[1]]$text
$results[[3]]$paragraph$rich_text[[1]]$text$content
[1] "Primarily intended effect of policy:: "

$results[[3]]$paragraph$rich_text[[1]]$text$link
NULL


$results[[3]]$paragraph$rich_text[[1]]$annotations
$results[[3]]$paragraph$rich_text[[1]]$annotations$bold
[1] FALSE

$results[[3]]$paragraph$rich_text[[1]]$annotations$italic
[1] FALSE

$results[[3]]$paragraph$rich_text[[1]]$annotations$strikethrough
[1] FALSE

$results[[3]]$paragraph$rich_text[[1]]$annotations$underline
[1] FALSE

$results[[3]]$paragraph$rich_text[[1]]$annotations$code
[1] FALSE

$results[[3]]$paragraph$rich_text[[1]]$annotations$color
[1] "default"


$results[[3]]$paragraph$rich_text[[1]]$plain_text
[1] "Primarily intended effect of policy:: "

$results[[3]]$paragraph$rich_text[[1]]$href
NULL


$results[[3]]$paragraph$rich_text[[2]]
$results[[3]]$paragraph$rich_text[[2]]$type
[1] "mention"

$results[[3]]$paragraph$rich_text[[2]]$mention
$results[[3]]$paragraph$rich_text[[2]]$mention$type
[1] "page"

$results[[3]]$paragraph$rich_text[[2]]$mention$page
$results[[3]]$paragraph$rich_text[[2]]$mention$page$id
[1] "6b2c4777-339f-4898-a849-8b6190ba7865"



$results[[3]]$paragraph$rich_text[[2]]$annotations
$results[[3]]$paragraph$rich_text[[2]]$annotations$bold
[1] FALSE

$results[[3]]$paragraph$rich_text[[2]]$annotations$italic
[1] FALSE

$results[[3]]$paragraph$rich_text[[2]]$annotations$strikethrough
[1] FALSE

$results[[3]]$paragraph$rich_text[[2]]$annotations$underline
[1] FALSE

$results[[3]]$paragraph$rich_text[[2]]$annotations$code
[1] FALSE

$results[[3]]$paragraph$rich_text[[2]]$annotations$color
[1] "default"


$results[[3]]$paragraph$rich_text[[2]]$plain_text
[1] "Urban planning and land use"

$results[[3]]$paragraph$rich_text[[2]]$href
[1] "https://www.notion.so/6b2c4777339f4898a8498b6190ba7865"


$results[[3]]$paragraph$rich_text[[3]]
$results[[3]]$paragraph$rich_text[[3]]$type
[1] "text"

$results[[3]]$paragraph$rich_text[[3]]$text
$results[[3]]$paragraph$rich_text[[3]]$text$content
[1] ", "

$results[[3]]$paragraph$rich_text[[3]]$text$link
NULL


$results[[3]]$paragraph$rich_text[[3]]$annotations
$results[[3]]$paragraph$rich_text[[3]]$annotations$bold
[1] FALSE

$results[[3]]$paragraph$rich_text[[3]]$annotations$italic
[1] FALSE

$results[[3]]$paragraph$rich_text[[3]]$annotations$strikethrough
[1] FALSE

$results[[3]]$paragraph$rich_text[[3]]$annotations$underline
[1] FALSE

$results[[3]]$paragraph$rich_text[[3]]$annotations$code
[1] FALSE

$results[[3]]$paragraph$rich_text[[3]]$annotations$color
[1] "default"


$results[[3]]$paragraph$rich_text[[3]]$plain_text
[1] ", "

$results[[3]]$paragraph$rich_text[[3]]$href
NULL


$results[[3]]$paragraph$rich_text[[4]]
$results[[3]]$paragraph$rich_text[[4]]$type
[1] "mention"

$results[[3]]$paragraph$rich_text[[4]]$mention
$results[[3]]$paragraph$rich_text[[4]]$mention$type
[1] "page"

$results[[3]]$paragraph$rich_text[[4]]$mention$page
$results[[3]]$paragraph$rich_text[[4]]$mention$page$id
[1] "997e4a17-4b08-4f35-b86e-a5028c9910e4"



$results[[3]]$paragraph$rich_text[[4]]$annotations
$results[[3]]$paragraph$rich_text[[4]]$annotations$bold
[1] FALSE

$results[[3]]$paragraph$rich_text[[4]]$annotations$italic
[1] FALSE

$results[[3]]$paragraph$rich_text[[4]]$annotations$strikethrough
[1] FALSE

$results[[3]]$paragraph$rich_text[[4]]$annotations$underline
[1] FALSE

$results[[3]]$paragraph$rich_text[[4]]$annotations$code
[1] FALSE

$results[[3]]$paragraph$rich_text[[4]]$annotations$color
[1] "default"


$results[[3]]$paragraph$rich_text[[4]]$plain_text
[1] "Transportation"

$results[[3]]$paragraph$rich_text[[4]]$href
[1] "https://www.notion.so/997e4a174b084f35b86ea5028c9910e4"



$results[[3]]$paragraph$color
[1] "default"



$results[[4]]
$results[[4]]$object
[1] "block"

$results[[4]]$id
[1] "d99fc22c-1120-498c-a954-da70aa9a7f08"

$results[[4]]$parent
$results[[4]]$parent$type
[1] "page_id"

$results[[4]]$parent$page_id
[1] "df0ef29f-da8a-4e74-8713-f30f19727503"


$results[[4]]$created_time
[1] "2024-08-26T12:23:00.000Z"

$results[[4]]$last_edited_time
[1] "2024-08-26T12:23:00.000Z"

$results[[4]]$created_by
$results[[4]]$created_by$object
[1] "user"

$results[[4]]$created_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[4]]$last_edited_by
$results[[4]]$last_edited_by$object
[1] "user"

$results[[4]]$last_edited_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[4]]$has_children
[1] FALSE

$results[[4]]$archived
[1] FALSE

$results[[4]]$in_trash
[1] FALSE

$results[[4]]$type
[1] "heading_1"

$results[[4]]$heading_1
$results[[4]]$heading_1$rich_text
$results[[4]]$heading_1$rich_text[[1]]
$results[[4]]$heading_1$rich_text[[1]]$type
[1] "text"

$results[[4]]$heading_1$rich_text[[1]]$text
$results[[4]]$heading_1$rich_text[[1]]$text$content
[1] "Description"

$results[[4]]$heading_1$rich_text[[1]]$text$link
NULL


$results[[4]]$heading_1$rich_text[[1]]$annotations
$results[[4]]$heading_1$rich_text[[1]]$annotations$bold
[1] FALSE

$results[[4]]$heading_1$rich_text[[1]]$annotations$italic
[1] FALSE

$results[[4]]$heading_1$rich_text[[1]]$annotations$strikethrough
[1] FALSE

$results[[4]]$heading_1$rich_text[[1]]$annotations$underline
[1] FALSE

$results[[4]]$heading_1$rich_text[[1]]$annotations$code
[1] FALSE

$results[[4]]$heading_1$rich_text[[1]]$annotations$color
[1] "default"


$results[[4]]$heading_1$rich_text[[1]]$plain_text
[1] "Description"

$results[[4]]$heading_1$rich_text[[1]]$href
NULL



$results[[4]]$heading_1$is_toggleable
[1] FALSE

$results[[4]]$heading_1$color
[1] "default"



$results[[5]]
$results[[5]]$object
[1] "block"

$results[[5]]$id
[1] "933e132a-3bc1-4cd0-b1d5-6287d9cab90e"

$results[[5]]$parent
$results[[5]]$parent$type
[1] "page_id"

$results[[5]]$parent$page_id
[1] "df0ef29f-da8a-4e74-8713-f30f19727503"


$results[[5]]$created_time
[1] "2024-08-26T12:23:00.000Z"

$results[[5]]$last_edited_time
[1] "2024-08-26T12:23:00.000Z"

$results[[5]]$created_by
$results[[5]]$created_by$object
[1] "user"

$results[[5]]$created_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[5]]$last_edited_by
$results[[5]]$last_edited_by$object
[1] "user"

$results[[5]]$last_edited_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[5]]$has_children
[1] FALSE

$results[[5]]$archived
[1] FALSE

$results[[5]]$in_trash
[1] FALSE

$results[[5]]$type
[1] "paragraph"

$results[[5]]$paragraph
$results[[5]]$paragraph$rich_text
$results[[5]]$paragraph$rich_text[[1]]
$results[[5]]$paragraph$rich_text[[1]]$type
[1] "text"

$results[[5]]$paragraph$rich_text[[1]]$text
$results[[5]]$paragraph$rich_text[[1]]$text$content
[1] "Complete Streets policies aim for all people regardless of travel mode, age, ability, income, race, or ethnicity to safely and conveniently access destinations. Complete Streets involve high-level policy direction that gradually modifies corridors, driveways, intersections, curbs, lanes, crosswalks, landscaping, transit stops, and more. Complete Streets policies work through everyday decision-making processes rather than a single project or design prescription. They come in a variety of forms like resolutions, policies, laws, plans, design manuals, executive orders, or tax ordinances. "

$results[[5]]$paragraph$rich_text[[1]]$text$link
NULL


$results[[5]]$paragraph$rich_text[[1]]$annotations
$results[[5]]$paragraph$rich_text[[1]]$annotations$bold
[1] FALSE

$results[[5]]$paragraph$rich_text[[1]]$annotations$italic
[1] FALSE

$results[[5]]$paragraph$rich_text[[1]]$annotations$strikethrough
[1] FALSE

$results[[5]]$paragraph$rich_text[[1]]$annotations$underline
[1] FALSE

$results[[5]]$paragraph$rich_text[[1]]$annotations$code
[1] FALSE

$results[[5]]$paragraph$rich_text[[1]]$annotations$color
[1] "default"


$results[[5]]$paragraph$rich_text[[1]]$plain_text
[1] "Complete Streets policies aim for all people regardless of travel mode, age, ability, income, race, or ethnicity to safely and conveniently access destinations. Complete Streets involve high-level policy direction that gradually modifies corridors, driveways, intersections, curbs, lanes, crosswalks, landscaping, transit stops, and more. Complete Streets policies work through everyday decision-making processes rather than a single project or design prescription. They come in a variety of forms like resolutions, policies, laws, plans, design manuals, executive orders, or tax ordinances. "

$results[[5]]$paragraph$rich_text[[1]]$href
NULL



$results[[5]]$paragraph$color
[1] "default"



$results[[6]]
$results[[6]]$object
[1] "block"

$results[[6]]$id
[1] "31a6ca81-05b5-45fc-a530-f7c1cc8e8d33"

$results[[6]]$parent
$results[[6]]$parent$type
[1] "page_id"

$results[[6]]$parent$page_id
[1] "df0ef29f-da8a-4e74-8713-f30f19727503"


$results[[6]]$created_time
[1] "2024-08-26T12:23:00.000Z"

$results[[6]]$last_edited_time
[1] "2024-08-26T12:23:00.000Z"

$results[[6]]$created_by
$results[[6]]$created_by$object
[1] "user"

$results[[6]]$created_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[6]]$last_edited_by
$results[[6]]$last_edited_by$object
[1] "user"

$results[[6]]$last_edited_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[6]]$has_children
[1] FALSE

$results[[6]]$archived
[1] FALSE

$results[[6]]$in_trash
[1] FALSE

$results[[6]]$type
[1] "heading_1"

$results[[6]]$heading_1
$results[[6]]$heading_1$rich_text
$results[[6]]$heading_1$rich_text[[1]]
$results[[6]]$heading_1$rich_text[[1]]$type
[1] "text"

$results[[6]]$heading_1$rich_text[[1]]$text
$results[[6]]$heading_1$rich_text[[1]]$text$content
[1] "How this policy relates to climate change"

$results[[6]]$heading_1$rich_text[[1]]$text$link
NULL


$results[[6]]$heading_1$rich_text[[1]]$annotations
$results[[6]]$heading_1$rich_text[[1]]$annotations$bold
[1] FALSE

$results[[6]]$heading_1$rich_text[[1]]$annotations$italic
[1] FALSE

$results[[6]]$heading_1$rich_text[[1]]$annotations$strikethrough
[1] FALSE

$results[[6]]$heading_1$rich_text[[1]]$annotations$underline
[1] FALSE

$results[[6]]$heading_1$rich_text[[1]]$annotations$code
[1] FALSE

$results[[6]]$heading_1$rich_text[[1]]$annotations$color
[1] "default"


$results[[6]]$heading_1$rich_text[[1]]$plain_text
[1] "How this policy relates to climate change"

$results[[6]]$heading_1$rich_text[[1]]$href
NULL



$results[[6]]$heading_1$is_toggleable
[1] FALSE

$results[[6]]$heading_1$color
[1] "default"



$results[[7]]
$results[[7]]$object
[1] "block"

$results[[7]]$id
[1] "2c51a036-17a3-467e-b138-fc94ba81aac3"

$results[[7]]$parent
$results[[7]]$parent$type
[1] "page_id"

$results[[7]]$parent$page_id
[1] "df0ef29f-da8a-4e74-8713-f30f19727503"


$results[[7]]$created_time
[1] "2024-08-26T12:23:00.000Z"

$results[[7]]$last_edited_time
[1] "2024-08-26T12:23:00.000Z"

$results[[7]]$created_by
$results[[7]]$created_by$object
[1] "user"

$results[[7]]$created_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[7]]$last_edited_by
$results[[7]]$last_edited_by$object
[1] "user"

$results[[7]]$last_edited_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[7]]$has_children
[1] FALSE

$results[[7]]$archived
[1] FALSE

$results[[7]]$in_trash
[1] FALSE

$results[[7]]$type
[1] "paragraph"

$results[[7]]$paragraph
$results[[7]]$paragraph$rich_text
$results[[7]]$paragraph$rich_text[[1]]
$results[[7]]$paragraph$rich_text[[1]]$type
[1] "text"

$results[[7]]$paragraph$rich_text[[1]]$text
$results[[7]]$paragraph$rich_text[[1]]$text$content
[1] "Complete Street policies play a role in larger climate goals by supporting sustainable transit options and transit-oriented development. By prioritizing street safety, active mobility, and transit, these policies can reap the climate benefits of low-carbon mobility and dense urban spaces. "

$results[[7]]$paragraph$rich_text[[1]]$text$link
NULL


$results[[7]]$paragraph$rich_text[[1]]$annotations
$results[[7]]$paragraph$rich_text[[1]]$annotations$bold
[1] FALSE

$results[[7]]$paragraph$rich_text[[1]]$annotations$italic
[1] FALSE

$results[[7]]$paragraph$rich_text[[1]]$annotations$strikethrough
[1] FALSE

$results[[7]]$paragraph$rich_text[[1]]$annotations$underline
[1] FALSE

$results[[7]]$paragraph$rich_text[[1]]$annotations$code
[1] FALSE

$results[[7]]$paragraph$rich_text[[1]]$annotations$color
[1] "default"


$results[[7]]$paragraph$rich_text[[1]]$plain_text
[1] "Complete Street policies play a role in larger climate goals by supporting sustainable transit options and transit-oriented development. By prioritizing street safety, active mobility, and transit, these policies can reap the climate benefits of low-carbon mobility and dense urban spaces. "

$results[[7]]$paragraph$rich_text[[1]]$href
NULL



$results[[7]]$paragraph$color
[1] "default"



$results[[8]]
$results[[8]]$object
[1] "block"

$results[[8]]$id
[1] "00661a3f-13f0-4117-a27e-6186089c9e91"

$results[[8]]$parent
$results[[8]]$parent$type
[1] "page_id"

$results[[8]]$parent$page_id
[1] "df0ef29f-da8a-4e74-8713-f30f19727503"


$results[[8]]$created_time
[1] "2024-08-26T12:23:00.000Z"

$results[[8]]$last_edited_time
[1] "2024-08-26T12:23:00.000Z"

$results[[8]]$created_by
$results[[8]]$created_by$object
[1] "user"

$results[[8]]$created_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[8]]$last_edited_by
$results[[8]]$last_edited_by$object
[1] "user"

$results[[8]]$last_edited_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[8]]$has_children
[1] FALSE

$results[[8]]$archived
[1] FALSE

$results[[8]]$in_trash
[1] FALSE

$results[[8]]$type
[1] "heading_1"

$results[[8]]$heading_1
$results[[8]]$heading_1$rich_text
$results[[8]]$heading_1$rich_text[[1]]
$results[[8]]$heading_1$rich_text[[1]]$type
[1] "text"

$results[[8]]$heading_1$rich_text[[1]]$text
$results[[8]]$heading_1$rich_text[[1]]$text$content
[1] "Image"

$results[[8]]$heading_1$rich_text[[1]]$text$link
NULL


$results[[8]]$heading_1$rich_text[[1]]$annotations
$results[[8]]$heading_1$rich_text[[1]]$annotations$bold
[1] FALSE

$results[[8]]$heading_1$rich_text[[1]]$annotations$italic
[1] FALSE

$results[[8]]$heading_1$rich_text[[1]]$annotations$strikethrough
[1] FALSE

$results[[8]]$heading_1$rich_text[[1]]$annotations$underline
[1] FALSE

$results[[8]]$heading_1$rich_text[[1]]$annotations$code
[1] FALSE

$results[[8]]$heading_1$rich_text[[1]]$annotations$color
[1] "default"


$results[[8]]$heading_1$rich_text[[1]]$plain_text
[1] "Image"

$results[[8]]$heading_1$rich_text[[1]]$href
NULL



$results[[8]]$heading_1$is_toggleable
[1] FALSE

$results[[8]]$heading_1$color
[1] "default"



$results[[9]]
$results[[9]]$object
[1] "block"

$results[[9]]$id
[1] "ad1f972d-4dc5-4dde-85f4-367ffb2ddcfd"

$results[[9]]$parent
$results[[9]]$parent$type
[1] "page_id"

$results[[9]]$parent$page_id
[1] "df0ef29f-da8a-4e74-8713-f30f19727503"


$results[[9]]$created_time
[1] "2024-08-26T12:23:00.000Z"

$results[[9]]$last_edited_time
[1] "2024-08-26T12:23:00.000Z"

$results[[9]]$created_by
$results[[9]]$created_by$object
[1] "user"

$results[[9]]$created_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[9]]$last_edited_by
$results[[9]]$last_edited_by$object
[1] "user"

$results[[9]]$last_edited_by$id
[1] "1ca75cfc-5e6e-4d74-a910-22230756647c"


$results[[9]]$has_children
[1] FALSE

$results[[9]]$archived
[1] FALSE

$results[[9]]$in_trash
[1] FALSE

$results[[9]]$type
[1] "image"

$results[[9]]$image
$results[[9]]$image$caption
list()

$results[[9]]$image$type
[1] "external"

$results[[9]]$image$external
$results[[9]]$image$external$url
[1] "https://www.mdpi.com/sustainability/sustainability-14-13142/article_deploy/html/images/sustainability-14-13142-g009b-550.jpg"





$next_cursor
NULL

$has_more
[1] FALSE

$type
[1] "block"

$block
named list()

$request_id
[1] "f5e9ef98-70fb-4c30-98f5-a2e521bcfaf2"
clear_page_children(test_page)
Deleted block 0cec0e78-1c5d-443c-906d-571d6f97151eDeleted block 59b021f4-1944-422c-abd0-bc982dc1ea63Deleted block 5a65ff61-8b18-48e3-97e0-95a0f7dccdc3Deleted block d99fc22c-1120-498c-a954-da70aa9a7f08Deleted block 933e132a-3bc1-4cd0-b1d5-6287d9cab90eDeleted block 31a6ca81-05b5-45fc-a530-f7c1cc8e8d33Deleted block 2c51a036-17a3-467e-b138-fc94ba81aac3Deleted block 00661a3f-13f0-4117-a27e-6186089c9e91Deleted block ad1f972d-4dc5-4dde-85f4-367ffb2ddcfdCleared 9 blocks from page df0ef29fda8a4e748713f30f19727503

6 Choose which pages to write to

Now we have basic logic lets just subset for pages we want to write and execute. Earlier we already created df_parsed which is the operatioanlie tempalting data for the 5 pages for this PoC. Lets just loop through and write to each page.

df_parsed %>% 
  group_by(row_number()) %>%
  group_walk(~{
    row = .x # row = df_parsed %>% slice(1)
    cli_alert_info("Starting to write to page - {row$title}")
    clear_page_children(row$id_clean)
    write_cec_template_poc(row)
    cli_alert_success("Finished writing to page")
  })
Page is already empty.
Deleted block 5c5afc0b-9686-463e-a17e-6884677ee82cDeleted block 1d76d259-dc19-401c-bbf0-36164c57f389Deleted block b08a4f69-fbd9-4ee1-a5db-5e8b0ca0e13bDeleted block de58e88c-34fd-4d83-87a0-6bd5e35bfae4Deleted block aeb7fcae-1dfb-4676-915d-6980fceae2cdDeleted block f9723304-e1ca-471f-a490-d8b29a85b2d8Deleted block b0b495b5-3234-4fa4-bac8-08e7b63baa44Deleted block b41c9773-147e-4ec3-947f-d6e9d37d98c2Deleted block 9c8da68a-c5a7-4764-b6d6-83bef4429146Cleared 9 blocks from page 81b63652a8be48eaa1b2fcfb8aa8165eDeleted block 8b23d11a-97b4-4380-9c49-18e1edd4ba45Deleted block a7656980-ed47-4a43-838b-a384551b1f54Deleted block 5ab6485d-45cf-4697-80f2-17403b9688e3Deleted block b2b77a9e-f2df-43a0-843e-71a04a6bb3acDeleted block 679ac6ea-cfed-4804-b973-b51e394519a2Deleted block 1c8196bc-dad5-44e6-a74c-596e5ea0a33bDeleted block d4284d59-bc6e-4d06-9047-756832dfcf2fDeleted block 4029a920-00d3-4ddb-ae6d-2858118ee8ccDeleted block 3b560444-18c4-42bb-9831-f97b0c201fafCleared 9 blocks from page f8f99d629bfc4668837967406ad3a01bDeleted block 710c9a3b-9cd3-40b1-bfb3-2615a96dd52dDeleted block ccff8ea7-2a35-42ce-8829-6c423a402ea2Deleted block 8dfbc9b8-ad1f-4a22-bc75-4f1d940a901dDeleted block d9d43cb6-8396-4161-b5ca-df165281029fDeleted block 815b74ef-9611-4105-9808-9a1481b1ba34Deleted block a1d001de-afce-4bbb-a01b-d63b6a199cadDeleted block 9a7a4e54-3e19-4c13-b4f4-95732affbb2eDeleted block 084ab109-3c7c-4cca-b412-9930aea2bdddDeleted block 4e47ffc8-5690-4651-a6bd-178ddf8f5836Cleared 9 blocks from page 3f0c1c1ba26a46369aaa64c8c0a3bdbdDeleted block 8ad6737d-b32a-44a8-a275-0bb20a4e6a11Deleted block 2d25a6bd-3abc-42f0-9c7e-76c635c887aaDeleted block d0a12f00-d218-4f6f-968c-8a9b36b75d15Deleted block f6910619-b06e-4618-8da4-efed0e6f472aDeleted block 0d465d25-1dd8-4a4d-87f2-091950ee16dbDeleted block abd38676-f529-48b7-8b61-8f2228dc3b81Deleted block 0e3d90b6-5587-4612-80a9-ce3aaf32ca17Deleted block d0a035cf-0a2f-4f40-8a30-71c47f502da3Deleted block 205534fc-fa22-4288-a011-546a1d5619d0Cleared 9 blocks from page c3e2e3244a3f4cf09a82c28365bd0a3e