Add main screens to Cmd-P search (#288)

* declare types as global

* remove mobx types aliases

* put back model_old.ts

* remove types.ts

* add main screens to Cmd-P search

* make viewData optional

* minor hint fix

* address improvements suggested by evan

* more on let to const
This commit is contained in:
Red J Adaya 2024-02-13 09:54:12 +08:00 committed by GitHub
parent 85f22a0733
commit 532e65c8ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 80 additions and 36 deletions

View File

@ -5,7 +5,7 @@ import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { For } from "tsx-control-statements/components";
import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import { GlobalModel, GlobalCommandRunner } from "../../../models";
import { Modal, TextField, InputDecoration, Tooltip } from "../elements";
@ -15,6 +15,11 @@ import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg"
import "./tabswitcher.less";
type ViewDataType = {
label: string;
value: string;
};
type SwitcherDataType = {
sessionId: string;
sessionName: string;
@ -24,9 +29,25 @@ type SwitcherDataType = {
screenName: string;
icon: string;
color: string;
viewData?: ViewDataType;
};
const MaxOptionsToDisplay = 100;
const additionalOptions = [
{ label: "Connections", value: "connections" },
{ label: "History", value: "history" },
{ label: "Settings", value: "clientsettings" },
].map((item, index) => ({
sessionId: `additional-${index}`,
sessionName: "",
sessionIdx: -1,
screenId: `additional-${index}`,
screenIdx: -1,
screenName: "",
icon: "",
color: "",
viewData: item,
}));
@mobxReact.observer
class TabSwitcherModal extends React.Component<{}, {}> {
@ -44,8 +65,8 @@ class TabSwitcherModal extends React.Component<{}, {}> {
componentDidMount() {
this.activeSessionIdx = GlobalModel.getActiveSession().sessionIdx.get();
let oSessions = GlobalModel.sessionList;
let oScreens = GlobalModel.screenMap;
const oSessions = GlobalModel.sessionList;
const oScreens = GlobalModel.screenMap;
oScreens.forEach((oScreen) => {
if (oScreen == null) {
return;
@ -54,13 +75,13 @@ class TabSwitcherModal extends React.Component<{}, {}> {
return;
}
// Find the matching session in the observable array
let foundSession = oSessions.find((s) => {
const foundSession = oSessions.find((s) => {
return s.sessionId == oScreen.sessionId && !s.archived.get();
});
if (!foundSession) {
return;
}
let data: SwitcherDataType = {
const data: SwitcherDataType = {
sessionName: foundSession.name.get(),
sessionId: foundSession.sessionId,
sessionIdx: foundSession.sessionIdx.get(),
@ -85,11 +106,11 @@ class TabSwitcherModal extends React.Component<{}, {}> {
}
componentDidUpdate() {
let currFocusedIdx = this.focusedIdx.get();
const currFocusedIdx = this.focusedIdx.get();
// Check if selectedIdx has changed
if (currFocusedIdx !== this.prevFocusedIdx) {
let optionElement = this.optionRefs[currFocusedIdx]?.current;
const optionElement = this.optionRefs[currFocusedIdx]?.current;
if (optionElement) {
optionElement.scrollIntoView({ block: "nearest" });
@ -106,7 +127,7 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@boundMethod
getTabIcon(screen: Screen): string {
let tabIcon = "default";
let screenOpts = screen.opts.get();
const screenOpts = screen.opts.get();
if (screenOpts != null && !util.isBlank(screenOpts.tabicon)) {
tabIcon = screenOpts.tabicon;
}
@ -116,7 +137,7 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@boundMethod
getTabColor(screen: Screen): string {
let tabColor = "default";
let screenOpts = screen.opts.get();
const screenOpts = screen.opts.get();
if (screenOpts != null && !util.isBlank(screenOpts.tabcolor)) {
tabColor = screenOpts.tabcolor;
}
@ -129,7 +150,7 @@ class TabSwitcherModal extends React.Component<{}, {}> {
this.closeModal();
} else if (e.key === "ArrowUp" || e.key === "ArrowDown") {
e.preventDefault();
let newIndex = this.calculateNewIndex(e.key === "ArrowUp");
const newIndex = this.calculateNewIndex(e.key === "ArrowUp");
this.setFocusedIndex(newIndex);
} else if (e.key === "Enter") {
e.preventDefault();
@ -139,7 +160,7 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@boundMethod
calculateNewIndex(isUpKey) {
let currentIndex = this.focusedIdx.get();
const currentIndex = this.focusedIdx.get();
if (isUpKey) {
return Math.max(currentIndex - 1, 0);
} else {
@ -162,6 +183,11 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@boundMethod
handleSelect(index: number): void {
const selectedOption = this.sOptions[index];
if (selectedOption.sessionIdx === -1) {
GlobalCommandRunner.switchView(selectedOption.viewData.value);
this.closeModal();
return;
}
if (selectedOption) {
GlobalCommandRunner.switchScreen(selectedOption.screenId, selectedOption.sessionId);
this.closeModal();
@ -189,27 +215,28 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@mobx.computed
@boundMethod
filterOptions(searchInput: string): SwitcherDataType[] {
let filteredScreens = [];
for (let i = 0; i < this.options.length; i++) {
let tab = this.options[i];
let match = false;
const searchLower = searchInput.toLowerCase();
let filteredScreens = this.options.filter((tab) => {
if (searchInput.includes("/")) {
let [sessionFilter, screenFilter] = searchInput.split("/").map((s) => s.trim().toLowerCase());
match =
const [sessionFilter, screenFilter] = searchInput.split("/").map((s) => s.trim().toLowerCase());
return (
tab.sessionName.toLowerCase().includes(sessionFilter) &&
tab.screenName.toLowerCase().includes(screenFilter);
tab.screenName.toLowerCase().includes(screenFilter)
);
} else {
match =
tab.sessionName.toLowerCase().includes(searchInput) ||
tab.screenName.toLowerCase().includes(searchInput);
return (
tab.sessionName.toLowerCase().includes(searchLower) ||
tab.screenName.toLowerCase().includes(searchLower)
);
}
});
// Add tab to filtered list if it matches the criteria
if (match) {
filteredScreens.push(tab);
}
if (searchLower.length > 0) {
const additionalFiltered = additionalOptions.filter((item) =>
item.viewData?.label.toLowerCase().includes(searchLower)
);
filteredScreens = filteredScreens.concat(additionalFiltered);
}
return filteredScreens;
@ -218,9 +245,10 @@ class TabSwitcherModal extends React.Component<{}, {}> {
@mobx.computed
@boundMethod
sortOptions(options: SwitcherDataType[]): SwitcherDataType[] {
return options.sort((a, b) => {
let aInCurrentSession = a.sessionIdx === this.activeSessionIdx;
let bInCurrentSession = b.sessionIdx === this.activeSessionIdx;
const mainOptions = options.filter((o) => o.sessionIdx !== -1);
mainOptions.sort((a, b) => {
const aInCurrentSession = a.sessionIdx === this.activeSessionIdx;
const bInCurrentSession = b.sessionIdx === this.activeSessionIdx;
// Tabs in the current session are sorted by screenIdx
if (aInCurrentSession && bInCurrentSession) {
@ -243,11 +271,16 @@ class TabSwitcherModal extends React.Component<{}, {}> {
}
}
});
const additionalOptions = options.filter((o) => o.sessionIdx === -1);
additionalOptions.sort((a, b) => a.viewData?.label.localeCompare(b.viewData?.label));
return mainOptions.concat(additionalOptions);
}
@boundMethod
renderIcon(option: SwitcherDataType): React.ReactNode {
let tabIcon = option.icon;
const tabIcon = option.icon;
if (tabIcon === "default" || tabIcon === "square") {
return <SquareIcon className="left-icon" />;
}
@ -268,10 +301,15 @@ class TabSwitcherModal extends React.Component<{}, {}> {
})}
onClick={() => this.handleSelect(index)}
>
<If condition={option.sessionIdx != -1}>
<div className={cn("icon", "color-" + option.color)}>{this.renderIcon(option)}</div>
<div className="tabname">
#{option.sessionName} / {option.screenName}
</div>
</If>
<If condition={option.sessionIdx == -1}>
<div className="tabname">{option.viewData?.label}</div>
</If>
</div>
);
}
@ -290,13 +328,13 @@ class TabSwitcherModal extends React.Component<{}, {}> {
decoration={{
startDecoration: (
<InputDecoration position="start">
<div className="tabswitcher-search-prefix">Switch to Tab:</div>
<div className="tabswitcher-search-prefix">Go to:</div>
</InputDecoration>
),
endDecoration: (
<InputDecoration>
<Tooltip
message={`Type to filter workspaces and tabs.`}
message={`Type to filter workspaces, tabs and views.`}
icon={<i className="fa-sharp fa-regular fa-circle-question" />}
>
<i className="fa-sharp fa-regular fa-circle-question" />

View File

@ -34,6 +34,12 @@ class CommandRunner {
return prtn;
}
switchView(view: string) {
mobx.action(() => {
GlobalModel.activeMainView.set(view);
})();
}
switchSession(session: string) {
mobx.action(() => {
GlobalModel.activeMainView.set("session");