migrate modals to new modals system (#124)

* migrate screen settings modal to new modals system

* use screen member var in the methods

* migrate session settings modal to new modal system

* use Modal component in session settings modal

* migrate line settings modal to new modals system

* use Modal component in line settings modal

* migrate client settings modal to new modals framework

* set alert modal width to 500px

* remove screen settings modal after deletion

* use Dropdown component for connnections dropdown

* use Dropdown component for connections dropdown in new tab flow

* replace InfoMessage with Tooltip

* use Dropdown for fontsize dropdown

* use Dropdown for renderer dropdown

* fix dropdown width issue on new tab container

* fix class names concatenation

* fix dropdown width issue in screen settings modal
This commit is contained in:
Red J Adaya
2023-12-07 22:51:46 -08:00
committed by GitHub
parent 87bf3f7a65
commit 8a938744f7
13 changed files with 531 additions and 368 deletions
-19
View File
@@ -74,9 +74,6 @@ class App extends React.Component<{}, {}> {
}
render() {
let screenSettingsModal = GlobalModel.screenSettingsModal.get();
let sessionSettingsModal = GlobalModel.sessionSettingsModal.get();
let lineSettingsModal = GlobalModel.lineSettingsModal.get();
let clientSettingsModal = GlobalModel.clientSettingsModal.get();
let remotesModel = GlobalModel.remotesModel;
let disconnected = !GlobalModel.ws.open.get() || !GlobalModel.waveSrvRunning.get();
@@ -121,22 +118,6 @@ class App extends React.Component<{}, {}> {
</ErrorBoundary>
</div>
<ModalsProvider />
<If condition={screenSettingsModal != null}>
<ScreenSettingsModal
key={screenSettingsModal.sessionId + ":" + screenSettingsModal.screenId}
sessionId={screenSettingsModal.sessionId}
screenId={screenSettingsModal.screenId}
/>
</If>
<If condition={sessionSettingsModal != null}>
<SessionSettingsModal key={sessionSettingsModal} sessionId={sessionSettingsModal} />
</If>
<If condition={lineSettingsModal != null}>
<LineSettingsModal key={String(lineSettingsModal)} linenum={lineSettingsModal} />
</If>
<If condition={clientSettingsModal}>
<ClientSettingsModal />
</If>
</div>
);
}
+4
View File
@@ -3,3 +3,7 @@ export const CREATE_REMOTE = "createRemote";
export const VIEW_REMOTE = "viewRemote";
export const EDIT_REMOTE = "editRemote";
export const ALERT = "alert";
export const SCREEN_SETTINGS = "screenSettings";
export const SESSION_SETTINGS = "sessionSettings";
export const LINE_SETTINGS = "lineSettings";
export const CLIENT_SETTINGS = "clientSettings";
+15 -6
View File
@@ -610,7 +610,7 @@
position: relative;
background-color: transparent;
height: 44px;
min-width: 412px;
min-width: 150px;
width: 100%;
border: 1px solid var(--element-separator, rgba(241, 246, 243, 0.15));
border-radius: 6px;
@@ -618,6 +618,10 @@
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.4), 0px 0px 0.5px 0px rgba(0, 0, 0, 0.5),
0px 0px 0.5px 0px rgba(255, 255, 255, 0.5) inset, 0px 0.5px 0px 0px rgba(255, 255, 255, 0.2) inset;
&.no-label {
height: 34px;
}
&-label {
position: absolute;
left: 16px;
@@ -841,7 +845,7 @@
justify-content: center;
i {
font-size: 16px;
font-size: 13px;
}
}
@@ -865,11 +869,11 @@
background-color: #444;
border-radius: 5px;
overflow: hidden;
max-width: 300px;
width: 300px;
i {
display: inline;
font-size: 16px;
font-size: 13px;
fill: @base-color;
padding-top: 0.2em;
}
@@ -1114,6 +1118,11 @@
line-height: 20px;
border-bottom: 1px solid rgba(250, 250, 250, 0.1);
.wave-modal-title {
color: #eceeec;
font-size: 15px;
}
button {
i {
font-size: 18px;
@@ -1132,8 +1141,8 @@
width: 100%;
padding: 0 20px 20px;
button:first-child {
margin-right: 8px;
button:last-child {
margin-left: 8px;
}
}
}
+20 -14
View File
@@ -150,6 +150,7 @@ interface TooltipProps {
message: React.ReactNode;
icon?: React.ReactNode; // Optional icon property
children: React.ReactNode;
className?: string;
}
interface TooltipState {
@@ -185,8 +186,8 @@ class Tooltip extends React.Component<TooltipProps, TooltipState> {
if (iconElement) {
const rect = iconElement.getBoundingClientRect();
return {
top: `${rect.bottom + window.scrollY - 29.5}px`,
left: `${rect.left + window.scrollX + rect.width / 2 - 19}px`,
top: `${rect.bottom + window.scrollY - 29}px`,
left: `${rect.left + window.scrollX + rect.width / 2 - 17.5}px`,
};
}
return {};
@@ -199,7 +200,7 @@ class Tooltip extends React.Component<TooltipProps, TooltipState> {
const style = this.calculatePosition();
return ReactDOM.createPortal(
<div className="wave-tooltip" style={style}>
<div className={cn("wave-tooltip", this.props.className)} style={style}>
{this.props.icon && <div className="wave-tooltip-icon">{this.props.icon}</div>}
<div className="wave-tooltip-message">{this.props.message}</div>
</div>,
@@ -864,7 +865,7 @@ interface DropdownDecorationProps {
}
interface DropdownProps {
label: string;
label?: string;
options: { value: string; label: string }[];
value?: string;
className?: string;
@@ -1051,7 +1052,7 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
{options.map((option, index) => (
<div
key={option.value}
className={cn("wave-dropdown-item", {
className={cn("wave-dropdown-item unselectable", {
"wave-dropdown-item-highlighted": index === highlightedIndex,
})}
onClick={(e) => this.handleSelect(option.value, e)}
@@ -1068,8 +1069,9 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
return (
<div
className={cn(`wave-dropdown ${className || ""}`, {
className={cn("wave-dropdown", className, {
"wave-dropdown-error": isError,
"no-label": !label,
})}
ref={this.wrapperRef}
tabIndex={0}
@@ -1078,15 +1080,19 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
onFocus={this.handleFocus}
>
{decoration?.startDecoration && <>{decoration.startDecoration}</>}
<If condition={label}>
<div
className={cn("wave-dropdown-label unselectable", {
float: shouldLabelFloat,
"offset-left": decoration?.startDecoration,
})}
>
{label}
</div>
</If>
<div
className={cn("wave-dropdown-label", {
float: shouldLabelFloat,
"offset-left": decoration?.startDecoration,
})}
className={cn("wave-dropdown-display unselectable", { "offset-left": decoration?.startDecoration })}
>
{label}
</div>
<div className={cn("wave-dropdown-display", { "offset-left": decoration?.startDecoration })}>
{selectedOptionLabel}
</div>
<div className={cn("wave-dropdown-arrow", { "wave-dropdown-arrow-rotate": isOpen })}>
@@ -1106,7 +1112,7 @@ interface ModalHeaderProps {
const ModalHeader: React.FC<ModalHeaderProps> = ({ onClose, title }) => (
<div className="wave-modal-header">
{<div>{title}</div>}
{<div className="wave-modal-title">{title}</div>}
<IconButton theme="secondary" variant="ghost" onClick={onClose}>
<i className="fa-sharp fa-solid fa-xmark"></i>
</IconButton>
+99 -1
View File
@@ -396,13 +396,109 @@
gap: 12px;
align-self: stretch;
width: 100%;
> div {
width: 100%;
}
}
}
}
.screen-settings-modal {
width: 640px;
min-height: 329px;
.wave-modal-content {
gap: 24px;
.wave-modal-body {
display: flex;
padding: 0px 20px;
flex-direction: column;
align-items: flex-start;
gap: 4px;
align-self: stretch;
width: 100%;
.screen-settings-dropdown {
width: 412px;
.lefticon {
position: absolute;
top: 50%;
left: 16px;
transform: translateY(-50%);
.globe-icon {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.status-icon {
position: absolute;
left: 7px;
top: 8px;
}
}
}
.archived-label,
.actions-label {
div:first-child {
margin-right: 5px;
}
div:last-child i {
font-size: 13px;
}
}
}
}
}
.screen-settings-tooltip .wave-tooltip-icon {
i {
font-size: 13px;
}
}
.session-settings-modal {
width: 640px;
.wave-modal-content {
gap: 24px;
.wave-modal-body {
display: flex;
padding: 0px 20px;
flex-direction: column;
align-items: flex-start;
gap: 4px;
align-self: stretch;
width: 100%;
}
}
}
.line-settings-modal {
width: 640px;
.wave-modal-content {
gap: 24px;
.wave-modal-body {
display: flex;
padding: 0px 20px;
flex-direction: column;
align-items: flex-start;
gap: 4px;
align-self: stretch;
width: 100%;
}
}
}
.client-settings-modal {
width: 640px;
.wave-modal-content {
gap: 24px;
@@ -470,6 +566,8 @@
}
.alert-modal {
width: 500px;
.wave-modal-content {
.wave-modal-body {
padding: 40px 20px;
+5
View File
@@ -9,6 +9,7 @@ import {
EditRemoteConnModal,
AlertModal,
} from "./modals";
import { ScreenSettingsModal, SessionSettingsModal, LineSettingsModal, ClientSettingsModal } from "./settings";
import * as constants from "../../appconst";
const modalsRegistry: { [key: string]: () => React.ReactElement } = {
@@ -17,6 +18,10 @@ const modalsRegistry: { [key: string]: () => React.ReactElement } = {
[constants.VIEW_REMOTE]: () => <ViewRemoteConnDetailModal />,
[constants.EDIT_REMOTE]: () => <EditRemoteConnModal />,
[constants.ALERT]: () => <AlertModal />,
[constants.SCREEN_SETTINGS]: () => <ScreenSettingsModal />,
[constants.SESSION_SETTINGS]: () => <SessionSettingsModal />,
[constants.LINE_SETTINGS]: () => <LineSettingsModal />,
[constants.CLIENT_SETTINGS]: () => <ClientSettingsModal />,
};
export { modalsRegistry };
File diff suppressed because it is too large Load Diff
+2
View File
@@ -39,6 +39,7 @@ import { PluginModel } from "../../plugins/plugins";
import { Prompt } from "../common/prompt/prompt";
import * as lineutil from "./lineutil";
import { ErrorBoundary } from "../../app/common/error/errorboundary";
import * as constants from "../appconst";
import { ReactComponent as CheckIcon } from "../assets/icons/line/check.svg";
import { ReactComponent as CommentIcon } from "../assets/icons/line/comment.svg";
@@ -439,6 +440,7 @@ class LineCmd extends React.Component<
mobx.action(() => {
GlobalModel.lineSettingsModal.set(line.linenum);
})();
GlobalModel.modalsModel.pushModal(constants.LINE_SETTINGS);
}
}
+3 -4
View File
@@ -15,7 +15,6 @@ import { ReactComponent as HelpIcon } from "../assets/icons/help.svg";
import { ReactComponent as SettingsIcon } from "../assets/icons/settings.svg";
import { ReactComponent as DiscordIcon } from "../assets/icons/discord.svg";
import { ReactComponent as HistoryIcon } from "../assets/icons/history.svg";
import { ReactComponent as FavoritesIcon } from "../assets/icons/favourites.svg";
import { ReactComponent as AppsIcon } from "../assets/icons/apps.svg";
import { ReactComponent as ConnectionsIcon } from "../assets/icons/connections.svg";
import { ReactComponent as WorkspacesIcon } from "../assets/icons/workspaces.svg";
@@ -25,6 +24,7 @@ import { ReactComponent as ActionsIcon } from "../assets/icons/tab/actions.svg";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel, GlobalCommandRunner, Session } from "../../model/model";
import { sortAndFilterRemotes, isBlank, openLink } from "../../util/util";
import * as constants from "../appconst";
import "./sidebar.less";
@@ -130,9 +130,7 @@ class MainSideBar extends React.Component<{}, {}> {
@boundMethod
handleSettingsClick(): void {
mobx.action(() => {
GlobalModel.clientSettingsModal.set(true);
})();
GlobalModel.modalsModel.pushModal(constants.CLIENT_SETTINGS);
}
@boundMethod
@@ -142,6 +140,7 @@ class MainSideBar extends React.Component<{}, {}> {
mobx.action(() => {
GlobalModel.sessionSettingsModal.set(session.sessionId);
})();
GlobalModel.modalsModel.pushModal(constants.SESSION_SETTINGS);
}
getSessions() {
+24 -2
View File
@@ -131,6 +131,29 @@
gap: 8px;
align-self: stretch;
.conn-dropdown {
width: 412px;
.lefticon {
position: absolute;
top: 50%;
left: 16px;
transform: translateY(-50%);
.globe-icon {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.status-icon {
position: absolute;
left: 7px;
top: 8px;
}
}
}
&.conn-section {
gap: 8px;
}
@@ -152,7 +175,7 @@
padding: 8px 0 8px 2px;
align-items: flex-start;
gap: 14px;
&.tabicon-list {
gap: 12px;
}
@@ -164,7 +187,6 @@
position: relative;
font-size: 14px;
&.tabicon {
display: flex;
align-items: center;
+46 -7
View File
@@ -19,12 +19,13 @@ import { getRemoteStr } from "../../common/prompt/prompt";
import { GlobalModel, ScreenLines, Screen, Session } from "../../../model/model";
import { Line } from "../../line/linecomps";
import { LinesView } from "../../line/linesview";
import { ConnectionDropdown } from "../../connections_deprecated/connections";
import * as util from "../../../util/util";
import { TextField } from "../../common/common";
import { TextField, Dropdown } from "../../common/common";
import { ReactComponent as EllipseIcon } from "../../assets/icons/ellipse.svg";
import { ReactComponent as Check12Icon } from "../../assets/icons/check12.svg";
import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg";
import { ReactComponent as GlobeIcon } from "../../assets/icons/globe.svg";
import { ReactComponent as StatusCircleIcon } from "../../assets/icons/statuscircle.svg";
import "./screenview.less";
import "./tabs.less";
@@ -53,6 +54,12 @@ class ScreenView extends React.Component<{ session: Session; screen: Screen }, {
class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
connDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "NewTabSettings-connDropdownActive" });
errorMessage: OV<string | null> = mobx.observable.box(null, { name: "NewTabSettings-errorMessage" });
remotes: T.RemoteType[];
constructor(props) {
super(props);
this.remotes = GlobalModel.remotes;
}
@boundMethod
selectTabColor(color: string): void {
@@ -99,6 +106,28 @@ class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
GlobalModel.remotesModel.openAddModal({ remoteedit: true });
}
@boundMethod
getOptions(): { label: string; value: string }[] {
return this.remotes
.filter((r) => !r.archived)
.map((remote) => ({
...remote,
label:
remote.remotealias && !util.isBlank(remote.remotealias)
? `${remote.remotecanonicalname}`
: remote.remotecanonicalname,
value: remote.remotecanonicalname,
}))
.sort((a, b) => {
let connValA = util.getRemoteConnVal(a);
let connValB = util.getRemoteConnVal(b);
if (connValA !== connValB) {
return connValA - connValB;
}
return a.remoteidx - b.remoteidx;
});
}
renderTabIconSelector(): React.ReactNode {
let { screen } = this.props;
let curIcon = screen.getTabIcon();
@@ -163,6 +192,7 @@ class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
let { screen } = this.props;
let rptr = screen.curRemote.get();
let curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
return (
<div className="newtab-container">
<div className="newtab-section name-section">
@@ -179,11 +209,20 @@ class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
You're connected to [{getRemoteStr(rptr)}]. Do you want to change it?
</div>
<div>
<ConnectionDropdown
curRemote={curRemote}
allowNewConn={true}
onSelectRemote={this.selectRemote}
onNewConn={this.clickNewConnection}
<Dropdown
className="conn-dropdown"
label={curRemote.remotealias}
options={this.getOptions()}
defaultValue={curRemote.remotecanonicalname}
onChange={this.selectRemote}
decoration={{
startDecoration: (
<div className="lefticon">
<GlobeIcon className="globe-icon" />
<StatusCircleIcon className={cn("status-icon", "status-" + curRemote.status)} />
</div>
),
}}
/>
</div>
<div className="text-caption cr-help-text">
+3 -1
View File
@@ -11,11 +11,12 @@ import cn from "classnames";
import { debounce } from "throttle-debounce";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { GlobalModel, GlobalCommandRunner, Session, Screen, TabIcons } from "../../../model/model";
import { GlobalModel, GlobalCommandRunner, Session, Screen } from "../../../model/model";
import { renderCmdText } from "../../common/common";
import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg";
import { ReactComponent as ActionsIcon } from "../../assets/icons/tab/actions.svg";
import { ReactComponent as AddIcon } from "../../assets/icons/add.svg";
import * as constants from "../../appconst";
import "../workspace.less";
import "./tabs.less";
@@ -100,6 +101,7 @@ class ScreenTabs extends React.Component<{ session: Session }, {}> {
mobx.action(() => {
GlobalModel.screenSettingsModal.set({ sessionId: screen.sessionId, screenId: screen.screenId });
})();
GlobalModel.modalsModel.pushModal(constants.SCREEN_SETTINGS);
}
renderTabIcon = (screen: Screen): React.ReactNode => {
+2 -1
View File
@@ -390,7 +390,7 @@ function getColorRGB(colorInput) {
return computedColorStyle;
}
function commandRtnHandler(prtn: Promise<CommandRtnType>, errorMessage: OV<string>) {
function commandRtnHandler(prtn: Promise<CommandRtnType>, errorMessage: OV<string>) {
prtn.then((crtn) => {
if (crtn.success) {
return;
@@ -424,4 +424,5 @@ export {
openLink,
getColorRGB,
commandRtnHandler,
getRemoteConnVal,
};