feat(channels): tag editing on the channel detail page (R8 S1 Part 2)
Bring the same tag control to the channel page, next to Subscribe:
- backend: GET /api/channels/{id} now returns this user's `tag_ids` for the channel
(added to _channel_detail_dict + the ChannelDetail interface), matching the manager
list shape;
- ChannelPage renders the shared ChannelTagsControl, wired to attach/detach/create with
an optimistic update on the channel-detail cache (reverting on failure) and a manager
list invalidation so a tag added here shows there too.
Reuses the R8 popover platform + ChannelTagsControl — no new tag UI.
This commit is contained in:
@@ -230,6 +230,7 @@ def _channel_detail_dict(
|
||||
blocked: bool,
|
||||
stored: int,
|
||||
deep_requested: bool,
|
||||
tag_ids: list[int],
|
||||
) -> dict:
|
||||
return {
|
||||
"id": channel.id,
|
||||
@@ -257,6 +258,9 @@ def _channel_detail_dict(
|
||||
"backfill_done": channel.backfill_done,
|
||||
"from_explore": channel.from_explore,
|
||||
"details_synced": channel.details_synced_at is not None,
|
||||
# This user's personal tag links for the channel (same shape as the manager list), so the
|
||||
# channel page can offer the same tag editor next to Subscribe.
|
||||
"tag_ids": tag_ids,
|
||||
}
|
||||
|
||||
|
||||
@@ -297,6 +301,13 @@ def channel_detail(
|
||||
).first() is not None
|
||||
blocked = _is_blocked(db, user, channel_id)
|
||||
stored = db.scalar(select(func.count(Video.id)).where(Video.channel_id == channel_id)) or 0
|
||||
tag_ids = list(
|
||||
db.scalars(
|
||||
select(ChannelTag.tag_id).where(
|
||||
ChannelTag.user_id == user.id, ChannelTag.channel_id == channel_id
|
||||
)
|
||||
).all()
|
||||
)
|
||||
return _channel_detail_dict(
|
||||
channel,
|
||||
subscribed=subscribed,
|
||||
@@ -304,6 +315,7 @@ def channel_detail(
|
||||
blocked=blocked,
|
||||
stored=int(stored),
|
||||
deep_requested=bool(sub.deep_requested) if sub else False,
|
||||
tag_ids=tag_ids,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user