Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions core/src/types/teams.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

export interface TeamFolder {
id: number
mountPoint: string
quota: number | null
}

export interface SharedResourceProvider {
id: string
name: string
}

export interface SharedResource {
id: string | number
label: string
url: string
iconSvg?: string
iconURL?: string
iconEmoji?: string
provider: SharedResourceProvider
}

export interface TeamAppAction {
id: string
label: string
icon?: string
prompt?: { title: string, value?: string }
confirm?: { title: string, message: string }
resourcePicker?: TeamAppResourcePickerOptions
}

export interface TeamAppEntry {
id: string
label: string
icon?: string
iconSvg?: string
iconEmoji?: string
href?: string
legacyIds?: string[]
actions?: TeamAppAction[]
viewData?: Record<string, unknown>
}

export interface TeamAppNavigation {
entries: TeamAppEntry[]
actions?: TeamAppAction[]
resourceKeys?: Array<{ providerId: string, resourceId: string }>
}

export interface TeamAppActionResult {
navigationEntryIds?: string[]
open?: string
}

export interface TeamAppResource extends Pick<TeamAppEntry, 'id' | 'label' | 'icon' | 'iconSvg' | 'iconEmoji'> {
description?: string
}

export interface TeamAppResourcePickerOptions {
title: string
resources: TeamAppResource[]
selectedIds?: string[]
}

export interface TeamAppContext {
teamId: string
signal: AbortSignal
}

export interface TeamAppView {
mount: (element: HTMLElement, context: TeamAppContext, entry: TeamAppEntry) => Promise<() => void>
}
11 changes: 11 additions & 0 deletions lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -1074,10 +1074,21 @@
'OCP\\TaskProcessing\\TaskTypes\\TextToTextSummary' => $baseDir . '/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php',
'OCP\\TaskProcessing\\TaskTypes\\TextToTextTopics' => $baseDir . '/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php',
'OCP\\TaskProcessing\\TaskTypes\\TextToTextTranslate' => $baseDir . '/lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php',
'OCP\\Teams\\ITeamAppProvider' => $baseDir . '/lib/public/Teams/ITeamAppProvider.php',
'OCP\\Teams\\ITeamFolderProvider' => $baseDir . '/lib/public/Teams/ITeamFolderProvider.php',
'OCP\\Teams\\ITeamManager' => $baseDir . '/lib/public/Teams/ITeamManager.php',
'OCP\\Teams\\ITeamResourceProvider' => $baseDir . '/lib/public/Teams/ITeamResourceProvider.php',
'OCP\\Teams\\Team' => $baseDir . '/lib/public/Teams/Team.php',
'OCP\\Teams\\TeamAppAction' => $baseDir . '/lib/public/Teams/TeamAppAction.php',
'OCP\\Teams\\TeamAppActionConfirmation' => $baseDir . '/lib/public/Teams/TeamAppActionConfirmation.php',
'OCP\\Teams\\TeamAppActionPrompt' => $baseDir . '/lib/public/Teams/TeamAppActionPrompt.php',
'OCP\\Teams\\TeamAppActionResult' => $baseDir . '/lib/public/Teams/TeamAppActionResult.php',
'OCP\\Teams\\TeamAppEntry' => $baseDir . '/lib/public/Teams/TeamAppEntry.php',
'OCP\\Teams\\TeamAppNavigation' => $baseDir . '/lib/public/Teams/TeamAppNavigation.php',
'OCP\\Teams\\TeamAppResource' => $baseDir . '/lib/public/Teams/TeamAppResource.php',
'OCP\\Teams\\TeamAppResourceKey' => $baseDir . '/lib/public/Teams/TeamAppResourceKey.php',
'OCP\\Teams\\TeamAppResourcePicker' => $baseDir . '/lib/public/Teams/TeamAppResourcePicker.php',
'OCP\\Teams\\TeamAppRouteAlias' => $baseDir . '/lib/public/Teams/TeamAppRouteAlias.php',
'OCP\\Teams\\TeamFolder' => $baseDir . '/lib/public/Teams/TeamFolder.php',
'OCP\\Teams\\TeamResource' => $baseDir . '/lib/public/Teams/TeamResource.php',
'OCP\\Template' => $baseDir . '/lib/public/Template.php',
Expand Down
11 changes: 11 additions & 0 deletions lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -1115,10 +1115,21 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\TaskProcessing\\TaskTypes\\TextToTextSummary' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php',
'OCP\\TaskProcessing\\TaskTypes\\TextToTextTopics' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php',
'OCP\\TaskProcessing\\TaskTypes\\TextToTextTranslate' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php',
'OCP\\Teams\\ITeamAppProvider' => __DIR__ . '/../../..' . '/lib/public/Teams/ITeamAppProvider.php',
'OCP\\Teams\\ITeamFolderProvider' => __DIR__ . '/../../..' . '/lib/public/Teams/ITeamFolderProvider.php',
'OCP\\Teams\\ITeamManager' => __DIR__ . '/../../..' . '/lib/public/Teams/ITeamManager.php',
'OCP\\Teams\\ITeamResourceProvider' => __DIR__ . '/../../..' . '/lib/public/Teams/ITeamResourceProvider.php',
'OCP\\Teams\\Team' => __DIR__ . '/../../..' . '/lib/public/Teams/Team.php',
'OCP\\Teams\\TeamAppAction' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamAppAction.php',
'OCP\\Teams\\TeamAppActionConfirmation' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamAppActionConfirmation.php',
'OCP\\Teams\\TeamAppActionPrompt' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamAppActionPrompt.php',
'OCP\\Teams\\TeamAppActionResult' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamAppActionResult.php',
'OCP\\Teams\\TeamAppEntry' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamAppEntry.php',
'OCP\\Teams\\TeamAppNavigation' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamAppNavigation.php',
'OCP\\Teams\\TeamAppResource' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamAppResource.php',
'OCP\\Teams\\TeamAppResourceKey' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamAppResourceKey.php',
'OCP\\Teams\\TeamAppResourcePicker' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamAppResourcePicker.php',
'OCP\\Teams\\TeamAppRouteAlias' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamAppRouteAlias.php',
'OCP\\Teams\\TeamFolder' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamFolder.php',
'OCP\\Teams\\TeamResource' => __DIR__ . '/../../..' . '/lib/public/Teams/TeamResource.php',
'OCP\\Template' => __DIR__ . '/../../..' . '/lib/public/Template.php',
Expand Down
23 changes: 23 additions & 0 deletions lib/private/AppFramework/Bootstrap/RegistrationContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
use OCP\SystemReport\ISystemReportSection;
use OCP\Talk\ITalkBackend;
use OCP\TaskProcessing\ITaskType;
use OCP\Teams\ITeamAppProvider;
use OCP\Teams\ITeamResourceProvider;
use OCP\TextProcessing\IProvider as ITextProcessingProvider;
use OCP\Translation\ITranslationProvider;
Expand Down Expand Up @@ -163,6 +164,9 @@ class RegistrationContext {
/** @var ServiceRegistration<ITeamResourceProvider>[] */
private array $teamResourceProviders = [];

/** @var ServiceRegistration<ITeamAppProvider>[] */
private array $teamAppProviders = [];

/** @var ServiceRegistration<\OCP\TaskProcessing\IProvider>[] */
private array $taskProcessingProviders = [];

Expand Down Expand Up @@ -422,6 +426,11 @@ public function registerTeamResourceProvider(string $class) : void {
);
}

#[\Override]
public function registerTeamAppProvider(string $class): void {
$this->context->registerTeamAppProvider($this->appId, $class);
}

#[\Override]
public function registerCalendarRoomBackend(string $class): void {
$this->context->registerCalendarRoomBackend(
Expand Down Expand Up @@ -682,6 +691,13 @@ public function registerTeamResourceProvider(string $appId, string $class) {
);
}

/**
* @psalm-param class-string<ITeamAppProvider> $class
*/
public function registerTeamAppProvider(string $appId, string $class): void {
$this->teamAppProviders[] = new ServiceRegistration($appId, $class);
}

/**
* @psalm-param class-string<IUserMigrator> $migratorClass
*/
Expand Down Expand Up @@ -1117,6 +1133,13 @@ public function getTeamResourceProviders(): array {
return $this->teamResourceProviders;
}

/**
* @return ServiceRegistration<ITeamAppProvider>[]
*/
public function getTeamAppProviders(): array {
return $this->teamAppProviders;
}

/**
* @return ServiceRegistration<IDeclarativeSettingsForm>[]
*/
Expand Down
8 changes: 8 additions & 0 deletions lib/public/AppFramework/Bootstrap/IRegistrationContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,14 @@ public function registerCalendarRoomBackend(string $class): void;
*/
public function registerTeamResourceProvider(string $class): void;

/**
* Register app-owned navigation and embedded views for the Teams page.
*
* @param class-string<\OCP\Teams\ITeamAppProvider> $class
* @since 36.0.0
*/
public function registerTeamAppProvider(string $class): void;

/**
* Register an implementation of \OCP\UserMigration\IMigrator that
* will handle the implementation of a migrator
Expand Down
63 changes: 63 additions & 0 deletions lib/public/Teams/ITeamAppProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCP\Teams;

/**
* App-owned navigation and optional embedded views on the Teams page.
*
* Register the implementation with IRegistrationContext::registerTeamAppProvider().
*
* @since 36.0.0
*/
interface ITeamAppProvider {
/**
* Return the owning app ID.
*
* @since 36.0.0
*/
public function getId(): string;

/**
* Prepare initial state/styles and return an optional embedded-view module URL.
*
* @since 36.0.0
*/
public function load(): ?string;

/** @since 36.0.0 */
public function getOrder(): int;

/**
* Return alternate routes and the route parameter identifying an entry.
*
* @return list<TeamAppRouteAlias>
* @since 36.0.0
*/
public function getRouteAliases(): array;

/**
* Return navigation entries, available actions and shared resources represented by the entries.
*
* @param array{teamId: string, teamName: string, userId: string, isAdmin: bool, folder: ?TeamFolder, resources: list<TeamResource>, navigationEntryIds: list<string>, saveNavigationEntryIds: callable} $context
* @return TeamAppNavigation Entries and optional actions and resource keys for this team.
* @since 36.0.0
*/
public function getNavigation(array $context): TeamAppNavigation;

/**
* Execute an app action and return optional replacement navigation entry IDs and an entry ID to open.
*
* @param array{teamId: string, teamName: string, userId: string, isAdmin: bool, folder: ?TeamFolder, resources: list<TeamResource>, navigationEntryIds: list<string>, saveNavigationEntryIds: callable} $context
* @param array<string, mixed> $parameters
* @return TeamAppActionResult Omitted keys leave the current navigation and open entry unchanged.
* @since 36.0.0
*/
public function executeAction(array $context, string $actionId, array $parameters): TeamAppActionResult;
}
36 changes: 36 additions & 0 deletions lib/public/Teams/TeamAppAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCP\Teams;

/**
* An available app command with optional input or confirmation dialogs.
*
* @since 36.0.0
*/
final class TeamAppAction implements \JsonSerializable {
/** @since 36.0.0 */
public function __construct(
public readonly string $id,
public readonly string $label,
public readonly ?string $icon = null,
public readonly ?TeamAppActionPrompt $prompt = null,
public readonly ?TeamAppActionConfirmation $confirm = null,
public readonly ?TeamAppResourcePicker $resourcePicker = null,
) {
}

/**
* @return array<string, string|TeamAppActionPrompt|TeamAppActionConfirmation|TeamAppResourcePicker>
* @since 36.0.0
*/
public function jsonSerialize(): array {

Check failure on line 33 in lib/public/Teams/TeamAppAction.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

MissingOverrideAttribute

lib/public/Teams/TeamAppAction.php:33:2: MissingOverrideAttribute: Method OCP\Teams\TeamAppAction::jsonserialize should have the "Override" attribute (see https://psalm.dev/358)

Check failure on line 33 in lib/public/Teams/TeamAppAction.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

MissingOverrideAttribute

lib/public/Teams/TeamAppAction.php:33:2: MissingOverrideAttribute: Method OCP\Teams\TeamAppAction::jsonserialize should have the "Override" attribute (see https://psalm.dev/358)
return array_filter(get_object_vars($this), static fn ($value): bool => $value !== null);
}
}
32 changes: 32 additions & 0 deletions lib/public/Teams/TeamAppActionConfirmation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCP\Teams;

/**
* A confirmation dialog displayed before executing an app action.
*
* @since 36.0.0
*/
final class TeamAppActionConfirmation implements \JsonSerializable {
/** @since 36.0.0 */
public function __construct(
public readonly string $title,
public readonly string $message,
) {
}

/**
* @return array{title: string, message: string}
* @since 36.0.0
*/
public function jsonSerialize(): array {

Check failure on line 29 in lib/public/Teams/TeamAppActionConfirmation.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

MissingOverrideAttribute

lib/public/Teams/TeamAppActionConfirmation.php:29:2: MissingOverrideAttribute: Method OCP\Teams\TeamAppActionConfirmation::jsonserialize should have the "Override" attribute (see https://psalm.dev/358)

Check failure on line 29 in lib/public/Teams/TeamAppActionConfirmation.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

MissingOverrideAttribute

lib/public/Teams/TeamAppActionConfirmation.php:29:2: MissingOverrideAttribute: Method OCP\Teams\TeamAppActionConfirmation::jsonserialize should have the "Override" attribute (see https://psalm.dev/358)
return ['title' => $this->title, 'message' => $this->message];
}
}
32 changes: 32 additions & 0 deletions lib/public/Teams/TeamAppActionPrompt.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCP\Teams;

/**
* A text prompt displayed before executing an app action.
*
* @since 36.0.0
*/
final class TeamAppActionPrompt implements \JsonSerializable {
/** @since 36.0.0 */
public function __construct(
public readonly string $title,
public readonly ?string $value = null,
) {
}

/**
* @return array{title: string, value?: string}

Check failure on line 26 in lib/public/Teams/TeamAppActionPrompt.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidReturnType

lib/public/Teams/TeamAppActionPrompt.php:26:13: InvalidReturnType: The declared return type 'array{title: string, value?: string}' for OCP\Teams\TeamAppActionPrompt::jsonSerialize is incorrect, got 'array<'title'|'value', string>' which is different due to additional array shape fields (title) (see https://psalm.dev/011)

Check failure on line 26 in lib/public/Teams/TeamAppActionPrompt.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidReturnType

lib/public/Teams/TeamAppActionPrompt.php:26:13: InvalidReturnType: The declared return type 'array{title: string, value?: string}' for OCP\Teams\TeamAppActionPrompt::jsonSerialize is incorrect, got 'array<'title'|'value', string>' which is different due to additional array shape fields (title) (see https://psalm.dev/011)
* @since 36.0.0
*/
public function jsonSerialize(): array {

Check failure on line 29 in lib/public/Teams/TeamAppActionPrompt.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

MissingOverrideAttribute

lib/public/Teams/TeamAppActionPrompt.php:29:2: MissingOverrideAttribute: Method OCP\Teams\TeamAppActionPrompt::jsonserialize should have the "Override" attribute (see https://psalm.dev/358)

Check failure on line 29 in lib/public/Teams/TeamAppActionPrompt.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

MissingOverrideAttribute

lib/public/Teams/TeamAppActionPrompt.php:29:2: MissingOverrideAttribute: Method OCP\Teams\TeamAppActionPrompt::jsonserialize should have the "Override" attribute (see https://psalm.dev/358)
return array_filter(['title' => $this->title, 'value' => $this->value], static fn ($value): bool => $value !== null);

Check failure on line 30 in lib/public/Teams/TeamAppActionPrompt.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidReturnStatement

lib/public/Teams/TeamAppActionPrompt.php:30:10: InvalidReturnStatement: The inferred type 'array<'title'|'value', string>' does not match the declared return type 'array{title: string, value?: string}' for OCP\Teams\TeamAppActionPrompt::jsonSerialize due to additional array shape fields (title) (see https://psalm.dev/128)

Check failure on line 30 in lib/public/Teams/TeamAppActionPrompt.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidReturnStatement

lib/public/Teams/TeamAppActionPrompt.php:30:10: InvalidReturnStatement: The inferred type 'array<'title'|'value', string>' does not match the declared return type 'array{title: string, value?: string}' for OCP\Teams\TeamAppActionPrompt::jsonSerialize due to additional array shape fields (title) (see https://psalm.dev/128)
}
}
36 changes: 36 additions & 0 deletions lib/public/Teams/TeamAppActionResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCP\Teams;

/**
* Optional replacement navigation entry IDs and the entry to open after an action.
* Null fields leave the current navigation and open entry unchanged.
*
* @since 36.0.0
*/
final class TeamAppActionResult implements \JsonSerializable {
/**
* @param list<string>|null $navigationEntryIds
* @since 36.0.0
*/
public function __construct(
public readonly ?array $navigationEntryIds = null,
public readonly ?string $open = null,
) {
}

/**
* @return array{navigationEntryIds?: list<string>, open?: string}

Check failure on line 30 in lib/public/Teams/TeamAppActionResult.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

MoreSpecificReturnType

lib/public/Teams/TeamAppActionResult.php:30:13: MoreSpecificReturnType: The declared return type 'array{navigationEntryIds?: list<string>, open?: string}' for OCP\Teams\TeamAppActionResult::jsonSerialize is more specific than the inferred return type 'array<'navigationEntryIds'|'open', list<string>|string>' (see https://psalm.dev/070)
* @since 36.0.0
*/
public function jsonSerialize(): array {

Check failure on line 33 in lib/public/Teams/TeamAppActionResult.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

MissingOverrideAttribute

lib/public/Teams/TeamAppActionResult.php:33:2: MissingOverrideAttribute: Method OCP\Teams\TeamAppActionResult::jsonserialize should have the "Override" attribute (see https://psalm.dev/358)

Check failure on line 33 in lib/public/Teams/TeamAppActionResult.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

MissingOverrideAttribute

lib/public/Teams/TeamAppActionResult.php:33:2: MissingOverrideAttribute: Method OCP\Teams\TeamAppActionResult::jsonserialize should have the "Override" attribute (see https://psalm.dev/358)
return array_filter(get_object_vars($this), static fn ($value): bool => $value !== null);

Check failure on line 34 in lib/public/Teams/TeamAppActionResult.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

LessSpecificReturnStatement

lib/public/Teams/TeamAppActionResult.php:34:10: LessSpecificReturnStatement: The type 'array<'navigationEntryIds'|'open', list<string>|string>' is more general than the declared return type 'array{navigationEntryIds?: list<string>, open?: string}' for OCP\Teams\TeamAppActionResult::jsonSerialize (see https://psalm.dev/129)
}
}
Loading
Loading