Forum Discussion
zdeng88
Dec 03, 2024Copper Contributor
Cannot navigate to newly created channel tab by Graph API
Description:
We are experiencing an issue with navigation in our published MS Teams custom app. The app is published to the org catalog. We are using Sander/teams-js and teamsfx to implement a "Create Tab" user experience.
The problem is that after the tab is successfully created, we use the https://learn.microsoft.com/en-us/javascript/api/@microsoft/teams-js/pages?view=msteams-client-js-latest#@microsoft-teams-js-pages-navigatetoapp to open the tab and in some cases the navigation fails.
The code snippet we use to create the tab looks like as follows:
export class GraphClient {
credential: TeamsUserCredential;
client: Client;
constructor(clientId: string, initiateLoginEndpoint: string) {
this.credential = new TeamsUserCredential({
clientId,
initiateLoginEndpoint,
});
const authProvider = new TokenCredentialAuthenticationProvider(this.credential, { scopes });
this.client = Client.initWithMiddleware({
authProvider: authProvider,
});
}
async getTeamsApp(externalId: string): Promise<{
id: string;
externalId: string;
displayName: string;
distributionMethod: string;
} | null> {
const response = await this.client.api('/appCatalogs/teamsApps').filter(`externalId eq '${externalId}'`).get();
return response['@odata.count'] === 0 ? null : response.value[0];
}
async getTeamsInstalledApp(
teamId: string,
teamsAppId: string
): Promise<{
id: string;
teamsAppDefinition: {
id: string;
teamsAppId: string;
};
} | null> {
const response = await this.client
.api(`/teams/${teamId}/installedApps`)
.filter(`teamsAppDefinition/teamsAppId eq '${teamsAppId}'`)
.get();
return response['@odata.count'] === 0 ? null : response.value[0];
}
async installAppToTeam(teamId: string, teamsAppId: string): Promise<void> {
const teamsAppInstallation = {
'email address removed for privacy reasons': `https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/${teamsAppId}`,
};
await this.client.api(`/teams/${teamId}/installedApps`).post(teamsAppInstallation);
}
async addTabToChannel(
teamId: string,
channelId: string,
teamsAppId: string,
tabCreationProps: TabCreationProps
): Promise<{
tabEntityId: string;
webUrl: string;
}> {
const tabEntityId = generateRandomString(32);
const teamsTab = {
displayName: tabCreationProps.displayName,
'email address removed for privacy reasons': `https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/${teamsAppId}`,
configuration: {
entityId: tabEntityId,
contentUrl: tabCreationProps.contentUrl,
websiteUrl: tabCreationProps.websiteUrl,
removeUrl: tabCreationProps.removeUrl,
},
};
await this.client.api(`/teams/${teamId}/channels/${channelId}/tabs`).post(teamsTab);
return { tabEntityId, webUrl: tabCreationProps.websiteUrl };
}
}
export async function ensureAppInstalledInTeam(
graphClient: GraphClient,
teamId: string,
teamsAppId: string
): Promise<void> {
const installedApp = await graphClient.getTeamsInstalledApp(teamId, teamsAppId);
if (!installedApp) {
await graphClient.installAppToTeam(teamId, teamsAppId);
}
}
export async function createTabInChannel(
graphClient: GraphClient,
teamId: string,
channelId: string,
teamsAppExternalId: string,
tabCreationProps: TabCreationProps
): Promise<{
tabEntityId: string;
teamsAppId: string;
channelId: string;
webUrl: string;
}> {
const teamsAppDefinition = await graphClient.getTeamsApp(teamsAppExternalId);
if (!teamsAppDefinition) {
console.error('Teams App is not found in org catalog of current Teams environment.');
throw new Error('Unable to locate Teams App in current organization catalog.');
}
const teamsAppId = teamsAppDefinition.id;
try {
await ensureAppInstalledInTeam(graphClient, teamId, teamsAppId);
const { tabEntityId, webUrl } = await graphClient.addTabToChannel(
teamId,
channelId,
teamsAppId,
tabCreationProps
);
// Navigate to the newly created channel tab
pages.navigateToApp({
appId: teamsAppId,
channelId: channelId,
pageId: tabEntityId,
})
} catch (error) {
console.error('Fail to ensure the app is installed in the channel before adding a channel tab', error);
throw new Error('Fail to pin content in Teams channel. Please check the logs for details.');
}
}
Expected Behavior:
- The newly created tab should be open instead of opening the channel conversation tab or raising error.
Actual Behavior:
- If a user has never opened any channels of a team in Teams, then pinning any channel tab under that team in the Teams app will successfully open a new tab.
- If a user has already opened one of the channels in that team and pins that same opened channel's tab, it will redirect to the channel's conversation interface. If the user opens another channel that has not been opened before in that team and pins that channel tab, it will redirect but then a dialog error will pop up, displaying the channel’s conversation interface. However, in both cases, the tab is created, and once the conversation interface is shown, the new tab can be seen within the channel.
- If pinning a tab results in a dialog error and displays the channel’s conversation interface, the tab does not appear in the channel.
1 Reply
- Sayali-MSFT
Microsoft
@zdeng88- Thank you for your inquiry about your Teams app development issue!
We are checking the issue. We will get back to you shortly.