Side B is a real functional/UI fix that reworks post_header_meta to consolidate delete button placement, adjusts CSS flex layout in two themes, and refactors call sites—concrete, testable product code. Side A is a small CI workflow tweak (npm OIDC publishing config) which is useful infra maintenance but lower in lasting code value and scope compared to B's cross-cutting UI/logic change.
constitution · epochs · watch · epoch 3
c_db279f012399 (tommy-mor) vs c_fc17a4aa31e6 (tommy-mor)
download prompt · raw event · cmp_3cd3544aa0743e
council reasoning
A modernizes the npm release path for OIDC trusted publishing (Node 22, npm upgrade, drop NODE_AUTH_TOKEN secrets), a lasting security/ops improvement to how packages ship. B only relocates the delete control into post header meta and adjusts flex CSS—useful UI polish, but a small layout refactor with less project-wide impact.
Side A updates the release workflow toward npm OIDC trusted publishing by moving to Node 22, upgrading npm to a version that supports trusted publishing, and removing reliance on injected NPM auth tokens in the publish steps. Side B is a clean UI refactor that relocates the delete button into the post metadata and adjusts CSS layout, but it primarily changes presentation rather than project infrastructure or release behavior.
sides
A — c_db279f012399 (tommy-mor)
message
[af27c3ab] oicd first pass for npm
diff preview
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index faed75894dace9edcde19eb10753234a1c1261e9..6f3e27e491b56aaaa1ef64c547cc68921e010b3f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -88,9 +88,12 @@ jobs:
- uses: actions/setup-node@v4
with:
- node-version: 20
+ node-version: 22
registry-url: "https://registry.npmjs.org"
+ - name: Upgrade npm for OIDC trusted publishing support
+ run: npm install -g npm@latest
+
- name: Copy binaries into npm platform packages
shell: bash
run: |
@@ -125,8 +128,6 @@ jobs:
- name: Publish npm platform packages
shell: bash
- env:
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euxo pipefail
for pkg in packages/npm/platforms/*; do
@@ -135,15 +136,10 @@ jobs:
- name: Publish npm root package
shell: bash
- env:
- # Unscoped packages need a token that is allowed to create/publish unscoped names.
- # GitHub's setup-node expects NODE_AUTH_TOKEN. See:
- # https://docs.github.com/en/actions/tutorials/publish-packages/publish-nodejs-packages
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN_UNSCOPED }}
run: |
set -euxo pipefail
cd packages/npm
- npm publish --access public --provenance
+ npm publish --access public
publish-pypi:
name: publish PyPI
B — c_fc17a4aa31e6 (tommy-mor)
message
[af6c4464] moved delete button
diff preview
diff --git a/server/src/html/forum/ingest.rs b/server/src/html/forum/ingest.rs
index 168106e495cf1a81f62f6a49e35c64beea287924..308358abc6cd6811079d9ec41b114093c0294d02 100644
--- a/server/src/html/forum/ingest.rs
+++ b/server/src/html/forum/ingest.rs
@@ -45,6 +45,7 @@ fn post_header_meta(
principal: &str,
ts: i64,
now: i64,
+ delete_post_id: Option<&str>,
) -> Markup {
let post_href = nav.post_url(tag, post_idx);
let profile = profile_href(principal);
@@ -52,11 +53,19 @@ fn post_header_meta(
let ago = timeago::timeago(now, ts);
html! {
div class="ingest-meta muted" title=(hover) {
- a href=(post_href) class="post-num" { "#" (post_idx) }
- " "
- a href=(profile) class="post-author" { "@" (principal) }
- " · "
- (ago)
+ span class="ingest-meta-primary" {
+ a href=(post_href) class="post-num" { "#" (post_idx) }
+ " "
+ a href=(profile) class="post-author" { "@" (principal) }
+ " · "
+ (ago)
+ }
+ @if let Some(pid) = delete_post_id {
+ form class="post-delete-form" method="POST" action="/ui" {
+ input type="hidden" name=(UI_RPC_FIELD) value=(template_json_compact(&HtmlUiAction::RedactPost { post_id: pid.to_string() }).unwrap());
+ button type="submit" class="post-delete-btn" { "delete" }
+ }
+ }
}
}
}
@@ -70,18 +79,12 @@ pub(super) fn post_header_row(
now: i64,
show_delete: bool,
) -> Markup {
- let meta = post_header_meta(nav, tag, post_idx, &ing.principal, ing.ts, now);
- html! {
- div class="ingest-header-row" {
- (meta)
- @if show_delete {
- form class="post-delete-form" method="POST" action="/ui" {
- input type="hidden" name=(UI_RPC_FIELD) value=(template_json_compact(&HtmlUiAction::RedactPost { post_id: ing.id.clone() }).unwrap());
- button type="submit" class="post-delete-btn" { "delete" }
- }
- }
- }
- }
+ let delete_post_id = if show_delete {
+ Some(ing.id.as_str())
+ } else {
+ None
+ };
+ post_header_meta(nav, tag, post_idx, &ing.principal, ing.ts, now, delete_post_id)
}
pub(super) fn redacted_header_row(
@@ -92,7 +95,7 @@ pub(super) fn redacted_header_row(
now: i64,
expanded: bool,
) -> Markup {
- let meta = post_header_meta(nav, tag, post_idx, &ing.principal, ing.ts, now);
+ let meta = post_header_meta(nav, tag, post_idx, &ing.principal, ing.ts, now, None);
let rpc_expand = template_json_compact(&json!({
"action": "expand_redacted_post",
"room": nav.room_wire,
diff --git a/server/static/theme_default.css b/server/static/theme_default.css
index 560881c1eec62f12d1e66875287be3c2f39198fc..83b49d079e6bf3e47c27fbd443a0ae75b1a03051 100644
--- a/server/static/theme_default.css
+++ b/server/static/theme_default.css
@@ -552,12 +552,21 @@ pre a.pre-link {
}
div.ingest-meta {
+ align-items: center;
background: var(--g3);
border-bottom: 2px solid var(--lo);
color: var(--meta);
+ display: flex;
+ flex-wrap: wrap;
font-size: 12px;
+ gap: 6px 10px;
+ justify-content: space-between;
padding: 3px 10px;
}
+span.ingest-meta-primary {
+ flex: 1 1 auto;
+ min-width: 0;
+}
a.post-num { color: var(--meta); font-size: 12px; }
a.post-num:hover { color: var(--signal); }
a.post-author { color: var(--meta); font-size: 12px; text-decoration: none; }
@@ -579,7 +588,12 @@ div.ingest-header-row div.ingest-meta {
flex: 1 1 auto;
padding: 0;
}
-form.post-delete-form { display: inline; margin: 0; }
+form.post-delete-form {
+ display: block;
+ flex-shrink: 0;
+ margin: 0;
+ margin-left: auto;
+}
button.post-delete-btn {
background: var(--g4);
border: var(--bv) solid;
diff --git a/server/static/theme_retro_craft.css b/server/static/theme_retro_craft.css
index eb022a8c84c1d0cff36410541872d68a11195e31..7181c7f8547940a402ae0211220fd6ee93ee1364 100644
--- a/server/static/theme_retro_craft.css
+++ b/server/static/theme_retro_craft.css
@@ -132,8 +132,22 @@ p.post-truncation-action {
margin: 0;
}
div.ingest-meta {
+ align-items: center;
border-bottom: 1px solid var(--line);
- padding: 0.35rem 0.65rem;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ padding-left: 0.35rem;
+}
+span.ingest-meta-primary {
+ flex: 1 1 auto;
+ min-width: 0;
+}
+form.post-delete-form {
+ display: block;
+ flex-shrink: 0;
+ margin: 0;
+ margin-left: auto;
}
a.post-num {
color: var(--ink-dim);
Hardlinks — judgments / attempts / prompt
judgments
attempts
Prompt text is loaded only by the download route.