Skip to content

feat(teams): in-app Teams page#2561

Open
marcoambrosini wants to merge 6 commits into
masterfrom
feat/teams-spa
Open

feat(teams): in-app Teams page#2561
marcoambrosini wants to merge 6 commits into
masterfrom
feat/teams-spa

Conversation

@marcoambrosini

@marcoambrosini marcoambrosini commented Jun 26, 2026

Copy link
Copy Markdown
Member

Teams app front-end first step: mostly moved the functionality from contacts and added an overview page.
Screenshot 2026-06-26 at 20 08 13
Screenshot 2026-06-26 at 20 08 19

@marcoambrosini marcoambrosini requested a review from susnux June 26, 2026 11:25
@marcoambrosini marcoambrosini marked this pull request as draft June 26, 2026 11:30
@susnux

susnux commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

So no longer part of contacts app? Will simplify things :)

@jancborchardt jancborchardt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really really nice! :) Great first step in the right direction, and keeping it simple & contained by just porting over what we have.

@jancborchardt

jancborchardt commented Jun 27, 2026

Copy link
Copy Markdown
Member

Small details but no blocker @marcoambrosini :

  • Search input should probably go even above "Add", so that we have a common position at least in height for the in-app search functions.
  • The "Overview" icon in the nav should be filled when active?
  • The avatars of the teams in the nav seem a bit too large, there is no space towards the text

@marcoambrosini

Copy link
Copy Markdown
Member Author

@susnux could you have a look at the front-end tooling and wiring and tell me if it's sane?

@marcoambrosini

Copy link
Copy Markdown
Member Author

Search input should probably go even above "Add", so that we have a common position at least in height for the in-app search functions.

@jancborchardt then I would do it same as talk here, with the new button inline

Comment thread lib/Controller/PageController.php
Comment thread src/teams/components/TeamCard.vue Outdated
Comment thread src/teams/team-page/components/CircleDetails/CirclePasswordSettings.vue Outdated
Comment thread src/teams/team-page/components/CircleDetails/CirclePasswordSettings.vue Outdated
Comment thread src/teams/team-page/components/CircleDetails/CirclePasswordSettings.vue Outdated
Comment thread src/teams/team-page/components/CircleDetails/CircleSettings.vue Outdated
Comment thread src/teams/team-page/components/CircleDetails/CircleSettings.vue Outdated
Marco Ambrosini added 4 commits July 3, 2026 14:44
Add a PageController that renders the SPA shell, a /teams route plus a
catch-all so HTML5-history deep links survive a reload, and a Teams
entry in the app navigation.

Signed-off-by: Marco Ambrosini <marco.ambrosini@nextcloud.com>
Register src/main.ts as the 'main' Vite entry and pull in the runtime
deps the ported team-page code needs (vue-router, pinia, vuex, cdav,
virtua, cropper, MDI). Allow JS in tsconfig and skip linting the
ported src/teams/team-page sources until they are modernized.

Signed-off-by: Marco Ambrosini <marco.ambrosini@nextcloud.com>
The app shell (App, router, Pinia store) drives a home view listing
teams and a per-team page. The team page and its member/entity-picker
components, services and models are ported from the Contacts app and
kept under team-page/ (Vuex + Options API) while they are migrated.

Signed-off-by: Marco Ambrosini <marco.ambrosini@nextcloud.com>
Generate circle/team links and the dashboard widget's targets against
the new circles.Page.index route instead of the Contacts app, and drop
the now-unused route_to_circle config and IAppManager 'contacts'
checks. The widget no longer requires Contacts to be installed.

Signed-off-by: Marco Ambrosini <marco.ambrosini@nextcloud.com>
Marco Ambrosini added 2 commits July 3, 2026 14:44
Raise the max-version to 35.

Signed-off-by: Marco Ambrosini <marco.ambrosini@nextcloud.com>
Signed-off-by: Marco Ambrosini <marco.ambrosini@nextcloud.com>
@marcoambrosini marcoambrosini requested a review from susnux July 3, 2026 05:47
@jancborchardt jancborchardt linked an issue Jul 8, 2026 that may be closed by this pull request
@Koc

Koc commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

hey-hey!

Looks really promising. @marcoambrosini Will it work fine with large circles (1000+ members)? See my other PRs related to that nextcloud/collectives#2518, nextcloud/contacts#5330, so maybe you can backport some stuff from them

@marcoambrosini marcoambrosini marked this pull request as ready for review July 8, 2026 09:45
@jancborchardt jancborchardt moved this from 📐 At design to 🏗️ At engineering in 🖍 Design team Jul 8, 2026

@pringelmann pringelmann left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

If you rebase on master you'll find new testing configs for FE unit and E2E tests. If possible could you please add a few critical/happy path tests?

EDIT: tests will calcify the code too much this early in the process. Let's defer

if (team) {
router.push({ name: 'team', params: { teamId: team.id } })
}
open.value = false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found a bug here: open the dialog, hit "Cancel", then try "New team" again and nothing happens. Same after a successful create. Both close by flipping the local open ref, but the parent only unmounts on @close, which comes from onUpdateOpen and that only fires when NcDialog closes itself (Esc/backdrop/X). So createDialogOpen stays true and you can't reopen. Can we just emit close from submit and Cancel instead?

#[NoAdminRequired]
#[NoCSRFRequired]
#[FrontpageRoute(verb: 'GET', url: '/teams')]
public function index(): TemplateResponse {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dashboard widget checks frontend_enabled but this route and the nav entry don't, so Teams shows up even when the frontend is turned off. Intended?


<span :class="$style.teamCardResources">
<NcIconSvgWrapper :path="mdiFolderMultipleOutline" :size="18" inline />
{{ t('circles', '{count} resources', { count: team.resources.length }) }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be n(), otherwise a team with one resource reads "1 resources"

Comment thread src/teams/api.ts
export async function fetchTeams(): Promise<Team[]> {
const [circlesRes, dashRes] = await Promise.all([
axios.get<OcsResponse<RawCircle[]>>(generateOcsUrl('apps/circles/circles') + '?limit=-1', { headers: HEADERS }),
axios.get<OcsResponse<RawDashboardTeam[]>>(generateOcsUrl('apps/circles/teams/dashboard/widget') + '?limit=200&offset=0', { headers: HEADERS }),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the dashboard call fails but /circles succeeds, Promise.all rejects and the whole page shows the error state even though we have the team list. allSettled here and treat missing dashboard data as empty previews maybe?

@stediefan stediefan left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! I already built some UI stuff ontop - can't wait to publish after this gets merged. One further task would be to remove the corresponding code from contacts - right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: 🏗️ At engineering

Development

Successfully merging this pull request may close these issues.

Own frontend and app icon for TeamPage

6 participants