feat: browse reservations on a resource-by-time timeline - #140
Open
KinjiKawaguchi wants to merge 7 commits into
Open
KinjiKawaguchi wants to merge 7 commits into
KinjiKawaguchi wants to merge 7 commits into
Conversation
Google Calendarは1人の予定を時間軸で追うためのUIで、複数リソースの空きを 横並びで比べる用途には向かない。予約の実体はリソース×時間の二次元表なので、 リソースを縦・時間を横に取ったタイムラインをTopcoatで用意する。 閲覧専用とし、予約の作成・変更・キャンセルは既存のSlackとMCPが担う。 書き込みの経路がないため認証は設けず、ADMIN_GUIDEが既に前提としている LAN内運用に依存する。露出を抑えるため所有者はメールのローカルパートのみ表示する。 crates.io経由のライブラリ利用者にTopcoatの依存を負わせないよう、 webフィーチャの下に置いて既定では無効にする。TailwindのCSSはビルド時に生成して バイナリへ埋め込み、単一バイナリでの配布を保てるようにした。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uSBf6WpYKseYkhxDLKCLt
有効化にwebフィーチャが要ること、認証がなくLAN内運用が前提であること、 備考は表示されるので機微な内容を書かない運用が要ることを明記する。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uSBf6WpYKseYkhxDLKCLt
webフィーチャは既定で無効なため、指定がないとリリースされたバイナリから Web画面が抜け落ちる。ライブラリとしての依存は既定のままで変わらない。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uSBf6WpYKseYkhxDLKCLt
目盛りを一定時間の加算で置いていたため、夏時間の始まる日(現地の一日が23時間 しかない)を跨ぐと刻みが日付の変わり目からずれ、その日以降の見出しが消えていた。 現地の日付を軸に、各日の始まりから積む方式へ改める。 真夜中に夏時間が切り替わる地域では0時そのものが存在しない日がある。そこで 「その日で最初に存在する時刻」を日の始まりとして扱い、見出しを落とさないようにした。 表示範囲の決め方も一定時間の加算から現地日付での計算に揃えている。 あわせて表示範囲の終端を目盛りから外した。そこは範囲の終わりであって内側ではなく、 翌日の見出しを置くと表示していない日まで並んでいるように見えるため。 参照されていない TimelineBlock.id もここで落とす。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uSBf6WpYKseYkhxDLKCLt
行の高さとブロックの位置で同じ余白を別々の数値として書いていた。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uSBf6WpYKseYkhxDLKCLt
…c API The crate is published as a library, so whatever stays `pub` is part of what SemVer promises. The view and page items carry Topcoat's own types in their signatures, and Topcoat is a 0.x release that says breaking changes are to be expected — each one would have forced a major bump here for a reason that has nothing to do with this crate's own contract. Only `serve`, `serve_on` and the `query` port remain public. That is what the composition root needs, and none of them name a Topcoat type, so the framework can break without touching what this crate promises. The timing matters: widening visibility later is a minor change, narrowing it is a major one, and 1.7.0 has not shipped yet. Restricting the visibility also let the compiler point out that `TimelineRow::is_empty` was never used outside tests, so it is gone too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uSBf6WpYKseYkhxDLKCLt
The Rust API is already insulated from Topcoat, but the environment variables, the URL layout and the page itself are what operators actually depend on, and none of those are covered by the crate's public API. Saying now that they may move in a minor release keeps the option of reshaping the feature later without a major bump — and claiming stability afterwards is always available, whereas claiming instability afterwards is not. This matches how the GPU usage observer in section 5 is already labelled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uSBf6WpYKseYkhxDLKCLt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
予約の閲覧手段が Google Calendar の UI に依存している。だが予約の実体は「リソース × 時間」の二次元表であり、Calendar は「1人の予定を時間軸で追う」ための UI なので、GPU を横並びで見比べる用途に向かない。複数カレンダーを重ねると色が潰れて比較にならない。
リソースを縦軸・時間を横軸に取ったタイムラインを Web 画面として追加する。
What
閲覧専用の画面を1枚追加する。予約の作成・変更・キャンセルは既存の Slack と MCP が担い、この画面からは行わない。
?days=でも指定可、上限60日)。当日0時から始まるWEB_LISTEN_ADDR未設定なら機能無効という、MCP と同じオプトイン方式にしている。How
認証を設けていない。
docs/ADMIN_GUIDE_ja.mdが既に前提としている「同一 LAN 内、インターネットへの公開は範囲外」に依存する判断。書き込みの経路がないためリスクは情報の露出に限られる。露出を抑えるため、所有者はメールアドレスのローカルパートのみ表示する。備考はそのまま出るため、その旨をドキュメントに明記した。書き込み系を足す段になれば認証は必須になるが、Topcoat は
topcoat-session/topcoat-cookieを同梱しており、既存のMcpTokenRepositoryと同型の Web 専用トークンポートを足せば OAuth なしで済む。依存の受け渡しが唯一の設計上の難所だった。 Topcoat の
#[page]はグローバル関数で型パラメータを持てず、app_contextは Rust の型をキーに値を引く。一方ユースケースはリポジトリ実装でジェネリックなので、そのままでは画面が参照する型を書けない。interface/web側にReservationQueryを定義してトレイトオブジェクトへ均し、画面がリポジトリ実装を知らずに済むようにした。Tailwind の CSS はバイナリに埋め込んでいる。 標準構成では生成 CSS がディスク上の
dist/assetsに置かれ実行時に読まれるため、単一バイナリ配布が崩れる。build.rsが出力する$OUT_DIR/tailwind.cssをinclude_str!で<style>に直接埋めることで、cargo build --releaseだけでビルドが完結し、install.sh/ systemd unit / tar.gz の構成は変更不要になった。webフィーチャの下に置き既定では無効。crates.io 経由のライブラリ利用者に Topcoat の依存を負わせないため。配布バイナリでは有効にするのでrelease.ymlに--features webを追加した。検証
結合テストは、Topcoat の
.discover()がライブラリ側に置いた#[page]をリンク時に拾えているかの検証を兼ねている(拾えていなければ404が返る)。なお
view!マクロで条件付きのclassを書くと静的なclassを上書きしてしまい、レイアウトの土台ごと失われる挙動があった。class!マクロを使えば解決するが、再発防止に回帰テストを1件置いてある。🤖 Generated with Claude Code
https://claude.ai/code/session_016uSBf6WpYKseYkhxDLKCLt