Skip to content

Commit 3baaad9

Browse files
timtmokjuliasilge
andauthored
Add checksums to download table (#80)
Shows only if available Clicking on checksum copies it to clipboard --------- Co-authored-by: Julia Silge <julia.silge@gmail.com>
1 parent 5371c34 commit 3baaad9

File tree

3 files changed

+115
-12
lines changed

3 files changed

+115
-12
lines changed

_download.html

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,32 @@
1414
.visible {
1515
transition-duration: 1s;
1616
}
17+
.checksum {
18+
cursor: pointer;
19+
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
20+
text-decoration: underline;
21+
position: relative;
22+
display: inline-block;
23+
/* Added to ensure proper tooltip positioning */
24+
}
25+
.copy-feedback {
26+
position: absolute;
27+
background: rgba(0, 0, 0, 0.8);
28+
color: white;
29+
padding: 4px 8px;
30+
border-radius: 4px;
31+
font-size: 12px;
32+
bottom: 100%;
33+
left: 50%;
34+
transform: translateX(-50%);
35+
white-space: nowrap;
36+
z-index: 1000;
37+
opacity: 0;
38+
transition: opacity 0.2s ease-in-out;
39+
}
40+
.copy-feedback.visible {
41+
opacity: 1;
42+
}
1743
</style>
1844

1945
<script type="application/javascript">
@@ -51,4 +77,44 @@
5177
function updatePrivacy(checkbox) {
5278
setLinkEnablement(checkbox.checked);
5379
}
80+
81+
function copyChecksum(text, element) {
82+
// Remove any existing feedback elements
83+
const existingFeedback = element.querySelector('.copy-feedback');
84+
if (existingFeedback) {
85+
existingFeedback.remove();
86+
}
87+
88+
// Create feedback element
89+
const feedback = document.createElement('div');
90+
feedback.className = 'copy-feedback';
91+
feedback.textContent = 'Copied!';
92+
element.appendChild(feedback);
93+
94+
// Copy to clipboard
95+
navigator.clipboard.writeText(text).then(() => {
96+
// Show feedback
97+
requestAnimationFrame(() => {
98+
feedback.classList.add('visible');
99+
100+
// Hide and remove feedback after delay
101+
setTimeout(() => {
102+
feedback.classList.remove('visible');
103+
setTimeout(() => {
104+
feedback.remove();
105+
}, 200); // Remove after fade out
106+
}, 1000);
107+
});
108+
}).catch((err) => {
109+
console.error('Failed to copy text: ', err);
110+
feedback.textContent = 'Failed to copy';
111+
feedback.classList.add('visible');
112+
setTimeout(() => {
113+
feedback.classList.remove('visible');
114+
setTimeout(() => {
115+
feedback.remove();
116+
}, 200);
117+
}, 1000);
118+
});
119+
}
54120
</script>

_freeze/download/execute-results/html.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
2-
"hash": "4c298204fb3b3de18c489809e2a2942b",
2+
"hash": "ed6aa54fd60aa2e0e89a5768052bfc03",
33
"result": {
44
"engine": "knitr",
5-
"markdown": "---\ntitle: \"Download Positron\"\nparams:\n version: \"2025.06.0-167\"\nformat:\n html:\n include-in-header:\n - '_download.html'\n\n---\n\n### Positron on desktop\n\nFind out what you need to know to [get started](start.qmd) using Positron, then download the desktop installer for your platform.\n\n::: callout-important\n## Accept license agreement\n\nPlease review [Positron's license agreement](licensing.qmd) and [privacy policy](https://posit.co/about/privacy-policy/). Your acceptance of this license agreement and privacy policy is required as a condition to proceeding with your download or use of the software.\n\n<div id=\"privacy-policy-agreement\">\n <input type=\"checkbox\" id=\"privacy-checkbox\" onclick=\"updatePrivacy(this)\">\n <label>I agree to the [Positron license agreement](licensing.qmd) and [Posit Privacy Policy](https://posit.co/about/privacy-policy/).</label>\n</div>\n:::\n\n\n\n::: {.cell .plain id='download-table'}\n::: {.cell-output-display}\n\n\n|Platform |Download |Size |\n|:-----------------------------------------|:------------------------------------|:----|\n|Windows 10, 11 x64 (system level install) |[Positron-2025.06.0-167-Setup.exe](https://cdn.posit.co/positron/prereleases/win/x86_64/Positron-2025.06.0-167-Setup.exe)|312M |\n|Windows 10, 11 x64 (user level install) |[Positron-2025.06.0-167-UserSetup.exe](https://cdn.posit.co/positron/prereleases/win/x86_64/Positron-2025.06.0-167-UserSetup.exe)|312M |\n|MacOS 10.15+ (universal) |[Positron-2025.06.0-167.dmg](https://cdn.posit.co/positron/prereleases/mac/universal/Positron-2025.06.0-167.dmg)|773M |\n|Debian-based Linux x64 (Ubuntu 20+) |[Positron-2025.06.0-167-x64.deb](https://cdn.posit.co/positron/prereleases/deb/x86_64/Positron-2025.06.0-167-x64.deb)|310M |\n|Debian-based Linux arm64 (Ubuntu 20+) |[Positron-2025.06.0-167-arm64.deb](https://cdn.posit.co/positron/prereleases/deb/arm64/Positron-2025.06.0-167-arm64.deb)|304M |\n|Red Hat-based Linux x64 (RHEL9) |[Positron-2025.06.0-167-x64.rpm](https://cdn.posit.co/positron/prereleases/rpm/x86_64/Positron-2025.06.0-167-x64.rpm)|349M |\n|Red Hat-based Linux arm64 (RHEL9) |[Positron-2025.06.0-167-arm64.rpm](https://cdn.posit.co/positron/prereleases/rpm/arm64/Positron-2025.06.0-167-arm64.rpm)|344M |\n\n\n:::\n:::\n\n<br>\nOlder releases [are available on GitHub](https://github.com/posit-dev/positron/releases).\n\n### Positron Pro on Posit Workbench\n\n[Posit Workbench](https://posit.co/products/enterprise/workbench/) 2024.12.1 and later includes preview support for Positron Pro. To configure and use Positron Pro on Posit Workbench, please see the [Posit Workbench Administration Guide](https://docs.posit.co/ide/server-pro/positron_sessions/) and the [Positron Pro user guide](https://docs.posit.co/ide/server-pro/user/positron/getting-started/).\n",
5+
"markdown": "---\ntitle: \"Download Positron\"\nparams:\n version: \"2025.06.0-167\"\nformat:\n html:\n include-in-header:\n - '_download.html'\n\n---\n\n\n\n\n### Positron on desktop\n\nFind out what you need to know to [get started](start.qmd) using Positron, then download the desktop installer for your platform.\n\n::: callout-important\n## Accept license agreement\n\nPlease review [Positron's license agreement](licensing.qmd) and [privacy policy](https://posit.co/about/privacy-policy/). Your acceptance of this license agreement and privacy policy is required as a condition to proceeding with your download or use of the software.\n\n<div id=\"privacy-policy-agreement\">\n <input type=\"checkbox\" id=\"privacy-checkbox\" onclick=\"updatePrivacy(this)\">\n <label>I agree to the [Positron license agreement](licensing.qmd) and [Posit Privacy Policy](https://posit.co/about/privacy-policy/).</label>\n</div>\n:::\n\n\n\n\n\n::: {.cell .plain id='download-table'}\n::: {.cell-output-display}\n`````{=html}\n<table>\n <thead>\n <tr>\n <th style=\"text-align:left;\"> Platform </th>\n <th style=\"text-align:left;\"> Download </th>\n <th style=\"text-align:left;\"> Size </th>\n <th style=\"text-align:left;\"> SHA-256 </th>\n </tr>\n </thead>\n<tbody>\n <tr>\n <td style=\"text-align:left;\"> Windows 10, 11 x64 (system level install) </td>\n <td style=\"text-align:left;\"> <a href=\"https://cdn.posit.co/positron/prereleases/win/x86_64/Positron-2025.06.0-167-Setup.exe\">Positron-2025.06.0-167-Setup.exe</a> </td>\n <td style=\"text-align:left;\"> 312M </td>\n <td style=\"text-align:left;\"> <span class=\"checksum\" onclick=\"copyChecksum('c42fe045ea859d5d58f36c5961da1c993683f36966c276558a0540e04609df80', this)\" title=\"Click to copy full checksum\">c42fe04</span> </td>\n </tr>\n <tr>\n <td style=\"text-align:left;\"> Windows 10, 11 x64 (user level install) </td>\n <td style=\"text-align:left;\"> <a href=\"https://cdn.posit.co/positron/prereleases/win/x86_64/Positron-2025.06.0-167-UserSetup.exe\">Positron-2025.06.0-167-UserSetup.exe</a> </td>\n <td style=\"text-align:left;\"> 312M </td>\n <td style=\"text-align:left;\"> <span class=\"checksum\" onclick=\"copyChecksum('251c751e03db66e50bc6a1e7a359317256861fbdaca8a89996c117b8cc4492fc', this)\" title=\"Click to copy full checksum\">251c751</span> </td>\n </tr>\n <tr>\n <td style=\"text-align:left;\"> MacOS 10.15+ (universal) </td>\n <td style=\"text-align:left;\"> <a href=\"https://cdn.posit.co/positron/prereleases/mac/universal/Positron-2025.06.0-167.dmg\">Positron-2025.06.0-167.dmg</a> </td>\n <td style=\"text-align:left;\"> 773M </td>\n <td style=\"text-align:left;\"> <span class=\"checksum\" onclick=\"copyChecksum('813178aba2feec6581a78d11b52cb2830d031c3729e3735cf67a567122a1f1a5', this)\" title=\"Click to copy full checksum\">813178a</span> </td>\n </tr>\n <tr>\n <td style=\"text-align:left;\"> Debian-based Linux x64 (Ubuntu 20+) </td>\n <td style=\"text-align:left;\"> <a href=\"https://cdn.posit.co/positron/prereleases/deb/x86_64/Positron-2025.06.0-167-x64.deb\">Positron-2025.06.0-167-x64.deb</a> </td>\n <td style=\"text-align:left;\"> 310M </td>\n <td style=\"text-align:left;\"> <span class=\"checksum\" onclick=\"copyChecksum('dae301bcd545f74108f9f4db614863d6b3e4c8dc5fe658d2d2d47b48261eba2f', this)\" title=\"Click to copy full checksum\">dae301b</span> </td>\n </tr>\n <tr>\n <td style=\"text-align:left;\"> Debian-based Linux arm64 (Ubuntu 20+) </td>\n <td style=\"text-align:left;\"> <a href=\"https://cdn.posit.co/positron/prereleases/deb/arm64/Positron-2025.06.0-167-arm64.deb\">Positron-2025.06.0-167-arm64.deb</a> </td>\n <td style=\"text-align:left;\"> 304M </td>\n <td style=\"text-align:left;\"> <span class=\"checksum\" onclick=\"copyChecksum('ab105ce82e31c21d799d021e9a443d3cd2526e18b3f3ab18f4adcf219b0f2b12', this)\" title=\"Click to copy full checksum\">ab105ce</span> </td>\n </tr>\n <tr>\n <td style=\"text-align:left;\"> Red Hat-based Linux x64 (RHEL9) </td>\n <td style=\"text-align:left;\"> <a href=\"https://cdn.posit.co/positron/prereleases/rpm/x86_64/Positron-2025.06.0-167-x64.rpm\">Positron-2025.06.0-167-x64.rpm</a> </td>\n <td style=\"text-align:left;\"> 349M </td>\n <td style=\"text-align:left;\"> <span class=\"checksum\" onclick=\"copyChecksum('74828bc6fd762f3e9d55bf21abfc1a0a9c99cbdfc743e61d1e0ade640fc25550', this)\" title=\"Click to copy full checksum\">74828bc</span> </td>\n </tr>\n <tr>\n <td style=\"text-align:left;\"> Red Hat-based Linux arm64 (RHEL9) </td>\n <td style=\"text-align:left;\"> <a href=\"https://cdn.posit.co/positron/prereleases/rpm/arm64/Positron-2025.06.0-167-arm64.rpm\">Positron-2025.06.0-167-arm64.rpm</a> </td>\n <td style=\"text-align:left;\"> 344M </td>\n <td style=\"text-align:left;\"> <span class=\"checksum\" onclick=\"copyChecksum('c6395724849994e0ad670fec7ef706a621884c875359656d48856ec5203eaf6e', this)\" title=\"Click to copy full checksum\">c639572</span> </td>\n </tr>\n</tbody>\n</table>\n\n`````\n:::\n:::\n\n\n\n<br>\nOlder releases [are available on GitHub](https://github.com/posit-dev/positron/releases).\n\n### Positron Pro on Posit Workbench\n\n[Posit Workbench](https://posit.co/products/enterprise/workbench/) 2024.12.1 and later includes preview support for Positron Pro. To configure and use Positron Pro on Posit Workbench, please see the [Posit Workbench Administration Guide](https://docs.posit.co/ide/server-pro/positron_sessions/) and the [Positron Pro user guide](https://docs.posit.co/ide/server-pro/user/positron/getting-started/).\n",
66
"supporting": [],
77
"filters": [
88
"rmarkdown/pagebreak.lua"

download.qmd

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,31 +27,61 @@ Please review [Positron's license agreement](licensing.qmd) and [privacy policy]
2727

2828
```{r, id='download-table'}
2929
#| echo: false
30+
#| warning: false
3031
#| classes: plain
3132
3233
library(purrr)
3334
library(glue)
3435
library(httr)
36+
library(jsonlite)
3537
38+
# Create URLs
3639
cdn_url <- "https://cdn.posit.co/positron/prereleases/"
37-
40+
windows_system <- glue("Positron-{params$version}-Setup.exe")
41+
windows_user <- glue("Positron-{params$version}-UserSetup.exe")
42+
macos_universal <- glue("Positron-{params$version}.dmg")
43+
debian_x64 <- glue("Positron-{params$version}-x64.deb")
44+
debian_arm <- glue("Positron-{params$version}-arm64.deb")
45+
redhat_x64 <- glue("Positron-{params$version}-x64.rpm")
46+
redhat_arm <- glue("Positron-{params$version}-arm64.rpm")
3847
urls <- list(
39-
glue("{cdn_url}win/x86_64/Positron-{params$version}-Setup.exe"),
40-
glue("{cdn_url}win/x86_64/Positron-{params$version}-UserSetup.exe"),
41-
glue("{cdn_url}mac/universal/Positron-{params$version}.dmg"),
42-
glue("{cdn_url}deb/x86_64/Positron-{params$version}-x64.deb"),
43-
glue("{cdn_url}deb/arm64/Positron-{params$version}-arm64.deb"),
44-
glue("{cdn_url}rpm/x86_64/Positron-{params$version}-x64.rpm"),
45-
glue("{cdn_url}rpm/arm64/Positron-{params$version}-arm64.rpm")
48+
glue("{cdn_url}win/x86_64/{windows_system}"),
49+
glue("{cdn_url}win/x86_64/{windows_user}"),
50+
glue("{cdn_url}mac/universal/{macos_universal}"),
51+
glue("{cdn_url}deb/x86_64/{debian_x64}"),
52+
glue("{cdn_url}deb/arm64/{debian_arm}"),
53+
glue("{cdn_url}rpm/x86_64/{redhat_x64}"),
54+
glue("{cdn_url}rpm/arm64/{redhat_arm}")
55+
)
56+
57+
# Get checksums
58+
checksum_data <- rlang::try_fetch(
59+
fromJSON(glue("{cdn_url}checksums/positron-{params$version}-checksums.json")),
60+
error = function(cnd) list(),
61+
warning = function(cnd) list()
4662
)
63+
all_installers <- list(
64+
windows_system,
65+
windows_user,
66+
macos_universal,
67+
debian_x64,
68+
debian_arm,
69+
redhat_x64,
70+
redhat_arm
71+
)
72+
checksums <- map_chr(all_installers, ~ pluck(checksum_data, .))
73+
checksums_short <- substr(checksums, 1, 7)
4774
75+
# Get file sizes
4876
cloudfront_headers <- map(urls, HEAD) |> map(headers)
4977
file_sizes <- map(cloudfront_headers, "content-length") |>
5078
map(fs::fs_bytes) |>
5179
map_chr(as.character)
5280
file_names_only <- stringr::str_extract(urls, "[^\\/]+$")
53-
markdown_links <- glue("[{file_names_only}]({urls})")
5481
82+
markdown_links <- glue('<a href="{urls}">{file_names_only}</a>')
83+
84+
# Create base table without checksums
5585
download_table <- data.frame(
5686
Platform = c(
5787
"Windows 10, 11 x64 (system level install)",
@@ -66,7 +96,14 @@ download_table <- data.frame(
6696
Size = file_sizes
6797
)
6898
69-
knitr::kable(download_table)
99+
# Add checksums column if data is available
100+
if (length(checksums) > 0) {
101+
download_table$`SHA-256` <- glue(
102+
'<span class="checksum" onclick="copyChecksum(\'{checksums}\', this)" title="Click to copy full checksum">{checksums_short}</span>'
103+
)
104+
}
105+
106+
knitr::kable(download_table, format = "html", escape = FALSE)
70107
```
71108
<br>
72109
Older releases [are available on GitHub](https://github.com/posit-dev/positron/releases).

0 commit comments

Comments
 (0)