Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for using premium apis #2885

Open
wants to merge 6 commits into
base: next/mgt-chat
Choose a base branch
from
Open
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
8 changes: 7 additions & 1 deletion packages/mgt-chat/src/components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { onRenderMessage } from '../../utils/chat';
import { renderMGTMention } from '../../utils/mentions';
import { registerAppIcons } from '../styles/registerIcons';
import { ChatHeader } from '../ChatHeader/ChatHeader';
import { GraphConfig } from '../../statefulClient/GraphConfig';
import { Error } from '../Error/Error';
import { LoadingMessagesErrorIcon } from '../Error/LoadingMessageErrorIcon';
import { OpenTeamsLinkError } from '../Error/OpenTeams';
Expand All @@ -19,6 +20,7 @@ registerAppIcons();

interface IMgtChatProps {
chatId: string;
usePremiumApis?: boolean;
}

const useStyles = makeStyles({
Expand Down Expand Up @@ -105,7 +107,7 @@ const messageThreadStyles: MessageThreadStyles = {
}
};

export const Chat = ({ chatId }: IMgtChatProps) => {
export const Chat = ({ chatId, usePremiumApis }: IMgtChatProps) => {
const styles = useStyles();
const chatClient: StatefulGraphChatClient = useGraphChatClient(chatId);
const [chatState, setChatState] = useState(chatClient.getState());
Expand All @@ -116,6 +118,10 @@ export const Chat = ({ chatId }: IMgtChatProps) => {
};
}, [chatClient]);

useEffect(() => {
GraphConfig.usePremiumApis = usePremiumApis ?? false;
}, [usePremiumApis]);

const isLoading = ['creating server connections', 'subscribing to notifications', 'loading messages'].includes(
chatState.status
);
Expand Down
1 change: 1 addition & 0 deletions packages/mgt-chat/src/statefulClient/GraphConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class GraphConfig {
public static canarySubscriptionVersion = 'testprodv1.0e2ewebsockets';

public static webSocketsPrefix = 'websockets:';
static usePremiumApis = false;

public static get graphEndpoint(): GraphEndpoint {
return GraphConfig.useCanary ? 'https://canary.graph.microsoft.com' : 'https://graph.microsoft.com';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
import { GraphConfig } from './GraphConfig';
import { SubscriptionsCache } from './Caching/SubscriptionCache';
import { Timer } from '../utils/Timer';
import { addPremiumApiSegment } from '../utils/addPremiumApiSegment';
import { getOrGenerateGroupId } from './getOrGenerateGroupId';

export const appSettings = {
Expand Down Expand Up @@ -396,7 +397,9 @@ export class GraphNotificationClient {
await this.subscriptionCache.deleteCachedSubscriptions(chatId);
}
const promises: Promise<unknown>[] = [];
promises.push(this.subscribeToResource(`/chats/${chatId}/messages`, ['created', 'updated', 'deleted']));
promises.push(
this.subscribeToResource(addPremiumApiSegment(`/chats/${chatId}/messages`), ['created', 'updated', 'deleted'])
);
promises.push(this.subscribeToResource(`/chats/${chatId}/members`, ['created', 'deleted']));
promises.push(this.subscribeToResource(`/chats/${chatId}`, ['updated', 'deleted']));
await Promise.all(promises).catch((e: Error) => {
Expand Down
5 changes: 3 additions & 2 deletions packages/mgt-chat/src/statefulClient/graph.chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { CacheService, IGraph, prepScopes } from '@microsoft/mgt-element';
import { ResponseType } from '@microsoft/microsoft-graph-client';
import { AadUserConversationMember, Chat, ChatMessage } from '@microsoft/microsoft-graph-types';
import { chatOperationScopes } from './chatOperationScopes';
import { addPremiumApiSegment } from '../utils/addPremiumApiSegment';

/**
* Generic collection response from graph
Expand Down Expand Up @@ -59,7 +60,7 @@ export const loadChatThread = async (
messageCount: number
): Promise<MessageCollection> => {
const response = (await graph
.api(`/chats/${chatId}/messages`)
.api(addPremiumApiSegment(`/chats/${chatId}/messages`))
.orderby('createdDateTime DESC')
.top(messageCount)
.middlewareOptions(prepScopes(chatOperationScopes.loadChatMessages))
Expand All @@ -86,7 +87,7 @@ export const loadChatThreadDelta = async (
messageCount: number
): Promise<MessageCollection> => {
const response = (await graph
.api(`/chats/${chatId}/messages`)
.api(addPremiumApiSegment(`/chats/${chatId}/messages`))
.filter(`lastModifiedDateTime gt ${lastModified}`)
.orderby('lastModifiedDateTime DESC')
.top(messageCount)
Expand Down
25 changes: 25 additions & 0 deletions packages/mgt-chat/src/utils/addPremiumApiSegment.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { GraphConfig } from '../statefulClient/GraphConfig';
import { addPremiumApiSegment } from './addPremiumApiSegment';
import { expect } from '@open-wc/testing';

describe('addPremiumApiSegment tests', () => {
it('should return the original url if premium apis are not enabled', async () => {
const url = 'https://graph.microsoft.com/v1.0/me';
const result = addPremiumApiSegment(url);
await expect(result).to.eql(url);
});

it('should add the premium api segment to the url', async () => {
const url = 'https://graph.microsoft.com/v1.0/me';
GraphConfig.usePremiumApis = true;
const result = addPremiumApiSegment(url);
await expect(result).to.eql(`${url}?model=B`);
});

it('should add the premium api segment to the url when it already has query params', async () => {
const url = 'https://graph.microsoft.com/v1.0/me?select=id';
GraphConfig.usePremiumApis = true;
const result = addPremiumApiSegment(url);
await expect(result).to.eql(`${url}&model=B`);
});
});
10 changes: 10 additions & 0 deletions packages/mgt-chat/src/utils/addPremiumApiSegment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { GraphConfig } from '../statefulClient/GraphConfig';

export const addPremiumApiSegment = (url: string) => {
// early exit if premium apis are not enabled
if (!GraphConfig.usePremiumApis) {
return url;
}
const urlHasExistingQueryParams = url.includes('?');
return `${url}${urlHasExistingQueryParams ? '&' : '?'}model=B`;
};
2 changes: 1 addition & 1 deletion packages/mgt-chat/src/utils/mentions.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { MgtTemplateProps, Person } from '@microsoft/mgt-react';
import { ChatMessageMention, User } from '@microsoft/microsoft-graph-types';
import { GraphChatClient } from 'src/statefulClient/StatefulGraphChatClient';
import { GraphChatClient } from '../statefulClient/StatefulGraphChatClient';
import { Mention } from '@azure/communication-react';

export const renderMGTMention = (chatState: GraphChatClient) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/mgt-chat/src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { ChatMessage, Message } from '@azure/communication-react';
import { GraphChatMessage } from 'src/statefulClient/StatefulGraphChatClient';
import type { GraphChatMessage } from '../statefulClient/StatefulGraphChatClient';

/**
* A typeguard to get the ChatMessage type
Expand Down
2 changes: 2 additions & 0 deletions packages/mgt-spfx/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
release
temp
1 change: 1 addition & 0 deletions samples/react-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@fluentui/react-components": "^9.19.1",
"@microsoft/mgt-chat": "*",
"@microsoft/mgt-msal2-provider": "*",
"@microsoft/mgt-react": "*",
Expand Down
53 changes: 31 additions & 22 deletions samples/react-chat/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, { memo, useCallback, useState } from 'react';
import React, { ChangeEvent, memo, useCallback, useState } from 'react';
import './App.css';
import { Get, Login } from '@microsoft/mgt-react';
import { Chat, NewChat } from '@microsoft/mgt-chat';
import { Chat as GraphChat } from '@microsoft/microsoft-graph-types';
import ChatListTemplate from './components/ChatListTemplate/ChatListTemplate';
import { FluentProvider, Switch, SwitchOnChangeData, teamsLightTheme } from '@fluentui/react-components';

const ChatList = memo(({ chatSelected }: { chatSelected: (e: GraphChat) => void }) => {
return (
Expand All @@ -25,31 +26,39 @@ function App() {
setShowNewChat(false);
}, []);

const [usePremiumApis, setUsePremiumApis] = useState<boolean>(false);
const onToggleChanged = useCallback((ev: ChangeEvent<HTMLInputElement>, data: SwitchOnChangeData) => {
setUsePremiumApis(data.checked ?? false);
}, []);

return (
<div className="App">
<header className="App-header">
Mgt Chat test harness
<br />
<Login />
</header>
<main className="main">
<div className="chat-selector">
<ChatList chatSelected={chatSelected} />
Selected chat: {chatId}
<br />
<button onClick={() => setChatId('')}>Clear selected chat</button>
<FluentProvider theme={teamsLightTheme}>
<header className="App-header">
Mgt Chat test harness
<br />
<button onClick={() => setShowNewChat(true)}>New Chat</button>
{showNewChat && (
<div className="new-chat">
<NewChat onChatCreated={onChatCreated} onCancelClicked={() => setShowNewChat(false)} mode="auto" />
</div>
)}
</div>
<Login />
</header>
<main className="main">
<div className="chat-selector">
<Switch onChange={onToggleChanged} checked={usePremiumApis} label="Use premium APIs?" />
<ChatList chatSelected={chatSelected} />
musale marked this conversation as resolved.
Show resolved Hide resolved
Selected chat: {chatId}
<br />
<button onClick={() => setChatId('')}>Clear selected chat</button>
<br />
<button onClick={() => setShowNewChat(true)}>New Chat</button>
{showNewChat && (
<div className="new-chat">
<NewChat onChatCreated={onChatCreated} onCancelClicked={() => setShowNewChat(false)} mode="auto" />
</div>
)}
</div>

{/* NOTE: removed the chatId guard as this case has an error state. */}
<div className="chat-pane">{<Chat chatId={chatId} />}</div>
</main>
{/* NOTE: removed the chatId guard as this case has an error state. */}
<div className="chat-pane">{<Chat chatId={chatId} usePremiumApis={usePremiumApis} />}</div>
</main>
</FluentProvider>
</div>
);
}
Expand Down
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -26715,6 +26715,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "react-chat@workspace:samples/react-chat"
dependencies:
"@fluentui/react-components": ^9.19.1
"@microsoft/mgt-chat": "*"
"@microsoft/mgt-msal2-provider": "*"
"@microsoft/mgt-react": "*"
Expand Down
Loading