diff --git a/DESCRIPTION b/DESCRIPTION
index 88c906ae..eea23ca4 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -67,7 +67,7 @@ Language: en-US
RoxygenNote: 7.3.2
Roxygen: list(markdown = TRUE)
Config/testthat/edition: 3
-Collate:
+Collate:
'audits.R'
'browse.R'
'connect.R'
diff --git a/NAMESPACE b/NAMESPACE
index c04ae9b2..65d159df 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -5,9 +5,11 @@ S3method("[",connect_tag_tree)
S3method("[[",connect_tag_tree)
S3method(api_build,op_base_connect)
S3method(api_build,op_head)
+S3method(as.data.frame,connect_content_list)
S3method(as.data.frame,connect_integration_list)
S3method(as.data.frame,connect_list_hits)
S3method(as.data.frame,tbl_connect)
+S3method(as_tibble,connect_content_list)
S3method(as_tibble,connect_integration_list)
S3method(as_tibble,connect_list_hits)
S3method(connect_vars,op_base)
diff --git a/R/content.R b/R/content.R
index f3a1eef6..42822f3c 100644
--- a/R/content.R
+++ b/R/content.R
@@ -1504,7 +1504,7 @@ get_content_packages <- function(content) {
#' usually not what you want.
#'
#' @return
-#' A list of [Content] objects.
+#' A list of [Content] objects, of class "connect_content_list"
#'
#' @details
#' Please see https://docs.posit.co/connect/api/#get-/v1/search/content for more
@@ -1548,9 +1548,12 @@ search_content <- function(
limit = limit
)
- purrr::map(res, function(x) {
+ content_list <- purrr::map(res, function(x) {
Content$new(client, x)
})
+
+ class(content_list) <- c("connect_content_list", class(content_list))
+ content_list
}
.search_content <- function(
@@ -1573,3 +1576,45 @@ search_content <- function(
client$GET(path, query = query)
}
+
+#' Convert content list to a data frame
+#'
+#' @description
+#' Converts a list returned by [search_content()] into a data frame.
+#'
+#' @param x A `connect_content_list` object (from [search_content()]).
+#' @param row.names Passed to [base::as.data.frame()].
+#' @param optional Passed to [base::as.data.frame()].
+#' @param ... Passed to [base::as.data.frame()].
+#'
+#' @return A `data.frame` with one row per content item.
+#' @export
+as.data.frame.connect_content_list <- function(
+ x,
+ row.names = NULL, # nolint
+ optional = FALSE,
+ ...
+) {
+ content_tbl <- as_tibble(x)
+ as.data.frame(
+ content_tbl,
+ row.names = row.names,
+ optional = optional,
+ ...
+ )
+}
+
+#' Convert integration list to a tibble
+#'
+#' @description
+#' Converts a list returned by [search_content()] to a tibble.
+#'
+#' @param x A `connect_content_list` object.
+#' @param ... Unused.
+#'
+#' @return A tibble with one row per content item.
+#' @export
+as_tibble.connect_content_list <- function(x, ...) {
+ content_data <- purrr::map(x, "content")
+ parse_connectapi_typed(content_data, connectapi_ptypes$content)
+}
diff --git a/man/VariantR6.Rd b/man/VariantR6.Rd
index be0cc4a6..cdf922d6 100644
--- a/man/VariantR6.Rd
+++ b/man/VariantR6.Rd
@@ -39,7 +39,6 @@ Other R6 classes:
\section{Methods}{
\subsection{Public methods}{
\itemize{
-\item \href{#method-Variant-get_variant}{\code{Variant$get_variant()}}
\item \href{#method-Variant-get_variant_remote}{\code{Variant$get_variant_remote()}}
\item \href{#method-Variant-new}{\code{Variant$new()}}
\item \href{#method-Variant-send_mail}{\code{Variant$send_mail()}}
@@ -90,19 +89,12 @@ Other R6 classes:
}}
\if{html}{\out{
}}
-\if{html}{\out{}}
-\if{latex}{\out{\hypertarget{method-Variant-get_variant}{}}}
-\subsection{Method \code{get_variant()}}{
-Get the underlying variant data.
-\subsection{Usage}{
-\if{html}{\out{}}\preformatted{Variant$get_variant()}\if{html}{\out{
}}
-}
-
-}
-\if{html}{\out{
}}
\if{html}{\out{}}
\if{latex}{\out{\hypertarget{method-Variant-get_variant_remote}{}}}
\subsection{Method \code{get_variant_remote()}}{
+Get the underlying variant data.
+
+
Get and store the (remote) variant data.
\subsection{Usage}{
\if{html}{\out{}}\preformatted{Variant$get_variant_remote()}\if{html}{\out{
}}
diff --git a/man/VariantSchedule.Rd b/man/VariantSchedule.Rd
index ee961e1a..d7c23e29 100644
--- a/man/VariantSchedule.Rd
+++ b/man/VariantSchedule.Rd
@@ -81,7 +81,6 @@ Other R6 classes:
connectapi::Variant$get_subscribers()
connectapi::Variant$get_url()
connectapi::Variant$get_url_rev()
-connectapi::Variant$get_variant()
connectapi::Variant$get_variant_remote()
connectapi::Variant$job()
connectapi::Variant$jobs()
diff --git a/man/VariantTask.Rd b/man/VariantTask.Rd
index 4f23bd9e..316a53a1 100644
--- a/man/VariantTask.Rd
+++ b/man/VariantTask.Rd
@@ -80,7 +80,6 @@ Other R6 classes:
connectapi::Variant$get_subscribers()
connectapi::Variant$get_url()
connectapi::Variant$get_url_rev()
-connectapi::Variant$get_variant()
connectapi::Variant$get_variant_remote()
connectapi::Variant$job()
connectapi::Variant$jobs()
diff --git a/man/as.data.frame.connect_content_list.Rd b/man/as.data.frame.connect_content_list.Rd
new file mode 100644
index 00000000..5f958dfd
--- /dev/null
+++ b/man/as.data.frame.connect_content_list.Rd
@@ -0,0 +1,23 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/content.R
+\name{as.data.frame.connect_content_list}
+\alias{as.data.frame.connect_content_list}
+\title{Convert content list to a data frame}
+\usage{
+\method{as.data.frame}{connect_content_list}(x, row.names = NULL, optional = FALSE, ...)
+}
+\arguments{
+\item{x}{A \code{connect_content_list} object (from \code{\link[=search_content]{search_content()}}).}
+
+\item{row.names}{Passed to \code{\link[base:as.data.frame]{base::as.data.frame()}}.}
+
+\item{optional}{Passed to \code{\link[base:as.data.frame]{base::as.data.frame()}}.}
+
+\item{...}{Passed to \code{\link[base:as.data.frame]{base::as.data.frame()}}.}
+}
+\value{
+A \code{data.frame} with one row per content item.
+}
+\description{
+Converts a list returned by \code{\link[=search_content]{search_content()}} into a data frame.
+}
diff --git a/man/as_tibble.connect_content_list.Rd b/man/as_tibble.connect_content_list.Rd
new file mode 100644
index 00000000..ff6147e2
--- /dev/null
+++ b/man/as_tibble.connect_content_list.Rd
@@ -0,0 +1,19 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/content.R
+\name{as_tibble.connect_content_list}
+\alias{as_tibble.connect_content_list}
+\title{Convert integration list to a tibble}
+\usage{
+\method{as_tibble}{connect_content_list}(x, ...)
+}
+\arguments{
+\item{x}{A \code{connect_content_list} object.}
+
+\item{...}{Unused.}
+}
+\value{
+A tibble with one row per content item.
+}
+\description{
+Converts a list returned by \code{\link[=search_content]{search_content()}} to a tibble.
+}
diff --git a/man/search_content.Rd b/man/search_content.Rd
index b84636e6..531fd25a 100644
--- a/man/search_content.Rd
+++ b/man/search_content.Rd
@@ -33,7 +33,7 @@ for pagination, but all subsequent pages will still be fetched. This is
usually not what you want.}
}
\value{
-A list of \link{Content} objects.
+A list of \link{Content} objects, of class "connect_content_list"
}
\description{
Search for content on the Connect server
diff --git a/tests/testthat/test-content.R b/tests/testthat/test-content.R
index 1aa56df1..563f551d 100644
--- a/tests/testthat/test-content.R
+++ b/tests/testthat/test-content.R
@@ -536,6 +536,58 @@ with_mock_dir("2025.09.0", {
)
)
})
+
+ test_that("search_content() can be converted to a data frame correctly", {
+ content_df <- search_content(client, q = "sea bream") |>
+ as_tibble()
+ expect_named(
+ content_df,
+ c(
+ "guid",
+ "name",
+ "title",
+ "description",
+ "access_type",
+ "connection_timeout",
+ "read_timeout",
+ "init_timeout",
+ "idle_timeout",
+ "max_processes",
+ "min_processes",
+ "max_conns_per_process",
+ "load_factor",
+ "created_time",
+ "last_deployed_time",
+ "bundle_id",
+ "app_mode",
+ "content_category",
+ "parameterized",
+ "cluster_name",
+ "image_name",
+ "r_version",
+ "py_version",
+ "quarto_version",
+ "run_as",
+ "run_as_current_user",
+ "owner_guid",
+ "content_url",
+ "dashboard_url",
+ "app_role",
+ "vanity_url",
+ "id",
+ "owner",
+ "tags"
+ )
+ )
+ expect_equal(
+ content_df$title,
+ c("sea bream report", "sea bream dashboard")
+ )
+ expect_equal(
+ content_df$guid,
+ c("c9f68287", "53032a0e")
+ )
+ })
})
test_that("content search errors on Connect < 2024.04.0", {