@notebook-intelligence/notebook-intelligence 2.2.5 → 2.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,12 @@
1
1
  // Copyright (c) Mehmet Bektas <mbektasgh@outlook.com>
2
- import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import React, { useCallback, useEffect, useMemo, useRef, useState, memo } from 'react';
3
3
  import { ReactWidget } from '@jupyterlab/apputils';
4
4
  import { UUID } from '@lumino/coreutils';
5
5
  import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
6
6
  import { NBIAPI, GitHubCopilotLoginStatus } from './api';
7
7
  import { BackendMessageType, BuiltinToolsetType, ContextType, GITHUB_COPILOT_PROVIDER_ID, RequestDataType, ResponseStreamDataType, TelemetryEventType } from './tokens';
8
- import { MarkdownRenderer } from './markdown-renderer';
8
+ import { MarkdownRenderer as OriginalMarkdownRenderer } from './markdown-renderer';
9
+ const MarkdownRenderer = memo(OriginalMarkdownRenderer);
9
10
  import copySvgstr from '../style/icons/copy.svg';
10
11
  import copilotSvgstr from '../style/icons/copilot.svg';
11
12
  import copilotWarningSvgstr from '../style/icons/copilot-warning.svg';
@@ -141,6 +142,7 @@ function ChatResponseHTMLFrame(props) {
141
142
  return (React.createElement("div", { className: "chat-response-html-frame", key: `key-${props.index}` },
142
143
  React.createElement("iframe", { className: "chat-response-html-frame-iframe", height: props.height, sandbox: "allow-scripts", src: iframSrc })));
143
144
  }
145
+ // Memoize ChatResponse for performance
144
146
  function ChatResponse(props) {
145
147
  var _a, _b, _c;
146
148
  const [renderCount, setRenderCount] = useState(0);
@@ -302,6 +304,7 @@ function ChatResponse(props) {
302
304
  }),
303
305
  msg.notebookLink && (React.createElement("a", { className: "copilot-generated-notebook-link", "data-ref": msg.notebookLink, onClick: openNotebook }, "open notebook")))));
304
306
  }
307
+ const MemoizedChatResponse = memo(ChatResponse);
305
308
  async function submitCompletionRequest(request, responseEmitter) {
306
309
  switch (request.type) {
307
310
  case RunChatCompletionType.Chat:
@@ -372,6 +375,8 @@ function SidebarComponent(props) {
372
375
  };
373
376
  const [toolSelections, setToolSelections] = useState(toolSelectionsInitial);
374
377
  const [hasExtensionTools, setHasExtensionTools] = useState(false);
378
+ const [lastScrollTime, setLastScrollTime] = useState(0);
379
+ const [scrollPending, setScrollPending] = useState(false);
375
380
  NBIAPI.configChanged.connect(() => {
376
381
  setToolConfig(NBIAPI.config.toolConfig);
377
382
  });
@@ -960,9 +965,24 @@ function SidebarComponent(props) {
960
965
  }
961
966
  }
962
967
  };
968
+ // Throttle scrollMessagesToBottom to only scroll every 500ms
969
+ const SCROLL_THROTTLE_TIME = 1000;
963
970
  const scrollMessagesToBottom = () => {
964
971
  var _a;
965
- (_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' });
972
+ const now = Date.now();
973
+ if (now - lastScrollTime >= SCROLL_THROTTLE_TIME) {
974
+ (_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' });
975
+ setLastScrollTime(now);
976
+ }
977
+ else if (!scrollPending) {
978
+ setScrollPending(true);
979
+ setTimeout(() => {
980
+ var _a;
981
+ (_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' });
982
+ setLastScrollTime(Date.now());
983
+ setScrollPending(false);
984
+ }, SCROLL_THROTTLE_TIME - (now - lastScrollTime));
985
+ }
966
986
  };
967
987
  const handleConfigurationClick = async () => {
968
988
  props
@@ -1142,7 +1162,7 @@ function SidebarComponent(props) {
1142
1162
  chatEnabled &&
1143
1163
  (chatMessages.length === 0 ? (React.createElement("div", { className: "sidebar-messages" },
1144
1164
  React.createElement("div", { className: "sidebar-greeting" }, "Welcome! How can I assist you today?"))) : (React.createElement("div", { className: "sidebar-messages" },
1145
- chatMessages.map((msg, index) => (React.createElement(ChatResponse, { key: `key-${index}`, message: msg, openFile: props.openFile, getApp: props.getApp, getActiveDocumentInfo: props.getActiveDocumentInfo, showGenerating: index === chatMessages.length - 1 &&
1165
+ chatMessages.map((msg, index) => (React.createElement(MemoizedChatResponse, { key: msg.id, message: msg, openFile: props.openFile, getApp: props.getApp, getActiveDocumentInfo: props.getActiveDocumentInfo, showGenerating: index === chatMessages.length - 1 &&
1146
1166
  msg.from === 'copilot' &&
1147
1167
  copilotRequestInProgress }))),
1148
1168
  React.createElement("div", { ref: messagesEndRef })))),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notebook-intelligence/notebook-intelligence",
3
- "version": "2.2.5",
3
+ "version": "2.2.7",
4
4
  "description": "AI coding assistant for JupyterLab",
5
5
  "keywords": [
6
6
  "AI",
@@ -7,7 +7,8 @@ import React, {
7
7
  useEffect,
8
8
  useMemo,
9
9
  useRef,
10
- useState
10
+ useState,
11
+ memo
11
12
  } from 'react';
12
13
  import { ReactWidget } from '@jupyterlab/apputils';
13
14
  import { UUID } from '@lumino/coreutils';
@@ -32,7 +33,8 @@ import {
32
33
  TelemetryEventType
33
34
  } from './tokens';
34
35
  import { JupyterFrontEnd } from '@jupyterlab/application';
35
- import { MarkdownRenderer } from './markdown-renderer';
36
+ import { MarkdownRenderer as OriginalMarkdownRenderer } from './markdown-renderer';
37
+ const MarkdownRenderer = memo(OriginalMarkdownRenderer);
36
38
 
37
39
  import copySvgstr from '../style/icons/copy.svg';
38
40
  import copilotSvgstr from '../style/icons/copilot.svg';
@@ -314,6 +316,7 @@ function ChatResponseHTMLFrame(props: any) {
314
316
  );
315
317
  }
316
318
 
319
+ // Memoize ChatResponse for performance
317
320
  function ChatResponse(props: any) {
318
321
  const [renderCount, setRenderCount] = useState(0);
319
322
  const msg: IChatMessage = props.message;
@@ -599,6 +602,7 @@ function ChatResponse(props: any) {
599
602
  </div>
600
603
  );
601
604
  }
605
+ const MemoizedChatResponse = memo(ChatResponse);
602
606
 
603
607
  async function submitCompletionRequest(
604
608
  request: IRunChatCompletionRequest,
@@ -726,6 +730,8 @@ function SidebarComponent(props: any) {
726
730
  };
727
731
  const [toolSelections, setToolSelections] = useState(toolSelectionsInitial);
728
732
  const [hasExtensionTools, setHasExtensionTools] = useState(false);
733
+ const [lastScrollTime, setLastScrollTime] = useState(0);
734
+ const [scrollPending, setScrollPending] = useState(false);
729
735
 
730
736
  NBIAPI.configChanged.connect(() => {
731
737
  setToolConfig(NBIAPI.config.toolConfig);
@@ -1475,8 +1481,24 @@ function SidebarComponent(props: any) {
1475
1481
  }
1476
1482
  };
1477
1483
 
1484
+ // Throttle scrollMessagesToBottom to only scroll every 500ms
1485
+ const SCROLL_THROTTLE_TIME = 1000;
1478
1486
  const scrollMessagesToBottom = () => {
1479
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
1487
+ const now = Date.now();
1488
+ if (now - lastScrollTime >= SCROLL_THROTTLE_TIME) {
1489
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
1490
+ setLastScrollTime(now);
1491
+ } else if (!scrollPending) {
1492
+ setScrollPending(true);
1493
+ setTimeout(
1494
+ () => {
1495
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
1496
+ setLastScrollTime(Date.now());
1497
+ setScrollPending(false);
1498
+ },
1499
+ SCROLL_THROTTLE_TIME - (now - lastScrollTime)
1500
+ );
1501
+ }
1480
1502
  };
1481
1503
 
1482
1504
  const handleConfigurationClick = async () => {
@@ -1740,8 +1762,8 @@ function SidebarComponent(props: any) {
1740
1762
  ) : (
1741
1763
  <div className="sidebar-messages">
1742
1764
  {chatMessages.map((msg, index) => (
1743
- <ChatResponse
1744
- key={`key-${index}`}
1765
+ <MemoizedChatResponse
1766
+ key={msg.id}
1745
1767
  message={msg}
1746
1768
  openFile={props.openFile}
1747
1769
  getApp={props.getApp}