feat(dashboard): create a team from the switcher - #372
Conversation
The switcher's Create-team button had no behaviour. It now opens a dialog with the only field a team needs — a name — over a logo the uploader drops onto the avatar, and lands the user on the new team's overview. Buzz Team's create right belongs to System Manager while any signed-in user may start a team of their own, so the insert goes past permissions in a rate-limited endpoint; the controller still lays down the slug, the Owner membership and the team settings. The limiter buckets on `cmd`, which only /api/method sets, hence createResource rather than a v2 call. Two things the flow surfaced: the team overview watched `currentTeam`, an object rebuilt on every teams refresh, so it re-fetched for the same team and the second request aborted the first — its rejection then sat in `error` over data that had already arrived. It watches the name now, and an aborted request no longer counts as an error. The manage shell also renders while the teams load, with the wait held in the panel rather than a blank window. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
❌ UI Demo Check failedThis pull request changes the UI (7 file(s) under 🛠️ How to fix
Either one re-runs this check automatically. |
Greptile SummaryThis PR adds authenticated team creation from the dashboard switcher and routes successful creation into the newly selected team's overview. It also revises team-overview request handling and introduces reusable loading UI.
Confidence Score: 4/5The concurrent-submit defect should be fixed before merging because a repeated Enter submission can persist multiple teams for one intended creation. The backend intentionally accepts duplicate names, while the new form's submit handler allows another native form submission during an in-flight request, so both requests can insert distinct teams. Files Needing Attention: dashboard/src/components/dashboard/teams/CreateTeamDialog.vue
|
| Filename | Overview |
|---|---|
| buzz/api/teams/init.py | Exposes the authenticated POST team-creation method with a five-per-hour rate limit. |
| buzz/api/teams/services.py | Inserts a Buzz Team past DocType create permissions so its controller can seed owner membership and settings. |
| buzz/api/teams/test_teams.py | Covers ownership, switcher visibility, repeated names, and mandatory-name validation for team creation. |
| dashboard/src/components/dashboard/teams/CreateTeamDialog.vue | Implements the creation form and upload UI, but native repeated form submissions can create duplicate teams concurrently. |
| dashboard/src/data/teams.ts | Adds the create/reload/select sequence and changes overview reloading to follow the selected team name. |
| dashboard/src/components/TeamSwitcher.vue | Connects the existing create-team action to the new dialog after closing the focus-trapping popover. |
| dashboard/src/layouts/ManagerLayout.vue | Keeps the shell visible while team access loads and gates routed content behind the pending state. |
| dashboard/src/pages/manage/teams/TeamOverview.vue | Reuses the loading panel and shared filtered overview error. |
| dashboard/src/pages/manage/teams/TeamMembers.vue | Uses the shared overview error while retaining the existing members loading presentation. |
Prompt To Fix All With AI
### Issue 1
dashboard/src/components/dashboard/teams/CreateTeamDialog.vue:32-34
**Concurrent team submissions create duplicates**
When a user submits the form again while creation is in progress, `submit` starts another request because it does not guard on `createTeam.loading`, causing multiple teams to be persisted for one intended creation.
```suggestion
async function submit() {
if (createTeam.loading) return;
showErrors.value = true;
if (invalid.value) return;
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "feat(dashboard): create a team from the ..." | Re-trigger Greptile
| async function submit() { | ||
| showErrors.value = true; | ||
| if (invalid.value) return; |
There was a problem hiding this comment.
Concurrent team submissions create duplicates
When a user submits the form again while creation is in progress, submit starts another request because it does not guard on createTeam.loading, causing multiple teams to be persisted for one intended creation.
| async function submit() { | |
| showErrors.value = true; | |
| if (invalid.value) return; | |
| async function submit() { | |
| if (createTeam.loading) return; | |
| showErrors.value = true; | |
| if (invalid.value) return; |
Prompt To Fix With AI
This is a comment left during a code review.
Path: dashboard/src/components/dashboard/teams/CreateTeamDialog.vue
Line: 32-34
Comment:
**Concurrent team submissions create duplicates**
When a user submits the form again while creation is in progress, `submit` starts another request because it does not guard on `createTeam.loading`, causing multiple teams to be persisted for one intended creation.
```suggestion
async function submit() {
if (createTeam.loading) return;
showErrors.value = true;
if (invalid.value) return;
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
The Create-team button in the team switcher did nothing. It now opens a dialog:
one centred field for the name, a logo dropped onto the avatar through
FileUploader, and on success the user lands on the new team's overview withthat team already selected.
Backend —
buzz.api.teams.create_team, POST, rate limited to 5/hour. Buzz Team'screate right belongs to System Manager while any signed-in user may start a team
of their own, so the insert goes past permissions; the controller still derives
the slug and lays down the Owner membership and the team settings. No duplicate
name check — two teams may share a name, and the slug collision is handled by
append_number_if_name_exists.Two things this flow surfaced, fixed here:
useTeamOverviewwatchedcurrentTeam, an object rebuilt on every teamsrefresh, so it re-fetched for the same team; the second request aborted the
first and VueUse left that rejection in
errorafter the newer request hadalready succeeded — "signal is aborted without reason" over loaded data. It
watches the team name now, and
teamOverviewErrordropsAbortError.a
LoadingPanel(pinging Buzz mark) in the right-hand pane, reused for theteam overview's own wait.
Gotchas:
frappe.form_dict.cmd, which/api/v2never sets,so the dashboard calls this over
createResource(/api/method) like thesibling team writes. Move it to a v2
useCalland every rate-limited v2endpoint shares one bucket.
createResourcedoes not awaitonSuccess, so the team switch happens increateAndSelectTeambefore navigation rather than in a success hook.Not changed: the account tabs,
Buzz Team's doctype permissions, or the deskadd-members flow.
TeamMemberskeeps its ownLoadingText.