Compare commits

..

25 Commits

Author SHA1 Message Date
tomasvaron
04d6a17b70 Merge branch 'user/t-tomasvaron/chatbot' of https://github.com/Azure/cosmos-explorer into user/t-tomasvaron/chatbot 2022-07-27 21:30:39 -04:00
tomasvaron
905413bf17 remove testing values 2022-07-27 21:29:52 -04:00
tomasvaron
f519aa7be3 Remove newline 2022-07-27 21:27:11 -04:00
tomasvaron
053e346fa4 revert changes 2022-07-27 21:26:21 -04:00
tomasvaron
b4909d9e13 merge 2022-07-18 11:59:08 -04:00
tomasvaron
b268b525d8 merge with master 2022-07-18 11:23:29 -04:00
tomasvaron
02d0353215 Added space between the chat symbol and button text 2022-07-14 10:30:28 -04:00
tomasvaron
4fd153d676 chatbot sticky button 2022-06-20 15:16:07 -04:00
tomasvaron
7b1f3bb493 Merge branch 'user/balalakshmin/chatbot' into user/t-tomasvaron/chatbot 2022-05-11 11:30:04 -04:00
Bala Lakshmi Narayanasami
95b43d83d1 Compile errors fixed 2022-05-11 15:12:55 +05:30
Bala Lakshmi Narayanasami
f9494030ac Format fix 2022-05-10 18:08:25 +05:30
Bala Lakshmi Narayanasami
a1087b2626 Updating package-lock 2022-05-10 16:35:19 +05:30
Bala Lakshmi Narayanasami
5aeca52234 Reverting local change 2022-05-10 15:42:00 +05:30
Bala Lakshmi Narayanasami
6c77430775 Fixed lint errors 2022-05-10 15:34:58 +05:30
Bala Lakshmi Narayanasami
7bc78f126b Reverting unwanted changes 2022-05-09 19:08:26 +05:30
Bala Lakshmi Narayanasami
e3ef515d8b Reverting vscode settings changes 2022-05-09 19:05:42 +05:30
Bala Lakshmi Narayanasami
7ffc1bc35a Code cleanup 2022-05-09 19:04:17 +05:30
Bala Lakshmi Narayanasami
6add6d2e86 Changes for getting conversation token 2022-05-09 18:50:04 +05:30
Bala Lakshmi Narayanasami
a089bac80e Adding chatbot behind feature flag 2022-05-06 16:59:47 +05:30
Bala Lakshmi Narayanasami
c0b5e185aa Merge branch 'master' of https://github.com/Azure/cosmos-explorer into user/balalakshmin/chatbot 2022-05-04 16:55:03 +05:30
Bala Lakshmi Narayanasami
986fe39d07 Minor fix 2022-04-27 16:13:37 +05:30
Bala Lakshmi Narayanasami
fd511f2706 icon alignment fix 2022-02-17 21:02:42 +05:30
Bala Lakshmi Narayanasami
c35e23eb47 updating botframework version 2022-01-12 19:45:34 +05:30
Bala Lakshmi Narayanasami
80be52685f Merge branch 'master' of https://github.com/Azure/cosmos-explorer into user/balalakshmin/chatbot 2022-01-06 19:48:55 +05:30
Bala Lakshmi Narayanasami
d29fd6e957 Merge latest master changes to chatbot 2021-08-03 17:11:00 +05:30
18 changed files with 46170 additions and 4955 deletions

23
less/chat.less Normal file
View File

@@ -0,0 +1,23 @@
@import "./Common/Constants";
.chat {
display: grid;
justify-content: right;
padding: 10px;
.chatButton {
margin: 0 45px 15px 0;
border: 10px;
min-height: 44px;
&:focus {
outline: 0px;
}
>span {
font-size: 17px;
font-family: @DataExplorerFont;
color: @AccentLow;
}
}
}

50940
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
"main": "index.js",
"dependencies": {
"@azure/arm-cosmosdb": "9.1.0",
"@azure/cosmos": "3.16.3",
"@azure/cosmos": "3.16.2",
"@azure/cosmos-language-service": "0.0.5",
"@azure/identity": "1.2.1",
"@azure/ms-rest-nodeauth": "3.0.7",
@@ -128,6 +128,7 @@
"@types/react-notification-system": "0.2.39",
"@types/react-redux": "7.1.7",
"@types/react-splitter-layout": "3.0.1",
"@types/react-youtube": "7.10.0",
"@types/sanitize-html": "1.27.2",
"@types/sinon": "2.3.3",
"@types/styled-components": "5.1.1",
@@ -192,7 +193,7 @@
"start": "webpack serve --mode development",
"dev": "echo \"WARNING: npm run dev has been deprecated\" && npm run build",
"build:dataExplorer:ci": "npm run build:ci",
"build": "npm run format:check && npm run lint && npm run compile && npm run compile:strict && npm run pack:prod --max_old_space_size=4096 && npm run copyToConsumers",
"build": "npm run format:check && npm run lint && npm run compile && npm run compile:strict && npm run pack:prod && npm run copyToConsumers",
"build:ci": "npm run format:check && npm run lint && npm run compile && npm run compile:strict && npm run pack:fast",
"pack:prod": "webpack --mode production",
"pack:fast": "webpack --mode development --progress",

View File

@@ -1,26 +0,0 @@
import { HttpHeaders } from "../Common/Constants";
import { configContext } from "../ConfigContext";
import { userContext } from "../UserContext";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
export class ChatbotClient {
public async getConversationToken(): Promise<{ conversationId: string; token: string; expires_in: number }> {
const url = `${configContext.JUNO_ENDPOINT}/api/chatbot/bot${userContext.databaseAccount.id}/conversationToken`;
const authorizationHeader = getAuthorizationHeader();
const response = await window.fetch(url, {
method: "GET",
headers: {
[HttpHeaders.contentType]: "application/json",
[authorizationHeader.header]: authorizationHeader.token,
Accept: "application/json",
},
});
if (!response.ok) {
throw new Error(await response.json());
}
const tokenResponse: { conversationId: string; token: string; expires_in: number } = await response.json();
return tokenResponse;
}
}

View File

@@ -9,7 +9,7 @@ import {
allowedJunoOrigins,
allowedMongoBackendEndpoints,
allowedMsalRedirectEndpoints,
validateEndpoint,
validateEndpoint
} from "Utils/EndpointValidation";
export enum Platform {
@@ -190,3 +190,4 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
}
export { configContext };

View File

@@ -0,0 +1,42 @@
import { IIconProps } from '@fluentui/react';
import { PrimaryButton } from '@fluentui/react/lib/Button';
import { AuthType } from 'AuthType';
import { SupportPaneComponent } from 'Explorer/Controls/SupportPaneComponent/SupportPaneComponent';
import Explorer from 'Explorer/Explorer';
import { useSidePanel } from 'hooks/useSidePanel';
import * as React from 'react';
import { userContext } from 'UserContext';
export interface ChatButtonProps {
container: Explorer;
}
const chatIcon: IIconProps = { iconName: 'ChatSolid', style: { marginRight: 10 } };
export const ChatButtonAction: React.FunctionComponent<ChatButtonProps> = props => {
const { container } = props;
if (userContext.authType === AuthType.AAD && userContext.features.enableChatbot) {
return (
<PrimaryButton className={"chatButton"} iconProps={chatIcon} onClick={() => {
useSidePanel
.getState()
.openSidePanel(
"Chat Assistant (Beta)",
<SupportPaneComponent
directLineToken={container.conversationToken()}
userToken={userContext.authorizationToken}
subId={userContext.subscriptionId}
rg={userContext.resourceGroup}
accName={userContext.databaseAccount.name}
/>
);
}}>
<span> Help? </span>
</PrimaryButton>
);
}
return <div></div>
};

View File

@@ -1,14 +1,13 @@
/**
* React component for Command button component.
*/
import { Icon } from "@fluentui/react";
import { Icon, IIconStyles } from "@fluentui/react";
import * as React from "react";
import CollapseChevronDownIcon from "../../../../images/QueryBuilder/CollapseChevronDown_16x.png";
import { KeyCodes } from "../../../Common/Constants";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import * as StringUtils from "../../../Utils/StringUtils";
/**
* Options for this component
*/
@@ -244,6 +243,7 @@ export class CommandButtonComponent extends React.Component<CommandButtonCompone
if (this.props.children && this.props.children.length > 0) {
contentClassName += " hasHiddenItems";
}
const iconButtonStyles: Partial<IIconStyles> = { root: { marginBottom: -3 } };
return (
<div className="commandButtonReact">
@@ -264,7 +264,7 @@ export class CommandButtonComponent extends React.Component<CommandButtonCompone
{
<div>
<Icon
styles={{ root: { marginBottom: -3 } }}
styles={iconButtonStyles}
className="panelInfoIcon"
iconName={this.props.iconName}
ariaLabel="ChatBot"

View File

@@ -30,8 +30,6 @@ exports[`SettingsComponent renders 1`] = `
"container": Explorer {
"_isInitializingNotebooks": false,
"_resetNotebookWorkspace": [Function],
"chatbotClient": ChatbotClient {},
"conversationToken": [Function],
"isFixedCollectionWithSharedThroughputSupported": [Function],
"isTabsContentExpanded": [Function],
"onRefreshDatabasesKeyPress": [Function],
@@ -108,8 +106,6 @@ exports[`SettingsComponent renders 1`] = `
"container": Explorer {
"_isInitializingNotebooks": false,
"_resetNotebookWorkspace": [Function],
"chatbotClient": ChatbotClient {},
"conversationToken": [Function],
"isFixedCollectionWithSharedThroughputSupported": [Function],
"isTabsContentExpanded": [Function],
"onRefreshDatabasesKeyPress": [Function],

View File

@@ -1,7 +1,10 @@
import { Activity } from "botframework-directlinejs";
import ReactWebChat, { createDirectLine } from "botframework-webchat";
import * as React from "react";
import ReactWebChat from "botframework-webchat";
import React from "react";
import * as _ from "underscore";
const BotFramework = require('botframework-webchat');
export interface SupportPaneComponentProps {
directLineToken: string;
userToken: string;
@@ -21,9 +24,11 @@ export class SupportPaneComponent extends React.Component<SupportPaneComponentPr
const styleOptions = {
bubbleBackground: "rgba(0, 0, 255, .1)",
bubbleFromUserBackground: "rgba(0, 255, 0, .1)",
suggestedActionLayout: 'flow',
markdownRespectCRLF: true,
};
const directLine = createDirectLine({ token: this.props.directLineToken });
const directLine = BotFramework.createDirectLine({ token: this.props.directLineToken });
const dl = {
...directLine,
postActivity: (activity: Activity) => {

View File

@@ -1,5 +1,6 @@
import { Link } from "@fluentui/react/lib/Link";
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
import { configContext } from "ConfigContext";
import { IGalleryItem } from "Juno/JunoClient";
import * as ko from "knockout";
import React from "react";
@@ -8,7 +9,6 @@ import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointValid
import shallow from "zustand/shallow";
import { AuthType } from "../AuthType";
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
import { ChatbotClient } from "../Chatbot/ChatbotClient";
import * as Constants from "../Common/Constants";
import { Areas, ConnectionStatusType, HttpStatusCodes, Notebook, PoolIdType } from "../Common/Constants";
import { readCollection } from "../Common/dataAccess/readCollection";
@@ -35,6 +35,7 @@ import { userContext } from "../UserContext";
import { getCollectionName, getUploadName } from "../Utils/APITypeUtils";
import { update } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
import { listByDatabaseAccount } from "../Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
import { stringToBlob } from "../Utils/BlobUtils";
import { isCapabilityEnabled } from "../Utils/CapabilityUtils";
import { fromContentUri, toRawContentUri } from "../Utils/GitHubUtils";
@@ -100,14 +101,12 @@ export default class Explorer {
private static readonly MaxNbDatabasesToAutoExpand = 5;
private phoenixClient: PhoenixClient;
private chatbotClient: ChatbotClient;
constructor() {
const startKey: number = TelemetryProcessor.traceStart(Action.InitializeDataExplorer, {
dataExplorerArea: Constants.Areas.ResourceTree,
});
this._isInitializingNotebooks = false;
this.phoenixClient = new PhoenixClient();
this.chatbotClient = new ChatbotClient();
useNotebook.subscribe(
() => this.refreshCommandBarButtons(),
(state) => state.isNotebooksEnabledForAccount
@@ -117,6 +116,8 @@ export default class Explorer {
this.conversationToken = ko.observable<string>();
this.generateConversationToken();
useSelectedNode.subscribe(() => {
// Make sure switching tabs restores tabs display
this.isTabsContentExpanded(false);
@@ -467,18 +468,26 @@ export default class Explorer {
}
private async generateConversationToken() {
if (userContext.databaseAccount === undefined || userContext.databaseAccount.id === undefined) {
return;
const url = `${configContext.JUNO_ENDPOINT}/api/chatbot/bot${userContext.databaseAccount.id}/conversationToken`;
const authorizationHeader = getAuthorizationHeader();
const response = await fetch(url, {
method: "GET",
headers: {
[Constants.HttpHeaders.authorization]: authorizationHeader.token,
Accept: "application/json",
[Constants.HttpHeaders.contentType]: "application/json",
},
});
if (!response.ok) {
throw new Error(await response.json());
}
try {
const tokenResponse = await this.chatbotClient.getConversationToken();
this.conversationToken(tokenResponse?.token);
if (tokenResponse?.expires_in) {
setTimeout(() => this.generateConversationToken(), (tokenResponse?.expires_in - 1000) * 1000);
}
} catch (error) {
console.error("Exception while getting conversation token");
console.error(error);
const tokenResponse: { conversationId: string; token: string; expires_in: number } = await response.json();
this.conversationToken(tokenResponse?.token);
if (tokenResponse?.expires_in) {
setTimeout(() => this.generateConversationToken(), (tokenResponse?.expires_in - 1000) * 1000);
}
}
@@ -1297,8 +1306,5 @@ export default class Explorer {
if (useNotebook.getState().isPhoenixNotebooks) {
await this.initNotebooks(userContext.databaseAccount);
}
if (userContext.features.enableChatbot) {
this.generateConversationToken();
}
}
}

View File

@@ -45,6 +45,7 @@
.fonticoncustom {
padding-top: 12px;
}
.status {
position: relative;
display: block;

View File

@@ -21,4 +21,4 @@
color: @SelectionHigh;
}
}
}
}

View File

@@ -19,8 +19,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
"container": Explorer {
"_isInitializingNotebooks": false,
"_resetNotebookWorkspace": [Function],
"chatbotClient": ChatbotClient {},
"conversationToken": [Function],
"isFixedCollectionWithSharedThroughputSupported": [Function],
"isTabsContentExpanded": [Function],
"onRefreshDatabasesKeyPress": [Function],

View File

@@ -9,8 +9,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
Explorer {
"_isInitializingNotebooks": false,
"_resetNotebookWorkspace": [Function],
"chatbotClient": ChatbotClient {},
"conversationToken": [Function],
"isFixedCollectionWithSharedThroughputSupported": [Function],
"isTabsContentExpanded": [Function],
"onRefreshDatabasesKeyPress": [Function],

View File

@@ -1,6 +1,7 @@
// CSS Dependencies
import { initializeIcons } from "@fluentui/react";
import "bootstrap/dist/css/bootstrap.css";
import { ChatButtonAction } from "Explorer/Controls/ChatButton/ChatButtonComponent";
import { QuickstartCarousel } from "Explorer/Tutorials/QuickstartCarousel";
import { QuickstartTutorial } from "Explorer/Tutorials/QuickstartTutorial";
import { useCarousel } from "hooks/useCarousel";
@@ -17,6 +18,7 @@ import "../externals/jquery.typeahead.min.js";
import "../images/CosmosDB_rgb_ui_lighttheme.ico";
import "../images/favicon.ico";
import hdeConnectImage from "../images/HdeConnectCosmosDB.svg";
import "../less/chat.less";
import "../less/documentDB.less";
import "../less/forms.less";
import "../less/infobox.less";
@@ -103,6 +105,9 @@ const App: React.FunctionComponent = () => {
<Tabs explorer={explorer} />
</div>
{/* Collections Tree and Tabs - End */}
<div className="chat">
<ChatButtonAction container={explorer} />
</div>
<div
className="dataExplorerErrorConsoleContainer"
role="contentinfo"
@@ -111,6 +116,7 @@ const App: React.FunctionComponent = () => {
>
<NotificationConsole />
</div>
</div>
<SidePanel />
<Dialog />

View File

@@ -29,8 +29,10 @@ export type Features = {
readonly mongoProxyEndpoint?: string;
readonly mongoProxyAPIs?: string;
readonly enableThroughputCap: boolean;
readonly enableNewQuickstart: boolean;
readonly enableChatbot?: boolean;
// can be set via both flight and feature flag
autoscaleDefault: boolean;
partitionKeyDefault: boolean;
@@ -91,6 +93,7 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
partitionKeyDefault2: "true" === get("pkpartitionkeytest"),
notebooksDownBanner: "true" === get("notebooksDownBanner"),
enableThroughputCap: "true" === get("enablethroughputcap"),
enableNewQuickstart: "true" === get("enablenewquickstart"),
enableChatbot: "true" === get("enablechatbot"),
};
}

View File

@@ -21,8 +21,7 @@
"resolveJsonModule": true,
"noEmit": true,
"types": ["jest"],
"baseUrl": "src",
"skipLibCheck": true
"baseUrl": "src"
},
"typedocOptions": {
"entryPoints": [

View File

@@ -244,10 +244,10 @@ module.exports = function (_env = {}, argv = {}) {
new TerserPlugin({
terserOptions: {
// These options increase our initial bundle size by ~5% but the builds are significantly faster and won't run out of memory
compress: true,
compress: false,
mangle: {
keep_fnames: false,
keep_classnames: false,
keep_fnames: true,
keep_classnames: true,
},
},
}),