small performance update for history info. separate each item into a full react component to allow for fine grained reactive updates (prevents large tree reconcilations when there are thousands of history items) (#246)

This commit is contained in:
Mike Sawka 2024-01-22 23:18:30 -08:00 committed by GitHub
parent 1b81b2906c
commit 9879fe4d11
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 63 additions and 47 deletions

View File

@ -869,7 +869,7 @@ class Markdown extends React.Component<
return <CodeBlockMarkdown codeSelectSelectedIndex={codeSelectIndex}>{props.children}</CodeBlockMarkdown>; return <CodeBlockMarkdown codeSelectSelectedIndex={codeSelectIndex}>{props.children}</CodeBlockMarkdown>;
} else { } else {
let clickHandler = (e: React.MouseEvent<HTMLElement>) => { let clickHandler = (e: React.MouseEvent<HTMLElement>) => {
let blockText = e.target.innerText; let blockText = (e.target as HTMLElement).innerText;
if (blockText) { if (blockText) {
blockText = blockText.replace(/\n$/, ""); // remove trailing newline blockText = blockText.replace(/\n$/, ""); // remove trailing newline
navigator.clipboard.writeText(blockText); navigator.clipboard.writeText(blockText);

View File

@ -29,43 +29,17 @@ function truncateWithTDots(str: string, maxLen: number): string {
} }
@mobxReact.observer @mobxReact.observer
class HistoryInfo extends React.Component<{}, {}> { class HItem extends React.Component<
lastClickHNum: string = null; {
lastClickTs: number = 0; hitem: HistoryItem;
containingText: mobx.IObservableValue<string> = mobx.observable.box(""); isSelected: boolean;
opts: HistoryQueryOpts;
componentDidMount() { snames: Record<string, string>;
let inputModel = GlobalModel.inputModel; scrNames: Record<string, string>;
let hitem = inputModel.getHistorySelectedItem(); onClick: (hitem: HistoryItem) => void;
if (hitem == null) { },
hitem = inputModel.getFirstHistoryItem(); {}
} > {
if (hitem != null) {
inputModel.scrollHistoryItemIntoView(hitem.historynum);
}
}
@boundMethod
handleItemClick(hitem: HistoryItem) {
let inputModel = GlobalModel.inputModel;
let selItem = inputModel.getHistorySelectedItem();
if (this.lastClickHNum == hitem.historynum && selItem != null && selItem.historynum == hitem.historynum) {
inputModel.grabSelectedHistoryItem();
return;
}
inputModel.giveFocus();
inputModel.setHistorySelectionNum(hitem.historynum);
let now = Date.now();
this.lastClickHNum = hitem.historynum;
this.lastClickTs = now;
setTimeout(() => {
if (this.lastClickTs == now) {
this.lastClickHNum = null;
this.lastClickTs = 0;
}
}, 3000);
}
renderRemote(hitem: HistoryItem): any { renderRemote(hitem: HistoryItem): any {
if (hitem.remote == null || isBlank(hitem.remote.remoteid)) { if (hitem.remote == null || isBlank(hitem.remote.remoteid)) {
return sprintf("%-15s ", ""); return sprintf("%-15s ", "");
@ -142,13 +116,8 @@ class HistoryInfo extends React.Component<{}, {}> {
return "-"; return "-";
} }
renderHItem( render() {
hitem: HistoryItem, let { hitem, isSelected, opts, snames, scrNames } = this.props;
opts: HistoryQueryOpts,
isSelected: boolean,
snames: Record<string, string>,
scrNames: Record<string, string>
): any {
let lines = hitem.cmdstr.split("\n"); let lines = hitem.cmdstr.split("\n");
let line: string = ""; let line: string = "";
let idx = 0; let idx = 0;
@ -163,7 +132,7 @@ class HistoryInfo extends React.Component<{}, {}> {
{ "history-haderror": hitem.haderror }, { "history-haderror": hitem.haderror },
"hnum-" + hitem.historynum "hnum-" + hitem.historynum
)} )}
onClick={() => this.handleItemClick(hitem)} onClick={() => this.props.onClick(hitem)}
> >
<div className="history-line"> <div className="history-line">
{infoText} {lines[0]} {infoText} {lines[0]}
@ -176,12 +145,51 @@ class HistoryInfo extends React.Component<{}, {}> {
</div> </div>
); );
} }
}
@mobxReact.observer
class HistoryInfo extends React.Component<{}, {}> {
lastClickHNum: string = null;
lastClickTs: number = 0;
containingText: mobx.IObservableValue<string> = mobx.observable.box("");
componentDidMount() {
let inputModel = GlobalModel.inputModel;
let hitem = inputModel.getHistorySelectedItem();
if (hitem == null) {
hitem = inputModel.getFirstHistoryItem();
}
if (hitem != null) {
inputModel.scrollHistoryItemIntoView(hitem.historynum);
}
}
@boundMethod @boundMethod
handleClose() { handleClose() {
GlobalModel.inputModel.toggleInfoMsg(); GlobalModel.inputModel.toggleInfoMsg();
} }
@boundMethod
handleItemClick(hitem: HistoryItem) {
let inputModel = GlobalModel.inputModel;
let selItem = inputModel.getHistorySelectedItem();
if (this.lastClickHNum == hitem.historynum && selItem != null && selItem.historynum == hitem.historynum) {
inputModel.grabSelectedHistoryItem();
return;
}
inputModel.giveFocus();
inputModel.setHistorySelectionNum(hitem.historynum);
let now = Date.now();
this.lastClickHNum = hitem.historynum;
this.lastClickTs = now;
setTimeout(() => {
if (this.lastClickTs == now) {
this.lastClickHNum = null;
this.lastClickTs = 0;
}
}, 3000);
}
render() { render() {
let inputModel = GlobalModel.inputModel; let inputModel = GlobalModel.inputModel;
let idx: number = 0; let idx: number = 0;
@ -224,7 +232,15 @@ class HistoryInfo extends React.Component<{}, {}> {
<If condition={hitems.length == 0}>[no history]</If> <If condition={hitems.length == 0}>[no history]</If>
<If condition={hitems.length > 0}> <If condition={hitems.length > 0}>
<For each="hitem" index="idx" of={hitems}> <For each="hitem" index="idx" of={hitems}>
{this.renderHItem(hitem, opts, hitem == selItem, snames, scrNames)} <HItem
key={hitem.historyid}
hitem={hitem}
isSelected={hitem == selItem}
opts={opts}
snames={snames}
scrNames={scrNames}
onClick={this.handleItemClick}
></HItem>
</For> </For>
</If> </If>
</div> </div>