refactor(claude): drop the redundant Team-tab account budget (T-158)

After live review: the shared account /usage budget read as redundant on
both the Activity and Team tabs. Usage is per-account and can't be split per
member, so one place is enough — it lives only on the Activity tab, next to
the refresh control that fetches it (T-415). Removes the Team-tab account
card, its usage prop wiring, the team.section.usage/team.usage.shared i18n
keys, and the now-obsolete team_tab test. The three-tab card facelift stays.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-27 07:56:09 +02:00
co-authored by Claude Opus 4.8
parent a72906d25d
commit 3cbe0e6ec6
8 changed files with 326 additions and 151 deletions
+197
View File
@@ -6587,3 +6587,200 @@ Dropdown/select listing registered accounts + a "(default)" option. Selecting is
- The Claude pane chrome badge + welcome view T-481.
', NULL, '2026-06-25 10:24:31', '2026-06-25 10:24:31', '2026-06-25 10:24:31', NULL, 'fd3c9504dad8bae438c1df879bd5eb44', 2) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM62FKQQD0B9B80PFY4', 'description', 'Show the account/subscription usage budget (5-hour + weekly limits, % used, reset times) in the Claude meta sidebar (T-141). BLOCKED: this data is not programmatically exposed under subscription (OAuth) auth as of claude 2.1.150 — verified empirically + via docs (2026-05-23). /usage is TUI-only (headless ''claude -p /usage'' returns only a one-liner); stats-cache.json has activity counts only; the stream-json rate_limit_event is undocumented + needs a billed turn; ''claude auth status --json'' shows plan only. A ''claude usage --json'' + a /v1/organizations/{org}/usage/subscription endpoint are an OPEN, unshipped feature request (GitHub anthropics/claude-code#44328). Revisit when #44328 ships or an API-key usage path exists. See project memory ''claude-usage-budget-not-exposed''.
2026-06-09: detached from T-132 (which is otherwise complete) and made the RESOLVER ticket for Q-34 (how + when to surface the budget given upstream doesn''t expose it). Stays in the backlog; revisit when a viable data path lands (upstream claude usage --json / endpoint per anthropics/claude-code#44328, or an API-key usage path).
UNBLOCKED (2026-06-12, T-415): probed claude 2.1.175 a forwarded /usage IS
answered headless in stream-json (free, num_turns 0) with parseable text
(session %, week % all-models, week % Sonnet). The Activity tab now renders it
via parseUsageText + a user-initiated refresh control. Remaining scope for this
ticket would be per-member/team budget split, if still wanted.
REFINED 2026-06-26
## Grounding (current state)
- T-415 SHIPPED the account-budget display. `/usage` is forwarded headless
(free, num_turns 0), parsed by `parseUsageText` `ClaudeUsage` (session %,
week all-models %, week Sonnet %) in
lib/builtin/claude/src/claude_status.dart, rendered in the Activity tab
(meta_sidebar/activity_tab.dart, USAGE `MetaSection`) with a user-initiated
refresh that publishes `/usage` on the `builtin.claude/command` channel.
claude_meta_sidebar.dart binds the PRIMARY session''s synthetic text items and
parses them into `_usage`.
## KEY FINDING a literal "per-member split" is not meaningful today
- Claude''s usage budget is per-ACCOUNT (subscription/OAuth), not per-session.
Every clide session in a workspace (primary, secondaries, managed teammates)
spawns against the SAME `~/.claude` login session_orchestrator spawns with
no per-session CLAUDE_* auth override and all transcripts live under one
project dir. So the whole team draws down ONE shared 5h/weekly budget.
- Rendering the same numbers on each roster row would mislead, not inform. True
per-member budgets need per-SESSION account login, which even T-476 (per-REPO
login) does NOT provide within one workspace/team the account is shared.
Treat per-member-different-account as out of scope unless per-session
multi-account auth ever exists.
## RECOMMENDED SCOPE (shippable, honest) resolves Q-34
Surface the existing account-wide budget in the TEAM tab as a single "Account"
section (NOT per-member): the team sidebar then answers "how much budget is left
for the account the whole team shares." Satisfies the ticket title without the
false split.
Implementation:
1. meta_sidebar/team_tab.dart (TeamTabView.build): add a `MetaSection`
(header i18n key `team.section.usage`) rendering the same 3 `MetaRow`s the
Activity tab uses (session / week-all / week-sonnet), shown only when usage
!= null, with a one-line caption that it is account-wide / shared across the
team (so it isn''t read as per-member).
2. claude_meta_sidebar.dart: pass the existing `_usage` (ClaudeUsage?) into
TeamTabView (it already passes `members`). No new fetch the primary''s
`/usage` already IS the account budget.
3. Optional: a refresh control in the team section mirroring the Activity tab
(publish `/usage` on `builtin.claude/command`), or just rely on the Activity
tab''s refresh keeping `_usage` current.
Files to touch: meta_sidebar/team_tab.dart, claude_meta_sidebar.dart (thread
usage), meta_sidebar/models.dart (reuse MetaSection/MetaRow),
assets/i18n/en_us + nl_nl/builtin.claude.json (new `team.section.usage` [+
caption] key keep en/nl parity for the a11y i18n gate).
## ALTERNATIVE PATHS (pick one before building)
A. Shared-account section in the team tab (recommended above).
B. Close T-158 as substantially DONE by T-415 the budget is already visible in
the Activity tab; a team-tab duplicate may be redundant. Q-34 answered either
way.
C. Keep the true per-member split as a FUTURE item, explicitly blocked on a
(currently non-existent) per-session multi-account login; park T-158 behind
it.
## ACCEPTANCE (for option A)
- Team tab shows ONE account-budget section (session / week / week-sonnet %)
when a `/usage` result is available, clearly labelled account-wide / shared.
- No per-member duplication of the same numbers.
- No new network/headless call beyond the existing user-initiated `/usage`
refresh (D-64 / POLICY: explicit user action only).
- en/nl parity for any new i18n keys.
## REFERENCES
T-415 (usage parse + Activity render); Q-34 (this resolves it); T-476 (per-REPO,
not per-session, account login does NOT enable per-member budgets);
`parseUsageText` / `ClaudeUsage` (claude_status.dart); activity_tab.dart USAGE
block; team_tab.dart roster; claude_meta_sidebar.dart usage binding.
DECISION 2026-06-26: go with option A.
Build the single shared-account budget section in the TEAM tab (account-wide,
clearly labelled NOT per-member). Options B (close as done-by-T-415) and C
(per-member, deferred behind per-session multi-account) are declined: per-member
is not meaningful under one shared account, and the team tab should carry its
own budget view rather than send the user to the Activity tab.
Scope is now exactly the "RECOMMENDED SCOPE" above (team_tab.dart MetaSection +
thread _usage from claude_meta_sidebar.dart + team.section.usage i18n key,
en/nl). This resolves Q-34. Ready to pick up; not yet started.', 'Show the account/subscription usage budget (5-hour + weekly limits, % used, reset times) in the Claude meta sidebar (T-141). BLOCKED: this data is not programmatically exposed under subscription (OAuth) auth as of claude 2.1.150 verified empirically + via docs (2026-05-23). /usage is TUI-only (headless ''claude -p /usage'' returns only a one-liner); stats-cache.json has activity counts only; the stream-json rate_limit_event is undocumented + needs a billed turn; ''claude auth status --json'' shows plan only. A ''claude usage --json'' + a /v1/organizations/{org}/usage/subscription endpoint are an OPEN, unshipped feature request (GitHub anthropics/claude-code#44328). Revisit when #44328 ships or an API-key usage path exists. See project memory ''claude-usage-budget-not-exposed''.
2026-06-09: detached from T-132 (which is otherwise complete) and made the RESOLVER ticket for Q-34 (how + when to surface the budget given upstream doesn''t expose it). Stays in the backlog; revisit when a viable data path lands (upstream claude usage --json / endpoint per anthropics/claude-code#44328, or an API-key usage path).
UNBLOCKED (2026-06-12, T-415): probed claude 2.1.175 a forwarded /usage IS
answered headless in stream-json (free, num_turns 0) with parseable text
(session %, week % all-models, week % Sonnet). The Activity tab now renders it
via parseUsageText + a user-initiated refresh control. Remaining scope for this
ticket would be per-member/team budget split, if still wanted.
REFINED 2026-06-26
## Grounding (current state)
- T-415 SHIPPED the account-budget display. `/usage` is forwarded headless
(free, num_turns 0), parsed by `parseUsageText` `ClaudeUsage` (session %,
week all-models %, week Sonnet %) in
lib/builtin/claude/src/claude_status.dart, rendered in the Activity tab
(meta_sidebar/activity_tab.dart, USAGE `MetaSection`) with a user-initiated
refresh that publishes `/usage` on the `builtin.claude/command` channel.
claude_meta_sidebar.dart binds the PRIMARY session''s synthetic text items and
parses them into `_usage`.
## KEY FINDING a literal "per-member split" is not meaningful today
- Claude''s usage budget is per-ACCOUNT (subscription/OAuth), not per-session.
Every clide session in a workspace (primary, secondaries, managed teammates)
spawns against the SAME `~/.claude` login session_orchestrator spawns with
no per-session CLAUDE_* auth override and all transcripts live under one
project dir. So the whole team draws down ONE shared 5h/weekly budget.
- Rendering the same numbers on each roster row would mislead, not inform. True
per-member budgets need per-SESSION account login, which even T-476 (per-REPO
login) does NOT provide within one workspace/team the account is shared.
Treat per-member-different-account as out of scope unless per-session
multi-account auth ever exists.
## RECOMMENDED SCOPE (shippable, honest) resolves Q-34
Surface the existing account-wide budget in the TEAM tab as a single "Account"
section (NOT per-member): the team sidebar then answers "how much budget is left
for the account the whole team shares." Satisfies the ticket title without the
false split.
Implementation:
1. meta_sidebar/team_tab.dart (TeamTabView.build): add a `MetaSection`
(header i18n key `team.section.usage`) rendering the same 3 `MetaRow`s the
Activity tab uses (session / week-all / week-sonnet), shown only when usage
!= null, with a one-line caption that it is account-wide / shared across the
team (so it isn''t read as per-member).
2. claude_meta_sidebar.dart: pass the existing `_usage` (ClaudeUsage?) into
TeamTabView (it already passes `members`). No new fetch the primary''s
`/usage` already IS the account budget.
3. Optional: a refresh control in the team section mirroring the Activity tab
(publish `/usage` on `builtin.claude/command`), or just rely on the Activity
tab''s refresh keeping `_usage` current.
Files to touch: meta_sidebar/team_tab.dart, claude_meta_sidebar.dart (thread
usage), meta_sidebar/models.dart (reuse MetaSection/MetaRow),
assets/i18n/en_us + nl_nl/builtin.claude.json (new `team.section.usage` [+
caption] key keep en/nl parity for the a11y i18n gate).
## ALTERNATIVE PATHS (pick one before building)
A. Shared-account section in the team tab (recommended above).
B. Close T-158 as substantially DONE by T-415 the budget is already visible in
the Activity tab; a team-tab duplicate may be redundant. Q-34 answered either
way.
C. Keep the true per-member split as a FUTURE item, explicitly blocked on a
(currently non-existent) per-session multi-account login; park T-158 behind
it.
## ACCEPTANCE (for option A)
- Team tab shows ONE account-budget section (session / week / week-sonnet %)
when a `/usage` result is available, clearly labelled account-wide / shared.
- No per-member duplication of the same numbers.
- No new network/headless call beyond the existing user-initiated `/usage`
refresh (D-64 / POLICY: explicit user action only).
- en/nl parity for any new i18n keys.
## REFERENCES
T-415 (usage parse + Activity render); Q-34 (this resolves it); T-476 (per-REPO,
not per-session, account login does NOT enable per-member budgets);
`parseUsageText` / `ClaudeUsage` (claude_status.dart); activity_tab.dart USAGE
block; team_tab.dart roster; claude_meta_sidebar.dart usage binding.
DECISION 2026-06-26: go with option A.
Build the single shared-account budget section in the TEAM tab (account-wide,
clearly labelled NOT per-member). Options B (close as done-by-T-415) and C
(per-member, deferred behind per-session multi-account) are declined: per-member
is not meaningful under one shared account, and the team tab should carry its
own budget view rather than send the user to the Activity tab.
Scope is now exactly the "RECOMMENDED SCOPE" above (team_tab.dart MetaSection +
thread _usage from claude_meta_sidebar.dart + team.section.usage i18n key,
en/nl). This resolves Q-34. Ready to pick up; not yet started.
REVISED 2026-06-27 (after live review): pivoted A B.
Seeing the shared-account card on BOTH the Activity and Team tabs read as
redundant usage is per-account and can''t be split per member, so one place
is enough. Removed the Team-tab account card (and its usage prop + i18n keys);
the budget now lives only on the Activity tab, next to the /usage refresh
control that fetches it (T-415). The three-tab card facelift stays. Q-34
answered: budget surfaces once, on Activity.', NULL, '2026-06-27 05:55:56', '2026-06-27 05:55:56.468', '2026-06-27 05:55:56.468', NULL, 'ba7329e54bf44c2cb5a9e7fb63e685f3', 2) ON CONFLICT(hash) DO NOTHING;
+104
View File
@@ -8332,3 +8332,107 @@ Dropdown/select listing registered accounts + a "(default)" option. Selecting is
- The Claude pane chrome badge + welcome view T-481.
', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-25 09:16:42', '2026-06-25 10:24:31', NULL, 'a699defe53d009c44e5af7f9f38a0c15', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM62FKQQD0B9B80PFY4', 'task', NULL, 'Team sidebar: account/team token budget (blocked on upstream)', 'Show the account/subscription usage budget (5-hour + weekly limits, % used, reset times) in the Claude meta sidebar (T-141). BLOCKED: this data is not programmatically exposed under subscription (OAuth) auth as of claude 2.1.150 — verified empirically + via docs (2026-05-23). /usage is TUI-only (headless ''claude -p /usage'' returns only a one-liner); stats-cache.json has activity counts only; the stream-json rate_limit_event is undocumented + needs a billed turn; ''claude auth status --json'' shows plan only. A ''claude usage --json'' + a /v1/organizations/{org}/usage/subscription endpoint are an OPEN, unshipped feature request (GitHub anthropics/claude-code#44328). Revisit when #44328 ships or an API-key usage path exists. See project memory ''claude-usage-budget-not-exposed''.
2026-06-09: detached from T-132 (which is otherwise complete) and made the RESOLVER ticket for Q-34 (how + when to surface the budget given upstream doesn''t expose it). Stays in the backlog; revisit when a viable data path lands (upstream claude usage --json / endpoint per anthropics/claude-code#44328, or an API-key usage path).
UNBLOCKED (2026-06-12, T-415): probed claude 2.1.175 a forwarded /usage IS
answered headless in stream-json (free, num_turns 0) with parseable text
(session %, week % all-models, week % Sonnet). The Activity tab now renders it
via parseUsageText + a user-initiated refresh control. Remaining scope for this
ticket would be per-member/team budget split, if still wanted.
REFINED 2026-06-26
## Grounding (current state)
- T-415 SHIPPED the account-budget display. `/usage` is forwarded headless
(free, num_turns 0), parsed by `parseUsageText` `ClaudeUsage` (session %,
week all-models %, week Sonnet %) in
lib/builtin/claude/src/claude_status.dart, rendered in the Activity tab
(meta_sidebar/activity_tab.dart, USAGE `MetaSection`) with a user-initiated
refresh that publishes `/usage` on the `builtin.claude/command` channel.
claude_meta_sidebar.dart binds the PRIMARY session''s synthetic text items and
parses them into `_usage`.
## KEY FINDING a literal "per-member split" is not meaningful today
- Claude''s usage budget is per-ACCOUNT (subscription/OAuth), not per-session.
Every clide session in a workspace (primary, secondaries, managed teammates)
spawns against the SAME `~/.claude` login session_orchestrator spawns with
no per-session CLAUDE_* auth override and all transcripts live under one
project dir. So the whole team draws down ONE shared 5h/weekly budget.
- Rendering the same numbers on each roster row would mislead, not inform. True
per-member budgets need per-SESSION account login, which even T-476 (per-REPO
login) does NOT provide within one workspace/team the account is shared.
Treat per-member-different-account as out of scope unless per-session
multi-account auth ever exists.
## RECOMMENDED SCOPE (shippable, honest) resolves Q-34
Surface the existing account-wide budget in the TEAM tab as a single "Account"
section (NOT per-member): the team sidebar then answers "how much budget is left
for the account the whole team shares." Satisfies the ticket title without the
false split.
Implementation:
1. meta_sidebar/team_tab.dart (TeamTabView.build): add a `MetaSection`
(header i18n key `team.section.usage`) rendering the same 3 `MetaRow`s the
Activity tab uses (session / week-all / week-sonnet), shown only when usage
!= null, with a one-line caption that it is account-wide / shared across the
team (so it isn''t read as per-member).
2. claude_meta_sidebar.dart: pass the existing `_usage` (ClaudeUsage?) into
TeamTabView (it already passes `members`). No new fetch the primary''s
`/usage` already IS the account budget.
3. Optional: a refresh control in the team section mirroring the Activity tab
(publish `/usage` on `builtin.claude/command`), or just rely on the Activity
tab''s refresh keeping `_usage` current.
Files to touch: meta_sidebar/team_tab.dart, claude_meta_sidebar.dart (thread
usage), meta_sidebar/models.dart (reuse MetaSection/MetaRow),
assets/i18n/en_us + nl_nl/builtin.claude.json (new `team.section.usage` [+
caption] key keep en/nl parity for the a11y i18n gate).
## ALTERNATIVE PATHS (pick one before building)
A. Shared-account section in the team tab (recommended above).
B. Close T-158 as substantially DONE by T-415 the budget is already visible in
the Activity tab; a team-tab duplicate may be redundant. Q-34 answered either
way.
C. Keep the true per-member split as a FUTURE item, explicitly blocked on a
(currently non-existent) per-session multi-account login; park T-158 behind
it.
## ACCEPTANCE (for option A)
- Team tab shows ONE account-budget section (session / week / week-sonnet %)
when a `/usage` result is available, clearly labelled account-wide / shared.
- No per-member duplication of the same numbers.
- No new network/headless call beyond the existing user-initiated `/usage`
refresh (D-64 / POLICY: explicit user action only).
- en/nl parity for any new i18n keys.
## REFERENCES
T-415 (usage parse + Activity render); Q-34 (this resolves it); T-476 (per-REPO,
not per-session, account login does NOT enable per-member budgets);
`parseUsageText` / `ClaudeUsage` (claude_status.dart); activity_tab.dart USAGE
block; team_tab.dart roster; claude_meta_sidebar.dart usage binding.
DECISION 2026-06-26: go with option A.
Build the single shared-account budget section in the TEAM tab (account-wide,
clearly labelled NOT per-member). Options B (close as done-by-T-415) and C
(per-member, deferred behind per-session multi-account) are declined: per-member
is not meaningful under one shared account, and the team tab should carry its
own budget view rather than send the user to the Activity tab.
Scope is now exactly the "RECOMMENDED SCOPE" above (team_tab.dart MetaSection +
thread _usage from claude_meta_sidebar.dart + team.section.usage i18n key,
en/nl). This resolves Q-34. Ready to pick up; not yet started.
REVISED 2026-06-27 (after live review): pivoted A B.
Seeing the shared-account card on BOTH the Activity and Team tabs read as
redundant usage is per-account and can''t be split per member, so one place
is enough. Removed the Team-tab account card (and its usage prop + i18n keys);
the budget now lives only on the Activity tab, next to the /usage refresh
control that fetches it (T-415). The three-tab card facelift stays. Q-34
answered: budget surfaces once, on Activity.', 'done', 'low', NULL, NULL, NULL, '2026-05-23 20:48:38', '2026-06-27 05:55:56.468', NULL, 'c69aaa48a145eccdaed208eb01ab8a57', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
-3
View File
@@ -22,9 +22,6 @@ heading, and (b) bumping `pubspec.yaml` `version:` in the same commit.
fleshed out to full token + syntax coverage and ships alongside a
contrast-hardened `summer-night-hc`, both selectable in Settings → Appearance.
(T-478)
- **Account budget in the Team tab.** The Claude meta sidebar's Team tab now
shows the shared account `/usage` budget as a single labelled card (usage is
per-account, not per-member). (T-158)
### Changed
-2
View File
@@ -194,8 +194,6 @@
"taskRow.reassign": { "translation": "Reassign task" },
"team.empty": { "translation": "No team active." },
"team.section.tasks": { "translation": "TASKS" },
"team.section.usage": { "translation": "Account" },
"team.usage.shared": { "translation": "Shared across the team" },
"tabStrip.activity": { "translation": "Activity" },
"tabStrip.team": { "translation": "Team" },
"tabStrip.team.count": { "translation": "Team · {count}" },
-2
View File
@@ -194,8 +194,6 @@
"taskRow.reassign": { "translation": "Taak opnieuw toewijzen" },
"team.empty": { "translation": "Geen team actief." },
"team.section.tasks": { "translation": "TAKEN" },
"team.section.usage": { "translation": "Account" },
"team.usage.shared": { "translation": "Gedeeld met het hele team" },
"tabStrip.activity": { "translation": "Activiteit" },
"tabStrip.team": { "translation": "Team" },
"tabStrip.team.count": { "translation": "Team · {count}" },
@@ -19,10 +19,10 @@
/// `meta_sidebar/` (T-395 split). Activity and Config render on the same
/// table geometry (`buildMetaTable`) so switching tabs doesn't visually jump.
///
/// The account budget now surfaces from a forwarded `/usage` (T-415): the
/// Activity tab renders it, and the Team tab repeats it as a single shared
/// ACCOUNT card (T-158) — usage is per-account (one `~/.claude` login), so it's
/// shown once, not split per member.
/// The account budget surfaces from a forwarded `/usage` (T-415): the Activity
/// tab renders it next to its refresh control. It is NOT duplicated on the Team
/// tab — usage is per-account (one `~/.claude` login), so it can't be split per
/// member; one place to see it is enough (T-158).
library;
import 'dart:async';
@@ -313,7 +313,6 @@ class _ClaudeMetaSidebarState extends State<ClaudeMetaSidebar> {
members: _members,
memberStatus: _memberStatus,
orchestrator: _orchestrator,
usage: _usage,
tasks: _tasks,
injectingAgentId: _injectingAgentId,
injectController: _injectCtl,
@@ -4,12 +4,12 @@
/// state, and orchestrator wiring. Split out of claude_meta_sidebar.dart
/// (T-395).
///
/// Also carries the shared account budget (T-158): the `/usage` figures are
/// per-ACCOUNT — every team session shares one `~/.claude` login, so this is a
/// single shared budget shown once and labelled as such, NOT a per-member split.
/// The account `/usage` budget is deliberately NOT shown here: it is
/// per-account (every team session shares one `~/.claude` login), so it can't
/// be split per member — it lives once on the Activity tab, next to the
/// refresh control that fetches it (T-158).
library;
import 'package:clide/builtin/claude/src/claude_status.dart' show ClaudeUsage;
import 'package:clide/builtin/claude/src/meta_sidebar/models.dart';
import 'package:clide/builtin/claude/src/meta_sidebar/roster_row.dart';
import 'package:clide/builtin/claude/src/meta_sidebar/task_row.dart';
@@ -36,7 +36,6 @@ class TeamTabView extends StatelessWidget {
required this.onSetPermissionMode,
required this.onFork,
required this.onOpenChatPane,
this.usage,
});
final List<TeamMemberJoined> members;
@@ -52,18 +51,13 @@ class TeamTabView extends StatelessWidget {
final void Function(String memberName) onFork;
final VoidCallback onOpenChatPane;
/// Parsed `/usage` budget for the account this team shares (T-158). Null until
/// the first `/usage` refresh (driven from the Activity tab control).
final ClaudeUsage? usage;
@override
Widget build(BuildContext context) {
final tokens = ClideSettings.theme.of(context).surface;
if (members.isEmpty) {
return metaPlaceholder(ClideSettings.i18n.string(context, 'team.empty', namespace: 'builtin.claude', placeholder: 'No team active.'));
}
final children = <Widget>[
..._accountSection(context, tokens),
if (members.isEmpty)
metaPlaceholder(ClideSettings.i18n.string(context, 'team.empty', namespace: 'builtin.claude', placeholder: 'No team active.'))
else
for (final m in members)
AgentRosterRow(
key: ValueKey(m.agentId),
@@ -96,43 +90,6 @@ class TeamTabView extends StatelessWidget {
return ListView(padding: const EdgeInsets.all(12), children: children);
}
/// The shared account-budget card (T-158): one ACCOUNT section with the three
/// `/usage` figures and a caption that it is account-wide, not per-member.
/// Empty when no `/usage` result has arrived yet.
List<Widget> _accountSection(BuildContext context, SurfaceTokens tokens) {
final u = usage;
if (u == null || (u.session == null && u.week == null && u.weekSonnet == null)) return const [];
return [
metaSectionHeader(context, tokens, ClideSettings.i18n.string(context, 'team.section.usage', namespace: 'builtin.claude', placeholder: 'ACCOUNT')),
metaCard(tokens, [
if (u.session != null)
metaCardRow(
tokens,
MetaRow(ClideSettings.i18n.string(context, 'activity.row.session', namespace: 'builtin.claude', placeholder: 'session'), u.session!),
),
if (u.week != null)
metaCardRow(
tokens,
MetaRow(ClideSettings.i18n.string(context, 'activity.row.weekAll', namespace: 'builtin.claude', placeholder: 'week (all)'), u.week!),
),
if (u.weekSonnet != null)
metaCardRow(
tokens,
MetaRow(ClideSettings.i18n.string(context, 'activity.row.weekSonnet', namespace: 'builtin.claude', placeholder: 'week (sonnet)'), u.weekSonnet!),
),
]),
Padding(
padding: const EdgeInsets.only(left: 2, top: 4),
child: ClideText(
ClideSettings.i18n.string(context, 'team.usage.shared', namespace: 'builtin.claude', placeholder: 'Shared across the team'),
muted: true,
fontSize: clideFontCaption,
),
),
const SizedBox(height: 16),
];
}
Widget _taskSection(BuildContext context, SurfaceTokens tokens) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
-75
View File
@@ -1,75 +0,0 @@
/// T-158: the Team tab carries the shared account budget — a single ACCOUNT
/// card from the forwarded `/usage`, NOT a per-member split (usage is
/// per-account: every team session shares one ~/.claude login).
library;
import 'package:clide/builtin/claude/src/claude_status.dart' show ClaudeUsage;
import 'package:clide/builtin/claude/src/meta_sidebar/team_tab.dart';
import 'package:clide/widgets/widgets.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../helpers/kernel_fixture.dart';
import '../../helpers/widget_harness.dart';
void main() {
late KernelFixture f;
late TextEditingController inject;
setUp(() async {
f = await KernelFixture.create();
inject = TextEditingController();
});
tearDown(() {
inject.dispose();
f.dispose();
});
// No team members + no catalog seeded, so labels fall back to their English
// placeholders ('ACCOUNT' is the uppercased section header).
TeamTabView view({ClaudeUsage? usage}) => TeamTabView(
members: const [],
memberStatus: const {},
orchestrator: null,
tasks: const [],
injectingAgentId: null,
injectController: inject,
onToggleInject: (_) {},
onInjectSubmit: (_, _) {},
onClose: (_) {},
onSetPermissionMode: (_, _) {},
onFork: (_) {},
onOpenChatPane: () {},
usage: usage,
);
testWidgets('renders the shared ACCOUNT budget card when usage is present', (tester) async {
await tester.pumpWidget(harness(f, view(usage: const ClaudeUsage(session: '15% used', week: '53% used', weekSonnet: '0% used'))));
await tester.pump();
expect(find.text('ACCOUNT'), findsOneWidget);
expect(find.text('15% used'), findsOneWidget);
expect(find.text('53% used'), findsOneWidget);
expect(find.text('0% used'), findsOneWidget);
// Labelled shared, not per-member.
expect(find.text('Shared across the team'), findsOneWidget);
// Solo (no members) still shows the budget above the empty-team notice.
expect(find.text('No team active.'), findsOneWidget);
});
testWidgets('omits the ACCOUNT card when no usage has been fetched', (tester) async {
await tester.pumpWidget(harness(f, view()));
await tester.pump();
expect(find.text('ACCOUNT'), findsNothing);
expect(find.text('Shared across the team'), findsNothing);
expect(find.text('No team active.'), findsOneWidget);
});
testWidgets('omits the ACCOUNT card when the usage result is empty', (tester) async {
await tester.pumpWidget(harness(f, view(usage: const ClaudeUsage())));
await tester.pump();
expect(find.text('ACCOUNT'), findsNothing);
});
}