Skip to content

Release: v0.1.0#137

Open
github-actions[bot] wants to merge 23 commits into
mainfrom
develop
Open

Release: v0.1.0#137
github-actions[bot] wants to merge 23 commits into
mainfrom
develop

Conversation

@github-actions

Copy link
Copy Markdown

Improvements

Technical

themightychris and others added 2 commits June 26, 2026 11:19
The horizontal logo sat at h-8 (32px) in the h-14 (56px) bar, leaving ~12px of
dead space above/below. Bump to h-12 (48px) so it fills ~86% of the bar height
with a 4px gap top and bottom — a fuller, more present lockup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(web): enlarge header logo to fill the navbar
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Author

Changelog

- fix(web): enlarge header logo to fill the navbar [#136] @themightychris
- feat(web): add Join/Leave project buttons (#113) [#138] @themightychris
- feat(web): self "Manage account" link on PersonDetail (#113) [#139] @themightychris
- feat(web): ProjectDetail soft-delete banner for staff (#113) [#140] @themightychris
- feat(blog): excerpt fallback + tag chips (#113) [#141] @themightychris
- feat(web): ProjectDetail "More ▾" actions dropdown (#113) [#142] @themightychris
- feat(import): import legacy person avatars (#130) [#143] @themightychris
- feat(person): deactivate / reactivate / purge (#129) [#144] @themightychris
- chore(deps): bump gitsheets to 1.4.1 (TOML parser memory fix, #132) [#145] @themightychris

themightychris and others added 21 commits June 26, 2026 13:21
ProjectDetail declared "Join Project" / "Leave project" actions in the spec
(project-detail.md) and the API endpoints existed, but the SPA never rendered
the buttons. Add them to the sidebar:

- Join Project — signed-in users who aren't members (POST .../members/join)
- Leave project — members, except a sole maintainer who must transfer the
  role first (POST .../members/leave); shows an explanatory hint instead.

Membership is computed client-side from the members list + the signed-in user
(the project response carries no per-viewer flag). Added api client join/leave
methods and ProjectDetail tests for both states.

First slice of the #113 UI-gaps umbrella. The soft-delete banner (the other
half of the ProjectDetail pairing) is deferred — it needs the project response
to expose `deletedAt`, a small API/serializer change tracked under #113.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eave

feat(web): add Join/Leave project buttons (#113)
person-detail.md's sidebar declares a self-only "Manage account" link to
/account; the SPA didn't render it. Add it to the sidebar, gated on the viewer
being the profile owner (useAuth slug match). Tests cover self (link present,
href=/account) and anonymous (absent).

Note: the other two items in this #113 batch were already implemented since the
2026-05-30 audit — PeopleIndex's sort dropdown (PeopleIndex.tsx) and
HelpWantedIndex's "Post a role" button — so they need no change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(web): self "Manage account" link on PersonDetail (#113)
project-detail.md declares a staff-only banner across the top of a soft-deleted
project with a Restore action; the SPA never rendered it because the project
response didn't carry deletedAt.

- Expose `deletedAt` on the project detail response (serializer + spec
  api/projects.md). Null for active projects; non-null only when staff fetch a
  soft-deleted one (non-staff get 404).
- Render the yellow banner with a Restore button (reuses the existing action
  runner + project refetch). Gated on deletedAt + staff accountLevel.
- Tests: banner shows for staff + deleted, absent for active.

The "More ▼" header dropdown (the other half of this ProjectDetail pairing in
#113) is a separate follow-up — it's a pure UI refactor with no API dependency.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-more

feat(web): ProjectDetail soft-delete banner for staff (#113)
Two blog UI gaps from the spec-drift audit:

- BlogIndex (blog-index.md): when `summary` is null, fall back to the first
  paragraph of `bodyHtml` truncated to ~280 chars (plain-text, derived
  client-side from the already-sanitized HTML).
- BlogDetail (blog-detail.md): render the post's tags as chips in the footer
  linking to `/blog?tag=<handle>`. The blog response didn't carry tags, so the
  serializer now resolves them (tag-assignments where taggableType=blog_post)
  and includes a `tags` field (spec api/blog.md updated). Web type + UI added.

Tests: BlogIndex excerpt fallback; BlogDetail chips present/absent; API blog
suite still green (tags in response).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per project-detail.md, the header keeps "Edit Project" as the primary button
and moves the secondary actions into a "More ▾" dropdown: Add Member, Log Buzz,
Post Update, Post Help-Wanted Role, Manage Members, and (admin) Delete Project
behind a confirm dialog. The previously-contextual section buttons (Post Update,
Log Buzz, Post new role) are removed now that they live in the header dropdown —
single source per the spec.

Delete soft-deletes via the existing endpoint and refetches, so the soft-delete
banner (from the prior PR) appears for staff immediately. Tests: dropdown
trigger present for management perms, absent for anonymous.

Completes the #113 UI-gaps umbrella.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(blog): excerpt fallback + tag chips (#113)
…ropdown

feat(web): ProjectDetail "More ▾" actions dropdown (#113)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Legacy users showed initials where their codeforphilly.org photo used to be —
the importer brought blog media but never person avatars. A spike found the
source: person.PrimaryPhotoID → GET /media/<id>. (Projects have no image field
in laddr, so this is avatars only.)

RawPersonSchema now parses PrimaryPhotoID. For each person with one, the
importer fetches /media/<id>, runs it through the existing processAvatar
(square original + 128px thumb), stores both as gitsheets attachments
(avatar.jpg + avatar-128.jpg), and sets avatarKey — the same convention as the
avatar-upload route. Reuses the blog-media machinery (fetchMediaBytes +
BlobObject.write + setAttachments), concurrency 4, failures non-fatal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two removal verbs: deactivate (soft, self-service, reversible, login not
blocked, "Deactivated user" placeholder on references) and purge (admin-only
cascading hard delete, git-revertable). Authz + endpoints + placeholder shape.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- API: POST /api/people/:slug/{deactivate,reactivate} (self | staff) and
  /purge (administrator), via the write mutex.
- Read: people.get returns a deactivated person only to staff or self (for
  reactivation); lists exclude deactivated for non-staff; serializePersonAvatar
  (+ author/member serializers) emits a "Deactivated user" placeholder.
- Purge cascades: person + memberships + help-wanted-interest + person
  tag-assignments + authored updates/buzz/blog-posts, in one commit.
- Web: /account self deactivate/reactivate; admin Danger Zone; placeholder
  rendering.

Implements specs/behaviors/person-lifecycle.md + api/people.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
API guard + cascade tests (14) and web tests for self-deactivate and the
deactivated-reference placeholder. Fixes the draft test's mintCookies helper,
which ignored its level arg so staff/admin callers authenticated as plain users
(spurious 403s).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(import): import legacy person avatars (#130)
feat(person): deactivate / reactivate / purge (#129)
Command:
  npm install gitsheets@^1.4.1 -w apps/api

Picks up gitsheets 1.4.1, which switches the TOML record parser from
@iarna/toml to smol-toml (JarvusInnovations/gitsheets#197). This fixes
the #132 boot-heap blowup at its root: @iarna's parser pinned ~12x each
record's source in V8 sliced/cons-strings.

Measured end-to-end against the full `published` import via the boot
path:
  retained heap     581 MB -> 88 MB  (6.6x)
  transient peak    532 MB -> 71 MB  (7.5x)
  rss               806 MB -> 292 MB

type-check + lint clean; api 412/412 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chore(deps): bump gitsheets to 1.4.1 (TOML parser memory fix, #132)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant